Làm cách nào để kiểm tra xem một dịch vụ có chạy trên Android không?


936

Làm cách nào để kiểm tra xem dịch vụ nền có đang chạy không?

Tôi muốn một hoạt động Android thay đổi trạng thái của dịch vụ - nó cho phép tôi bật nó nếu nó tắt và tắt nếu nó được bật.



17
câu trả lời đúng nằm bên dưới và không phải là câu trả lời: stackoverflow.com/a/5921190/2369122
toidiu 11/03/2015

1
@toidiu Nếu điều đó chưa được nerfed như thế getRunningTasks(), có lẽ nó sẽ như vậy.
Kevin Krumwiede

sử dụng hàm getSystemService () bạn có thể truy xuất tất cả các dịch vụ đang chạy. lặp qua nó và kiểm tra dịch vụ của bạn tồn tại trong danh sách ở đây, bạn có thể thấy một wiki
check

Câu trả lời:


292

Tôi đã có cùng một vấn đề cách đây không lâu. Vì dịch vụ của tôi là cục bộ, nên cuối cùng tôi chỉ sử dụng một trường tĩnh trong lớp dịch vụ để chuyển trạng thái, như được mô tả bởi hackbod ở đây

EDIT (cho hồ sơ):

Đây là giải pháp được đề xuất bởi hackbod:

Nếu mã máy khách và máy chủ của bạn là một phần của cùng một .apk và bạn đang ràng buộc với dịch vụ với một Intent cụ thể (một mã xác định lớp dịch vụ chính xác), thì bạn có thể chỉ cần đặt dịch vụ của mình đặt một biến toàn cục khi nó đang chạy khách hàng của bạn có thể kiểm tra.

Chúng tôi cố tình không có API để kiểm tra xem dịch vụ có đang chạy hay không, vì gần như không gặp sự cố, khi bạn muốn làm điều gì đó giống như bạn kết thúc với điều kiện cuộc đua trong mã của mình.


27
@Pacerier, giải pháp bạn tham khảo yêu cầu bắt đầu dịch vụ và tôi nghĩ giải pháp linh hoạt tốt nhất sẽ cho phép bạn kiểm tra xem một dịch vụ có chạy hay không mà không khởi động nó.
Tom

17
Còn nếu dịch vụ bị dừng bởi hệ thống, làm thế nào để bạn phát hiện ra điều đó và chuyển đổi biến của bạn?
jmng

23
Khi ứng dụng bị tắt, dịch vụ mà nó đã khởi động cũng bị giết nhưng dịch vụ onDestroy()không được gọi. Vì vậy, biến tĩnh không thể được cập nhật trong một kịch bản như vậy dẫn đến hành vi không nhất quán.
faizal

5
@faizal Không phải biến tĩnh cũng sẽ được xác định lại, do đó đặt nó trở về giá trị mặc định cho biết dịch vụ không còn chạy nữa?
PabloC

12
@faizal, Dịch vụ địa phương không phải là một quy trình riêng biệt, vì vậy nếu dịch vụ bị hủy thì ứng dụng cũng sẽ bị hủy.
Sever

1674

Tôi sử dụng những điều sau đây từ bên trong một hoạt động:

private boolean isMyServiceRunning(Class<?> serviceClass) {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (serviceClass.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}

Và tôi gọi nó bằng cách sử dụng:

isMyServiceRunning(MyService.class)

Điều này hoạt động đáng tin cậy, bởi vì nó dựa trên thông tin về các dịch vụ đang chạy được cung cấp bởi hệ điều hành Android thông qua ActivityManager # getRastyService .

Tất cả các cách tiếp cận sử dụng các sự kiện onDestroy hoặc onSometing hoặc Binder hoặc biến tĩnh sẽ không hoạt động đáng tin cậy vì là nhà phát triển mà bạn không bao giờ biết, khi Android quyết định giết tiến trình của bạn hoặc gọi lại trong số các cuộc gọi lại được đề cập hay không. Vui lòng lưu ý cột "có thể tiêu diệt" trong bảng sự kiện vòng đời trong tài liệu Android.


85
Cảm ơn giải pháp này. Tôi muốn thêm: Thay vào đó "com.example.MyService" thanh lịch hơn để sử dụng MyService
Class.getName

10
Cá nhân, tôi đã sử dụng một trường tĩnh. Mặc dù sử dụng getRastyService () là một giải pháp mạnh mẽ hơn, tôi tin rằng trong hai giải pháp này có sự đánh đổi giữa sự mạnh mẽ và hiệu quả / đơn giản. Nếu bạn cần kiểm tra thường xuyên xem một dịch vụ có đang chạy hay không, việc lặp qua 30+ dịch vụ đang chạy có thể không lý tưởng lắm. Trường hợp hiếm hoi của một dịch vụ bị phá hủy bởi hệ thống có thể được xử lý có thể bằng một khối thử / bắt hoặc bằng cách sử dụng START_STICKY.
cướp

80
Không, đó không phải là câu trả lời đúng bởi vì nó cũng được viết trong các tài liệu: "Lưu ý: phương pháp này chỉ dành cho gỡ lỗi hoặc thực hiện giao diện người dùng loại quản lý dịch vụ." Nó không có nghĩa là cho dòng điều khiển!
seb

40
Mọi người thấy thật thanh lịch khi phải trải qua tất cả những điều đó để kiểm tra xem máy chủ có đang chạy không?
Rui Marques

80
Bắt đầu Android O , getRunningServiceskhông được dùng nữa. Câu trả lời này cần một bản cập nhật cho phiên bản mới hơn.
pored91

75

Hiểu rồi!

Bạn PHẢI gọi startService()cho dịch vụ của bạn được đăng ký đúng cách và thông qua BIND_AUTO_CREATEsẽ không đủ.

Intent bindIntent = new Intent(this,ServiceTask.class);
startService(bindIntent);
bindService(bindIntent,mConnection,0);

Và bây giờ là lớp ServiceTools:

public class ServiceTools {
    private static String LOG_TAG = ServiceTools.class.getName();

    public static boolean isServiceRunning(String serviceClassName){
        final ActivityManager activityManager = (ActivityManager)Application.getContext().getSystemService(Context.ACTIVITY_SERVICE);
        final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

        for (RunningServiceInfo runningServiceInfo : services) {
            if (runningServiceInfo.service.getClassName().equals(serviceClassName)){
                return true;
            }
        }
        return false;
     }
}

Điều này sẽ liệt kê chỉ các dịch vụ hệ thống, không?! Vì vậy, dịch vụ địa phương của tôi bị loại khỏi danh sách và tôi sẽ nhận được sai; (
Ewoks

Điều này hoạt động với các dịch vụ bên ngoài, đối với các dịch vụ địa phương là khá rõ ràng nếu bạn đang chạy.
Kevin Parker

11
Xin lỗi nhưng tôi cần phải nói đó là câu trả lời siêu ngớ ngẩn..Tại sao nó lại quá rõ ràng?!
Ewoks

10
Không rõ ý bạn là gì ở đây ... Ai đang nói về sự cố? Tôi không thú vị trong việc phá vỡ nó. Dịch vụ có thể được bắt đầu, dừng lại, có thể đó là dịch vụ có ý định và nó sẽ tự dừng khi hoàn thành ... Câu hỏi là làm thế nào để biết liệu nó có còn chạy hay không sau 3 phút chẳng hạn.
Ewoks

1
Không chính xác để tạo ấn tượng rằng một dịch vụ ràng buộc cũng phải được bắt đầu. KHÔNG. Bind auto tạo thực hiện chính xác những gì nó nói. Nó sẽ tạo (và do đó "bắt đầu") dịch vụ nếu dịch vụ chưa chạy.
Sreedevi J

57

Một bổ sung nhỏ là:

Mục tiêu của tôi là biết được một dịch vụ đang chạy mà không thực sự chạy nó nếu nó không chạy.

Gọi bindService hoặc gọi một ý định có thể bị dịch vụ bắt gặp không phải là một ý tưởng hay vì nó sẽ khởi động dịch vụ nếu nó không chạy.

Vì vậy, như miracle2k đã đề xuất, tốt nhất là có một trường tĩnh trong lớp dịch vụ để biết liệu dịch vụ đã được bắt đầu hay chưa.

Để làm cho nó thậm chí còn sạch hơn, tôi đề nghị chuyển đổi dịch vụ trong một singleton với việc tìm nạp rất rất lười biếng: đó là, không có sự khởi tạo nào ở tất cả các singleton cá thể thông qua các phương thức tĩnh. Phương thức getInstance tĩnh của dịch vụ / singleton của bạn chỉ trả về thể hiện của singleton nếu nó đã được tạo. Nhưng nó không thực sự bắt đầu hoặc kích thích bản thân singleton. Dịch vụ chỉ được bắt đầu thông qua các phương thức bắt đầu dịch vụ bình thường.

Sau đó, sẽ còn sạch hơn khi sửa đổi mẫu thiết kế singleton để đổi tên phương thức getInstance khó hiểu thành một cái gì đó giống như isInstanceCreated() : boolean phương thức.

Mã sẽ trông như sau:

public class MyService extends Service
{
   private static MyService instance = null;

   public static boolean isInstanceCreated() {
      return instance != null;
   }//met

   @Override
   public void onCreate()
   {
      instance = this;
      ....
   }//met

   @Override
   public void onDestroy()
   {
      instance = null;
      ...
   }//met
}//class

Giải pháp này rất thanh lịch, nhưng nó chỉ phù hợp nếu bạn có quyền truy cập vào lớp dịch vụ và chỉ dành cho các lớp nằm bên cạnh ứng dụng / gói dịch vụ. Nếu các lớp của bạn nằm ngoài ứng dụng / gói dịch vụ thì bạn có thể truy vấn ActivityManager với các giới hạn được gạch chân bởi Pieter-Jan Van Robays.


32
Điều này là thiếu sót. onDestroy không được bảo đảm để được gọi.
Pacerier

8
Khi hệ thống thiếu bộ nhớ, dịch vụ của bạn sẽ tự động bị hủy mà không có cuộc gọi đến onDestroy của bạn, đó là lý do tại sao tôi nói rằng điều này là thiếu sót.
Pacerier

17
@Pacerier, nhưng nếu hệ thống giết tiến trình, thì cờ cá thể vẫn sẽ được đặt lại. Tôi đoán rằng khi người nhận tiếp theo được tải (đăng hệ thống giết dịch vụ), 'thể hiện' của cờ tĩnh sẽ được tạo lại thành null.
Tom

2
Ít nhất là tốt hơn so với việc lặp qua tất cả các dịch vụ trong isMyServiceRasty, điều này thực sự làm trì hoãn mọi thứ nếu được thực hiện trên mỗi vòng quay của thiết bị :)
Gunnar Forsgren - Mobimation

1
Biến đối tượng của bạn không được khai báo là cuối cùng, nếu không, nó không thể được đặt hoặc null'ed bởi các phương thức onCreate () hoặc onDestroy ().
k2col

27

Bạn có thể sử dụng cái này (Tôi chưa thử cái này, nhưng tôi hy vọng cái này hoạt động):

if(startService(someIntent) != null) {
    Toast.makeText(getBaseContext(), "Service is already running", Toast.LENGTH_SHORT).show();
}
else {
    Toast.makeText(getBaseContext(), "There is no service running, starting service..", Toast.LENGTH_SHORT).show();
}

Phương thức startService trả về một đối tượng ElementName nếu có một dịch vụ đang chạy. Nếu không, null sẽ được trả lại.

Xem phần mềm trừu tượng công khai startService (dịch vụ ý định) .

Điều này không giống như kiểm tra tôi nghĩ, vì nó bắt đầu dịch vụ, vì vậy bạn có thể thêm stopService(someIntent);theo mã.


11
Không chính xác những gì các tài liệu nói. Theo liên kết của bạn: "Trả về Nếu dịch vụ đang được khởi động hoặc đang chạy, thì Tên thành phần của dịch vụ thực tế đã bắt đầu được trả về; nếu không thì dịch vụ không tồn tại null được trả về."
Gabriel

Suy nghĩ tốt ... nhưng không phù hợp với tình hình hiện tại.
Code_Life

5
Cách này không đúng, vì khi kích hoạt IDE if(startService(someIntent) != null)sẽ kiểm tra IsserviceRunningnhưng điều đó cũng sẽ phát dịch vụ mới.
Chintan Khetiya

Như đã nêu, nếu bạn dừng dịch vụ sau điều khiển này, nó sẽ có ích cho vấn đề này. Nhưng tại sao để bắt đầu và dừng một dịch vụ không có gì?
Taner

6
Điều này sẽ bắt đầu dịch vụ, phải không? Chỉ muốn kiểm tra trạng thái dịch vụ thay vì bắt đầu ...
Raptor

26
/**
 * Check if the service is Running 
 * @param serviceClass the class of the Service
 *
 * @return true if the service is running otherwise false
 */
public boolean checkServiceRunning(Class<?> serviceClass){
    ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE))
    {
        if (serviceClass.getName().equals(service.service.getClassName()))
        {
            return true;
        }
    }
    return false;
}

21

Một trích xuất từ ​​các tài liệu Android :

Giống như sendBroadcast (Intent) , nhưng nếu có bất kỳ máy thu nào cho Intent, chức năng này sẽ chặn và gửi ngay lập tức chúng trước khi quay trở lại.

Hãy nghĩ về vụ hack này là "ping"Service . Vì chúng tôi có thể phát đồng bộ, chúng tôi có thể phát và nhận kết quả một cách đồng bộ , trên luồng UI.

Service

@Override
public void onCreate() {
   LocalBroadcastManager
     .getInstance(this)
     .registerReceiver(new ServiceEchoReceiver(), new IntentFilter("ping"));
     //do not forget to deregister the receiver when the service is destroyed to avoid
     //any potential memory leaks 
}

private class ServiceEchoReceiver extends BroadcastReceiver {
    public void onReceive (Context context, Intent intent) {
      LocalBroadcastManager
         .getInstance(this)
         .sendBroadcastSync(new Intent("pong"));
    }
}

Activity

    bool serviceRunning = false;

    protected void onCreate (Bundle savedInstanceState){
        LocalBroadcastManager.getInstance(this).registerReceiver(pong, new IntentFilter("pong"));
        LocalBroadcastManager.getInstance(this).sendBroadcastSync(new Intent("ping"));
        if(!serviceRunning){
           //run the service
        }
    }

    private BroadcastReceiver pong = new BroadcastReceiver(){
        public void onReceive (Context context, Intent intent) {
          serviceRunning = true;   
        }
    }

Người chiến thắng trong nhiều ứng dụng, tất nhiên, một lĩnh vực boolean tĩnh trên dịch vụ được thiết lập để trueService.onCreate()và để falseService.onDestroy()vì nó đơn giản hơn rất nhiều.


Đây là một giải pháp tốt hơn nhiều so với giải pháp được chấp nhận, thất bại nếu Android giết dịch vụ vì phương thức biến toàn cục vẫn sẽ chỉ ra rằng dịch vụ đang chạy khi thực sự không còn nữa. Thủ thuật phát bóng bàn đồng bộ này thực sự là phương pháp đáng tin cậy DUY NHẤT để kiểm tra xem một dịch vụ còn sống hay không. Nó một mình cho phép bạn chỉ cần HỎI dịch vụ nếu nó ở đó. Nếu nó trả lời thì dịch vụ vẫn còn hoạt động, nếu không thì nó chưa được khởi động hoặc đã bị tắt, theo chương trình hoặc bởi hệ thống để phục hồi bộ nhớ.
PhoenixReveal

13

Tôi đã sửa đổi một chút một trong các giải pháp được trình bày ở trên, nhưng chuyển lớp thay vì tên chuỗi chung, để đảm bảo so sánh các chuỗi đi ra từ cùng một phương thức class.getName()

public class ServiceTools {
    private static String LOG_TAG = ServiceTools.class.getName();

    public static boolean isServiceRunning(Context context,Class<?> serviceClass){
        final ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
        final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

        for (RunningServiceInfo runningServiceInfo : services) {
            Log.d(Constants.TAG, String.format("Service:%s", runningServiceInfo.service.getClassName()));
            if (runningServiceInfo.service.getClassName().equals(serviceClass.getName())){
                return true;
            }
        }
        return false;
    }
}

và sau đó

Boolean isServiceRunning = ServiceTools.isServiceRunning(
                    MainActivity.this.getApplicationContext(),
                    BackgroundIntentService.class);

để nghiêm túc hơn về mặt nghiêm ngặt, bạn có thể thay đổi lớp param thànhClass<? extends Service>
silentsudo

11

Cách thích hợp để kiểm tra xem một dịch vụ có đang chạy hay không chỉ đơn giản là hỏi nó. Triển khai BroadcastReceiver trong dịch vụ của bạn để phản hồi các lệnh ping từ các hoạt động của bạn. Đăng ký BroadcastReceiver khi dịch vụ bắt đầu và hủy đăng ký khi dịch vụ bị hủy. Từ hoạt động của bạn (hoặc bất kỳ thành phần nào), hãy gửi ý định phát sóng cục bộ đến dịch vụ và nếu nó phản hồi, bạn sẽ biết nó đang chạy. Lưu ý sự khác biệt tinh tế giữa ACTION_PING và ACTION_PONG trong mã bên dưới.

public class PingableService extends Service
{
    public static final String ACTION_PING = PingableService.class.getName() + ".PING";
    public static final String ACTION_PONG = PingableService.class.getName() + ".PONG";

    public int onStartCommand (Intent intent, int flags, int startId)
    {
        LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter(ACTION_PING));
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy ()
    {
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
        super.onDestroy();
    }

    private BroadcastReceiver mReceiver = new BroadcastReceiver()
    {
        @Override
        public void onReceive (Context context, Intent intent)
        {
            if (intent.getAction().equals(ACTION_PING))
            {
                LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getApplicationContext());
                manager.sendBroadcast(new Intent(ACTION_PONG));
            }
        }
    };
}


public class MyActivity extends Activity
{
    private boolean isSvcRunning = false;

    @Override
    protected void onStart()
    {
        LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getApplicationContext());
        manager.registerReceiver(mReceiver, new IntentFilter(PingableService.ACTION_PONG));
        // the service will respond to this broadcast only if it's running
        manager.sendBroadcast(new Intent(PingableService.ACTION_PING));
        super.onStart();
    }

    @Override
    protected void onStop()
    {
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
        super.onStop();
    }

    protected BroadcastReceiver mReceiver = new BroadcastReceiver()
    {
        @Override
        public void onReceive (Context context, Intent intent)
        {
            // here you receive the response from the service
            if (intent.getAction().equals(PingableService.ACTION_PONG))
            {
                isSvcRunning = true;
            }
        }
    };
}

1
Tôi thực sự thích cách tiếp cận này. Đó là một chút mã nặng khôn ngoan nhưng sẽ luôn hoạt động. Tôi không thấy ý định phát sóng bị từ chối bất cứ lúc nào sớm :)
chối ShellDude

8

Tôi chỉ muốn thêm một ghi chú vào câu trả lời của @Snicolas. Các bước sau đây có thể được sử dụng để kiểm tra dịch vụ dừng có / không gọi onDestroy().

  1. onDestroy() được gọi: Chuyển đến Cài đặt -> Ứng dụng -> Dịch vụ đang chạy -> Chọn và dừng dịch vụ của bạn.

  2. onDestroy()không được gọi: Truy cập Cài đặt -> Ứng dụng -> Quản lý ứng dụng -> Chọn và "Buộc dừng" ứng dụng của bạn trong đó dịch vụ của bạn đang chạy. Tuy nhiên, vì ứng dụng của bạn bị dừng ở đây, nên chắc chắn các trường hợp dịch vụ cũng sẽ bị dừng.

Cuối cùng, tôi muốn đề cập rằng cách tiếp cận được đề cập ở đó bằng cách sử dụng một biến tĩnh trong lớp singleton đang làm việc cho tôi.


7

onDestroy không phải lúc nào cũng được gọi trong dịch vụ nên điều này là vô ích!

Ví dụ: Chỉ cần chạy lại ứng dụng với một thay đổi từ Eclipse. Ứng dụng được thoát ra một cách mạnh mẽ bằng SIG: 9.


6

Trước hết, bạn không cố gắng tiếp cận dịch vụ bằng cách sử dụng Trình quản lý hoạt động. (Thảo luận ở đây )

Các dịch vụ có thể tự chạy, bị ràng buộc với một Hoạt động hoặc cả hai. Cách để kiểm tra Hoạt động nếu Dịch vụ của bạn có chạy hay không là bằng cách tạo giao diện (mở rộng Binder) nơi bạn khai báo các phương thức mà cả Hoạt động và Dịch vụ đều hiểu. Bạn có thể làm điều này bằng cách tạo Giao diện của riêng bạn, nơi bạn khai báo ví dụ "isServiceRasty ()". Sau đó, bạn có thể liên kết Hoạt động của mình với Dịch vụ của mình, chạy phương thức isServiceRasty (), Dịch vụ sẽ tự kiểm tra xem nó có chạy hay không và trả về một boolean cho Hoạt động của bạn.

Bạn cũng có thể sử dụng phương pháp này để dừng Dịch vụ của mình hoặc tương tác với nó theo cách khác.

Tôi đã sử dụng hướng dẫn này để tìm hiểu cách thực hiện kịch bản này trong ứng dụng của mình.


3
Cuộc thảo luận đó diễn ra vào '12 / 26/07 '. Đó là tháng bảy năm nay (tức là trong tương lai), hoặc đó là trước khi Android thậm chí còn công khai. Dù bằng cách nào cũng khiến tôi không tin tưởng nó.
Tom

Cuộc thảo luận đó là từ ngày 26 tháng 12 năm 2007. Họ đang thảo luận về phiên bản tiền phát hành mà tôi nghĩ ( developer.android.com/sdk/OLD_RELEASENOTES.html#m3-rc37a ) được phát hành vào ngày 14 tháng 12 năm 2007
ingh.am

6

Một lần nữa, một giải pháp thay thế khác mà mọi người có thể tìm thấy sạch hơn nếu họ sử dụng các ý định đang chờ xử lý (ví dụ AlarmManager:

public static boolean isRunning(Class<? extends Service> serviceClass) {
    final Intent intent = new Intent(context, serviceClass);
    return (PendingIntent.getService(context, CODE, intent, PendingIntent.FLAG_NO_CREATE) != null);
}

Đâu CODElà một hằng số mà bạn xác định riêng trong lớp để xác định các ý định đang chờ xử lý liên quan đến dịch vụ của bạn.


1
Kết hợp hoặc cập nhật câu trả lời trước đó của bạn. Xin vui lòng không đăng nhiều hơn một câu trả lời cho mỗi bài.
ChuongPham

Câu trả lời này có thể được mở rộng không, tức là làm thế nào để liên kết giá trị của CODE với dịch vụ?
Dave Nottage

Lấy bối cảnh ở đâu?
húng quế

6

Dưới đây là một hack thanh lịch bao gồm tất cả Ifs. Điều này chỉ dành cho các dịch vụ địa phương.

    public final class AService extends Service {

        private static AService mInstance = null;

        public static boolean isServiceCreated() {
            try {
                // If instance was not cleared but the service was destroyed an Exception will be thrown
                return mInstance != null && mInstance.ping();
            } catch (NullPointerException e) {
                // destroyed/not-started
                return false;
            }
        }

        /**
         * Simply returns true. If the service is still active, this method will be accessible.
         * @return
         */
        private boolean ping() {
            return true;
        }

        @Override
        public void onCreate() {
            mInstance = this;
        }

        @Override
        public void onDestroy() {
            mInstance = null;
        }
    }

Và sau đó:

    if(AService.isServiceCreated()){
        ...
    }else{
        startService(...);
    }

Vấn đề duy nhất với điều này là nếu dịch vụ là một dịch vụ dính và nó tự khởi động lại. Gọi tới isServiceCreated () sẽ trả về false sau khi dịch vụ bắt đầu lại vì mInstance sẽ là null.
Mira_Cole

1
Sẽ không onCreate được gọi sau đó khi dịch vụ tự khởi động lại?
TheRealChx101

6

Phiên bản Xamarin C #:

private bool isMyServiceRunning(System.Type cls)
{
    ActivityManager manager = (ActivityManager)GetSystemService(Context.ActivityService);

    foreach (var service in manager.GetRunningServices(int.MaxValue)) {
        if (service.Service.ClassName.Equals(Java.Lang.Class.FromType(cls).CanonicalName)) {
            return true;
        }
    }
    return false;
}

Bạn cần ỏContext` cho GetSystemService.
thử nghiệm

5

Đối với trường hợp sử dụng được đưa ra ở đây, chúng ta có thể chỉ cần sử dụng stopService()giá trị trả về của phương thức. Nó trả về truenếu có tồn tại dịch vụ được chỉ định và nó bị giết. Khác nó trở lại false. Vì vậy, bạn có thể khởi động lại dịch vụ nếu kết quả falsekhác, đảm bảo rằng dịch vụ hiện tại đã bị dừng. :) Sẽ tốt hơn nếu bạn có cái nhìn này .


5

Một cách tiếp cận khác sử dụng kotlin. Lấy cảm hứng từ câu trả lời của người dùng khác

fun isMyServiceRunning(serviceClass: Class<*>): Boolean {
    val manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    return manager.getRunningServices(Integer.MAX_VALUE)
            .any { it.service.className == serviceClass.name }
}

Như phần mở rộng kotlin

fun Context.isMyServiceRunning(serviceClass: Class<*>): Boolean {
    val manager = this.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    return manager.getRunningServices(Integer.MAX_VALUE)
            .any { it.service.className == serviceClass.name }
}

Sử dụng

context.isMyServiceRunning(MyService::class.java)

4

Trong kotlin, bạn có thể thêm biến boolean trong đối tượng đồng hành và kiểm tra giá trị của nó từ bất kỳ lớp nào bạn muốn:

companion object{
     var isRuning = false

}

Thay đổi giá trị khi dịch vụ được tạo và hủy

 override fun onCreate() {
        super.onCreate()
        isRuning = true
    }

override fun onDestroy() {
    super.onDestroy()
    isRuning = false
    }

3

Trong Lớp con dịch vụ của bạn Sử dụng Boolean tĩnh để có trạng thái Dịch vụ như được minh họa bên dưới.

Dịch vụ của tôi

class MyService : Service() {
    override fun onCreate() {
        super.onCreate()
        isServiceStarted = true
    }
    override fun onDestroy() {
        super.onDestroy()
        isServiceStarted = false
    }
    companion object {
        var isServiceStarted = false
    }
}

ChínhActivity.kt

class MainActivity : AppCompatActivity(){
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val serviceStarted = FileObserverService.isServiceStarted
        if (!serviceStarted) {
            val startFileObserverService = Intent(this, FileObserverService::class.java)
            ContextCompat.startForegroundService(this, startFileObserverService)
        }
    }
}

3

Đối với kotlin, bạn có thể sử dụng mã dưới đây.

fun isMyServiceRunning(calssObj: Class<SERVICE_CALL_NAME>): Boolean {
    val manager = requireActivity().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
        if (calssObj.getName().equals(service.service.getClassName())) {
            return true
        }
    }
    return false
}

Đây là một câu trả lời tuyệt vời cho các bài kiểm tra viết, vì bạn có thể sử dụng nó mà không thay đổi mã làm việc của bạn.
Robert Liberatore

2

Phản ứng của geekQ nhưng trong lớp Kotlin. Cảm ơn geekQ

fun isMyServiceRunning(serviceClass : Class<*> ) : Boolean{
    var manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
        if (serviceClass.name.equals(service.service.className)) {
            return true
        }
    }
    return false
}

Cuộc gọi

isMyServiceRunning(NewService::class.java)

6
ActivityManager.getRunningServiceskhông được dùng nữa kể từ Android O
Daniel Shatz

1

Có thể có một số dịch vụ có cùng tên lớp.

Tôi vừa mới tạo hai ứng dụng. Tên gói của ứng dụng đầu tiên là com.example.mock. Tôi đã tạo một gói con được gọi loremtrong ứng dụng và một dịch vụ được gọi Mock2Service. Vì vậy, tên đầy đủ của nó là com.example.mock.lorem.Mock2Service.

Sau đó, tôi tạo ra ứng dụng thứ hai và một dịch vụ được gọi là Mock2Service. Tên gói của ứng dụng thứ hai là com.example.mock.lorem. Tên đầy đủ của dịch vụ làcom.example.mock.lorem.Mock2Service , quá.

Đây là đầu ra logcat của tôi.

03-27 12:02:19.985: D/TAG(32155): Mock-01: com.example.mock.lorem.Mock2Service
03-27 12:02:33.755: D/TAG(32277): Mock-02: com.example.mock.lorem.Mock2Service

Một ý tưởng tốt hơn là để so sánh ComponentNametrường hợp vì equals()cácComponentName so sánh cả hai tên gói và tên lớp. Và không thể có hai ứng dụng có cùng tên gói được cài đặt trên thiết bị.

Phương thức equals () của ComponentName.

@Override
public boolean equals(Object obj) {
    try {
        if (obj != null) {
            ComponentName other = (ComponentName)obj;
            // Note: no null checks, because mPackage and mClass can
            // never be null.
            return mPackage.equals(other.mPackage)
                    && mClass.equals(other.mClass);
        }
    } catch (ClassCastException e) {
    }
    return false;
}

Tên thành phần


1

Vui lòng sử dụng mã này.

if (isMyServiceRunning(MainActivity.this, xyzService.class)) { // Service class name
    // Service running
} else {
    // Service Stop
}


public static boolean isMyServiceRunning(Activity activity, Class<?> serviceClass) {
        ActivityManager manager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (serviceClass.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }

0

Điều này áp dụng nhiều hơn đối với gỡ lỗi Dịch vụ Ý định vì chúng sinh ra một luồng, nhưng cũng có thể hoạt động cho các dịch vụ thông thường. Tôi tìm thấy chủ đề này nhờ Belling

Trong trường hợp của tôi, tôi đã chơi xung quanh với trình gỡ lỗi và tìm thấy chế độ xem luồng. Nó trông giống như biểu tượng dấu đầu dòng trong MS Word. Dù sao, bạn không cần phải ở chế độ gỡ lỗi để sử dụng nó. Bấm vào quá trình và bấm vào nút đó. Bất kỳ Dịch vụ Ý định nào sẽ hiển thị trong khi họ đang chạy, ít nhất là trên trình giả lập.


0

Nếu dịch vụ thuộc về một quy trình hoặc APK khác, hãy sử dụng giải pháp dựa trên Trình quản lý hoạt động.

Nếu bạn có quyền truy cập vào nguồn của nó, chỉ cần sử dụng giải pháp dựa trên trường tĩnh. Nhưng thay vì sử dụng boolean, tôi sẽ đề nghị sử dụng đối tượng Date. Trong khi dịch vụ đang chạy, chỉ cần cập nhật giá trị của nó thành 'ngay bây giờ' và khi hoàn thành, đặt thành không. Từ hoạt động bạn có thể kiểm tra xem null của nó hay ngày quá cũ có nghĩa là nó không chạy.

Bạn cũng có thể gửi thông báo quảng bá từ dịch vụ của mình cho biết đang chạy cùng thông tin khác như tiến trình.


0

Bên trong TheServiceClass xác định:

 public static Boolean serviceRunning = false;

Sau đó, trong onStartCommand (...)

 public int onStartCommand(Intent intent, int flags, int startId) {

    serviceRunning = true;
    ...
}

 @Override
public void onDestroy()
{
    serviceRunning = false;

} 

Sau đó, gọi if(TheServiceClass.serviceRunning == true)từ bất kỳ lớp học.


4
Điều này không hoạt động nếu dịch vụ của bạn bị Android giết.
Heisenberg

@Heisenberg Tôi chỉ tự mình trải nghiệm mà thôi. Bạn có biết tại sao không?
Tim

@Heisenberg khi ứng dụng của tôi bị HĐH giết, dịch vụ sẽ khởi động lại và đặt bool tĩnh thành true, nhưng khi nhận được nó báo cáo sai
Tim

Điều này sẽ không hoạt động nếu bạn gọi stopService. Ít nhất là cho các dịch vụ Ý định. onDestroy()sẽ được gọi ngay lập tức, nhưng onHandleIntent()vẫn sẽ được chạy
serggl

1
@Heisenberg Không giết dịch vụ do bộ nhớ thấp cũng có nghĩa là giết quá trình?
nhà phát triển Android

0

sử dụng đơn giản liên kết với không tạo tự động - xem ps. và cập nhật ...

public abstract class Context {

 ... 

  /*
  * @return {true} If you have successfully bound to the service, 
  *  {false} is returned if the connection is not made 
  *  so you will not receive the service object.
  */
  public abstract boolean bindService(@RequiresPermission Intent service,
        @NonNull ServiceConnection conn, @BindServiceFlags int flags);

thí dụ :

    Intent bindIntent = new Intent(context, Class<Service>);
    boolean bindResult = context.bindService(bindIntent, ServiceConnection, 0);

tại sao không sử dụng getRastyService ()

List<ActivityManager.RunningServiceInfo> getRunningServices (int maxNum)
Return a list of the services that are currently running.

Lưu ý: phương pháp này chỉ dành cho gỡ lỗi hoặc triển khai giao diện người dùng loại quản lý dịch vụ.


ps. tài liệu android là sai lệch tôi đã mở một vấn đề trên google tracker để loại bỏ mọi nghi ngờ:

https://issuetracker.google.com/issues/68908332

như chúng ta có thể thấy dịch vụ liên kết thực sự gọi một giao dịch thông qua liên kết ActivityManager thông qua các liên kết bộ đệm dịch vụ - tôi không theo dõi dịch vụ nào chịu trách nhiệm liên kết nhưng vì chúng ta có thể thấy kết quả của liên kết là:

int res = ActivityManagerNative.getDefault().bindService(...);
return res != 0;

giao dịch được thực hiện thông qua chất kết dính:

ServiceManager.getService("activity");

kế tiếp:

  public static IBinder getService(String name) {
    try {
        IBinder service = sCache.get(name);
        if (service != null) {
            return service;
        } else {
            return getIServiceManager().getService(name);

cái này được đặt trong ActivityThread thông qua:

 public final void bindApplication(...) {

        if (services != null) {
            // Setup the service cache in the ServiceManager
            ServiceManager.initServiceCache(services);
        }

cái này được gọi trong ActivityManagerService trong phương thức:

 private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
    ...
    thread.bindApplication(... , getCommonServicesLocked(),...)

sau đó:

 private HashMap<String, IBinder> getCommonServicesLocked() {

nhưng không có "hoạt động" chỉ có gói cửa sổ và báo động ..

vì vậy chúng tôi cần quay lại để gọi:

 return getIServiceManager().getService(name);

    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());

điều này thực hiện cuộc gọi thông qua:

    mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);

dẫn đến:

BinderInternal.getContextObject()

và đây là phương thức riêng ....

  /**
     * Return the global "context object" of the system.  This is usually
     * an implementation of IServiceManager, which you can use to find
     * other services.
     */
    public static final native IBinder getContextObject();

Bây giờ tôi không có thời gian để đào c vì vậy cho đến khi tôi mổ xẻ cuộc gọi, tôi tạm dừng câu trả lời của mình.

nhưng cách tốt nhất để kiểm tra nếu dịch vụ đang chạy là tạo liên kết (nếu liên kết không được tạo thì không tồn tại dịch vụ) - và truy vấn dịch vụ về trạng thái của nó thông qua liên kết (sử dụng cờ nội bộ được lưu trữ trên trạng thái).

cập nhật ngày 23 tháng 6 năm 2012

tôi tìm thấy những điều thú vị:

/**
 * Provide a binder to an already-bound service.  This method is synchronous
 * and will not start the target service if it is not present, so it is safe
 * to call from {@link #onReceive}.
 *
 * For peekService() to return a non null {@link android.os.IBinder} interface
 * the service must have published it before. In other words some component
 * must have called {@link android.content.Context#bindService(Intent, ServiceConnection, int)} on it.
 *
 * @param myContext The Context that had been passed to {@link #onReceive(Context, Intent)}
 * @param service Identifies the already-bound service you wish to use. See
 * {@link android.content.Context#bindService(Intent, ServiceConnection, int)}
 * for more information.
 */
public IBinder peekService(Context myContext, Intent service) {
    IActivityManager am = ActivityManager.getService();
    IBinder binder = null;
    try {
        service.prepareToLeaveProcess(myContext);
        binder = am.peekService(service, service.resolveTypeIfNeeded(
                myContext.getContentResolver()), myContext.getOpPackageName());
    } catch (RemoteException e) {
    }
    return binder;
}

Nói ngắn gọn :)

"Cung cấp một chất kết dính cho một dịch vụ đã bị ràng buộc. Phương pháp này là đồng bộ và sẽ không bắt đầu dịch vụ đích nếu nó không có mặt."

dịch vụ IBinder peekService (dịch vụ ý định, String yetType, String CallPackage) ném RemoteException;

*

public static IBinder peekService(IBinder remote, Intent service, String resolvedType)
             throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken("android.app.IActivityManager");
    service.writeToParcel(data, 0);
    data.writeString(resolvedType);
    remote.transact(android.os.IBinder.FIRST_CALL_TRANSACTION+84, data, reply, 0);
    reply.readException();
    IBinder binder = reply.readStrongBinder();
    reply.recycle();
    data.recycle();
    return binder;
}

*


bindResult (giá trị trả về của phương thức bindService) không xuất hiện dưới dạng false nếu dịch vụ không chạy.
Shangeeth Sivan

0

Chuyển đổi kotlin của tôi của các ActivityManager::getRunningServicescâu trả lời dựa. Đặt chức năng này trong một hoạt động-

private fun isMyServiceRunning(serviceClass: Class<out Service>) =
    (getSystemService(ACTIVITY_SERVICE) as ActivityManager)
        .getRunningServices(Int.MAX_VALUE)
        ?.map { it.service.className }
        ?.contains(serviceClass.name) ?: false

-2

Bạn có thể sử dụng các tùy chọn này từ các tùy chọn Nhà phát triển Android để xem dịch vụ của bạn có còn chạy trong nền không.

1. Open Settings in your Android device.
2. Find Developer Options.
3. Find Running Services option.
4. Find your app icon.
5. You will then see all the service that belongs to your app running in the background.

-5

Bình tĩnh nào mọi người ... :)

Tôi nghĩ rằng giải pháp phù hợp nhất là giữ một cặp khóa-giá trị trong SharedPreferenceskhoảng nếu dịch vụ có chạy hay không.

Logic rất thẳng; tại bất kỳ vị trí mong muốn trong lớp dịch vụ của bạn; đặt một giá trị boolean sẽ đóng vai trò là cờ cho bạn về việc dịch vụ có chạy hay không. Sau đó đọc giá trị này bất cứ nơi nào bạn muốn trong ứng dụng của bạn.

Mã mẫu mà tôi đang sử dụng trong ứng dụng của mình ở bên dưới:

Trong lớp Dịch vụ của tôi (Một dịch vụ cho Luồng âm thanh), tôi thực thi mã sau đây khi dịch vụ kết thúc;

private void updatePlayerStatus(boolean isRadioPlaying)
{
        SharedPreferences sharedPref = this.getSharedPreferences(getString(R.string.str_shared_file_name), Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPref.edit();
        editor.putBoolean(getString(R.string.str_shared_file_radio_status_key), isRadioPlaying);
        editor.commit();
}

Sau đó, trong bất kỳ hoạt động nào của ứng dụng của mình, tôi đang kiểm tra trạng thái của dịch vụ với sự trợ giúp của mã sau;

private boolean isRadioRunning() {
        SharedPreferences sharedPref = this.getSharedPreferences(getString(R.string.str_shared_file_name), Context.MODE_PRIVATE);

        return sharedPref.getBoolean(getString(R.string.str_shared_file_radio_status_key), false);
}

Không có quyền đặc biệt, không có vòng lặp ... Cách dễ dàng, giải pháp sạch :)

Nếu bạn cần thêm thông tin, xin vui lòng tham khảo liên kết

Hi vọng điêu nay co ich.


19
Chỉ có điều là không ai cập nhật giá trị cho bạn khi họ giết dịch vụ
Gunnar Forsgren - Mobimation

khi giết dịch vụ, onDestroy () sẽ được kích hoạt và có thể cập nhật trạng thái của nó
Jongz Puangput

5
@JongzPuangput, onDestroykhông phải lúc nào cũng được gọi khi dịch vụ bị giết. Ví dụ: tôi đã thấy các dịch vụ của mình bị giết trong các tình huống bộ nhớ thấp mà không onDestroyđược gọi.
Sam

@Sam Sau đó, cái gì sẽ được gọi là?
Ruchir Baronia

2
@RuchirBaronia Theo tôi nhớ, bạn chỉ cần không được thông báo khi công cụ của bạn bị giết. Tôi tin rằng Android được thiết kế để tiêu diệt các ứng dụng khi cần thiết và các ứng dụng nên được thiết kế để có thể bị giết bất cứ lúc nào mà không cần thông báo.
Sam
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.