Dịch vụ Android dừng khi ứng dụng bị đóng


77

Tôi đang bắt đầu một dịch vụ từ hoạt động Android chính của mình như sau:

final Context context = base.getApplicationContext();
final Intent intent = new Intent(context, MyService.class);
startService(intent);

Khi tôi đóng trang hoạt động bằng cách vuốt nó ra khỏi danh sách ứng dụng gần đây, dịch vụ sẽ ngừng chạy và khởi động lại sau một thời gian. Tôi không thể sử dụng các dịch vụ liên tục có thông báo do yêu cầu ứng dụng của tôi. Làm cách nào tôi có thể làm cho dịch vụ KHÔNG khởi động lại hoặc tắt và tiếp tục chạy khi thoát ứng dụng?



@kiran Vấn đề tôi đang gặp phải là dịch vụ được khởi động lại khi hoạt động đóng. Tôi đang tìm cách để giữ cho dịch vụ hoạt động mọi lúc (mà không cần khởi động lại khi hoạt động kết thúc).
Bam

1
Tôi cảm thấy chúng tôi không thể đạt được điều đó. Khi tài nguyên thấp, dịch vụ của bạn sẽ bị giết. Điều tốt nhất chúng tôi có thể hy vọng là khởi động lại. Và trên 4.4+, thao tác vuốt giết thậm chí sẽ không khởi động lại dịch vụ. Vui lòng đọc chủ đề
Kiran

Hãy suy nghĩ kỹ về việc bạn có thực sự cần dịch vụ của mình luôn chạy theo đúng nghĩa đen hay không: điều này có hại cho việc tiêu thụ năng lượng và bộ nhớ.
poolie

Câu trả lời:


48

Tôi đang ở trong tình huống tương tự, cho đến nay tôi đã biết khi ứng dụng bị đóng, dịch vụ cũng bị đóng bởi vì chúng nằm trong một chuỗi, vì vậy dịch vụ nên nằm trên một chuỗi khác để không bị đóng, hãy xem xét điều đó và xem xét việc duy trì hoạt động của dịch vụ với trình quản lý cảnh báo tại đây, ví dụ http://www.vogella.com/articles/AndroidServices/article.html theo cách này, dịch vụ của bạn sẽ không được hiển thị trong thông báo.

cuối cùng, sau tất cả các nghiên cứu tôi đã thực hiện, tôi nhận ra rằng lựa chọn tốt nhất cho một dịch vụ hoạt động lâu dài là startForeground()vì nó được tạo ra cho điều đó và hệ thống thực sự xử lý tốt dịch vụ của bạn.


10
@Bam Tôi có vấn đề chính xác này. Tuy nhiên, dịch vụ của tôi LÀ một dịch vụ nền trước và nó vẫn bị giết khi hoạt động của tôi bị đóng. Tôi đã thay đổi đối số khởi tạo ý định của mình từ ngữ cảnh getApplicationContext () thành getBaseContext () và nó đã giải quyết được vấn đề.
JayB

1
tôi có thể sử dụng getBaseContext () trong pendingIntent không?
Kairi San

1
thay vì sử dụng notificationManager.notify(intent.getIntExtra("notification_Id", 0), builder.build());tôi có nên sử dụng startForeground(intent.getIntExtra("notification_Id, 0), builder.build());không? Tôi đang sử dụng NotificationCompat.Builder
Kairi San

startForeground () cần api 26 có giải không?
Midhilaj

13

khiến bạn phục vụ như vậy trong Mainifest của bạn

 <service
            android:name=".sys.service.youservice"
            android:exported="true"
        android:process=":ServiceProcess" />

thì dịch vụ của bạn sẽ chạy trên quy trình khác có tên ServiceProcess


nếu bạn muốn làm cho dịch vụ của bạn không bao giờ chết:

  1. onStartCommand () trả về START_STICKY

  2. onDestroy () -> startelf

  3. tạo một dịch vụ Deamon

  4. jin -> tạo quy trình Deamon bản địa, bạn có thể tìm thấy một số dự án mã nguồn mở trên github

  5. startForeground (), có một cách để startForeground mà không cần Thông báo, hãy google nó


12
Khá chắc chắn rằng bắt đầu từ onDestroy sẽ được coi là chiến đấu với hệ thống Android, đó là một hành vi xấu.
Flare Cat

12

Điều này có thể giúp bạn. Tôi có thể nhầm nhưng đối với tôi thì có vẻ như điều này có liên quan đến việc trả về START_STICKYtrong onStartCommand()phương thức của bạn . Bạn có thể tránh gọi lại dịch vụ bằng cách quay lại START_NOT_STICKY.


4
Trên thực tế, dịch vụ ngừng chạy khi tôi thoát hoặc đóng ứng dụng (và sau đó dịch vụ khởi động lại). Tôi không muốn dịch vụ tạm dừng / dừng khi tôi thoát / đóng ứng dụng; Tôi muốn nó tiếp tục chạy. Tôi tin rằng giải pháp có liên quan đến việc chạy dịch vụ trên một quy trình riêng biệt nhưng tôi không thực sự chắc chắn.
Bam

Làm việc artex tốt, Cảm ơn
Manikandan K

8

Các dịch vụ đôi khi khá phức tạp.

Khi bạn bắt đầu một dịch vụ từ một hoạt động (hoặc quy trình của bạn), về cơ bản, dịch vụ cũng nằm trên cùng một quy trình.

trích dẫn từ ghi chú của nhà phát triển

Hầu hết sự nhầm lẫn về lớp Dịch vụ thực sự xoay quanh những gì nó không phải là:

Một Dịch vụ không phải là một quá trình riêng biệt. Bản thân đối tượng Dịch vụ không ngụ ý rằng nó đang chạy trong quy trình của chính nó; trừ khi được chỉ định khác, nó chạy trong cùng một quá trình với ứng dụng mà nó là một phần.

Dịch vụ không phải là một chuỗi. Bản thân nó không phải là một phương tiện để thực hiện công việc của chuỗi chính (để tránh lỗi Ứng dụng Không phản hồi).

Vì vậy, điều này có nghĩa là, nếu người dùng vuốt ứng dụng khỏi các tác vụ gần đây, nó sẽ xóa quy trình của bạn (điều này bao gồm tất cả các hoạt động của bạn, v.v.). Bây giờ, hãy xem ba tình huống.

Đầu tiên , nơi dịch vụ không có thông báo nền trước.

Trong trường hợp này, quy trình của bạn bị hủy cùng với dịch vụ của bạn.

Thứ hai , nơi dịch vụ thông báo nền trước

Trong trường hợp này, dịch vụ không bị giết và quá trình cũng không

Tình huống thứ ba Nếu dịch vụ không có thông báo nền, nó vẫn có thể tiếp tục chạy nếu ứng dụng bị đóng. Chúng tôi có thể làm điều này bằng cách làm cho dịch vụ chạy trong một quy trình khác. (Tuy nhiên, tôi đã nghe một số người nói rằng nó có thể không hoạt động. Hãy để bạn tự thử )

bạn có thể tạo một dịch vụ trong một quy trình riêng biệt bằng cách đưa thuộc tính dưới đây vào tệp kê khai của mình.

android: process = ": yourService"

hoặc là

android: process = "yourService" tên tiến trình phải bắt đầu bằng chữ thường.

trích dẫn từ ghi chú của nhà phát triển

Nếu tên được gán cho thuộc tính này bắt đầu bằng dấu hai chấm (':'), một quy trình mới, riêng tư đối với ứng dụng, sẽ được tạo khi cần thiết và dịch vụ sẽ chạy trong quy trình đó. Nếu tên tiến trình bắt đầu bằng một tự viết thường , dịch vụ sẽ chạy trong một tiến trình chung của tên đó, với điều kiện nó có quyền làm như vậy. Điều này cho phép các thành phần trong các ứng dụng khác nhau chia sẻ một quy trình, giảm việc sử dụng tài nguyên.

đây là những gì tôi đã thu thập được, nếu ai là chuyên gia, xin vui lòng sửa cho tôi nếu tôi sai :)



4

Vấn đề chính là không thể khởi động dịch vụ khi ứng dụng đóng, hệ điều hành android ( Trong một số hệ điều hành ) sẽ giết dịch vụ để Tối ưu hóa tài nguyên, Nếu bạn không thể khởi động lại dịch vụ, hãy gọi người quản lý báo động để khởi động bộ thu như thế này, Đây là toàn bộ mã, Mã này sẽ giữ cho dịch vụ của bạn còn sống.

Tệp kê khai là,

         <service
            android:name=".BackgroundService"
            android:description="@string/app_name"
            android:enabled="true"
            android:label="Notification" />
        <receiver android:name="AlarmReceiver">
            <intent-filter>
                <action android:name="REFRESH_THIS" />
            </intent-filter>
        </receiver>

TRONG Máng báo thức khởi động Activty chính theo cách này,

String alarm = Context.ALARM_SERVICE;
        AlarmManager am = (AlarmManager) getSystemService(alarm);

        Intent intent = new Intent("REFRESH_THIS");
        PendingIntent pi = PendingIntent.getBroadcast(this, 123456789, intent, 0);

        int type = AlarmManager.RTC_WAKEUP;
        long interval = 1000 * 50;

        am.setInexactRepeating(type, System.currentTimeMillis(), interval, pi);

điều này sẽ là người nhận cuộc gọi và người nhận cuộc gọi là,

public class AlarmReceiver extends BroadcastReceiver {
    Context context;

    @Override
    public void onReceive(Context context, Intent intent) {
        this.context = context;

        System.out.println("Alarma Reciver Called");

        if (isMyServiceRunning(this.context, BackgroundService.class)) {
            System.out.println("alredy running no need to start again");
        } else {
            Intent background = new Intent(context, BackgroundService.class);
            context.startService(background);
        }
    }

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

        if (services != null) {
            for (int i = 0; i < services.size(); i++) {
                if ((serviceClass.getName()).equals(services.get(i).service.getClassName()) && services.get(i).pid != 0) {
                    return true;
                }
            }
        }
        return false;
    }
}

Và người nhận Alaram này sẽ gọi một lần khi ứng dụng android được mở và khi ứng dụng được đóng lại.

public class BackgroundService extends Service {
    private String LOG_TAG = null;

    @Override
    public void onCreate() {
        super.onCreate();
        LOG_TAG = "app_name";
        Log.i(LOG_TAG, "service created");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(LOG_TAG, "In onStartCommand");
        //ur actual code
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // Wont be called as service is not bound
        Log.i(LOG_TAG, "In onBind");
        return null;
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Log.i(LOG_TAG, "In onTaskRemoved");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(LOG_TAG, "In onDestroyed");
    }
}

2

hãy thử điều này, nó sẽ giữ cho dịch vụ chạy trong nền.

BackServices.class

public class BackServices extends Service{

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
      // Let it continue running until it is stopped.
      Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
      return START_STICKY;
   }
   @Override
   public void onDestroy() {
      super.onDestroy();
      Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
   }
}

trong MainActivity của bạn, hãy onCreatethả dòng mã này

startService(new Intent(getBaseContext(), BackServices.class));

Bây giờ dịch vụ sẽ tiếp tục chạy trong nền.


7
Vấn đề vẫn còn ở đó: khi tôi giết ứng dụng từ menu gần đây, dịch vụ sẽ được khởi động lại (onStartCommand được gọi lại). Điều duy nhất giúp tôi là làm cho nó trở thành một dịch vụ tiền cảnh.
Bam

1

Sử dụng cùng một quy trình cho dịch vụ và hoạt động và START_STICKY hoặc START_REDELIVER_INTENT trong dịch vụ là cách duy nhất để có thể khởi động lại dịch vụ khi ứng dụng khởi động lại, điều này xảy ra khi người dùng đóng ứng dụng, chẳng hạn như khi hệ thống quyết định để đóng nó vì lý do tối ưu hóa. Bạn KHÔNG THỂ có một dịch vụ sẽ chạy vĩnh viễn mà không bị gián đoạn. Điều này là do thiết kế, điện thoại thông minh không được tạo ra để chạy các quy trình liên tục trong thời gian dài. Điều này là do thực tế là thời lượng pin là ưu tiên cao nhất. Bạn cần thiết kế dịch vụ của mình để nó xử lý việc bị dừng tại bất kỳ thời điểm nào.


1

Bạn phải thêm mã này vào lớp Dịch vụ của mình để nó xử lý trường hợp khi quy trình của bạn bị hủy

 @Override
    public void onTaskRemoved(Intent rootIntent) {
        Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
        restartServiceIntent.setPackage(getPackageName());

        PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
        AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        alarmService.set(
                AlarmManager.ELAPSED_REALTIME,
                SystemClock.elapsedRealtime() + 1000,
                restartServicePendingIntent);

        super.onTaskRemoved(rootIntent);
    }

0

Tại sao không sử dụng IntentService?

IntentService mở một Chủ đề mới ngoài Chủ đề chính và hoạt động ở đó, theo cách đó, việc đóng ứng dụng sẽ không ảnh hưởng đến nó

Hãy lưu ý rằng IntentService chạy onHandleIntent () và khi hoàn thành, dịch vụ sẽ đóng lại, hãy xem nó có phù hợp với nhu cầu của bạn không. http://developer.android.com/reference/android/app/IntentService.html


2
Trên thực tế, yêu cầu của tôi là có một dịch vụ nền luôn chạy. Việc bắt đầu dịch vụ dưới dạng Dịch vụ nền trước đã giải quyết được vấn đề đó cho tôi.
Bam

0

Giải pháp tốt nhất là sử dụng Bộ điều hợp đồng bộ trong Android để bắt đầu dịch vụ. Tạo Bộ điều hợp đồng bộ và gọi dịch vụ bắt đầu của chúng .. bên trong phương thức onPerformSync. để tạo Tài khoản đồng bộ hóa, vui lòng tham khảo liên kết này https://developer.android.com/training/sync-adapters/index.html

Tại sao SyncAdapter? Trả lời: Vì trước đó bạn đã từng khởi động dịch vụ bằng ngữ cảnh Ứng dụng của mình. vì vậy bất cứ khi nào quy trình ứng dụng của bạn bị giết (Khi bạn xóa nó khỏi trình quản lý tác vụ hoặc OS, hãy giết nó vì thiếu tài nguyên) lúc đó dịch vụ của bạn cũng sẽ bị xóa. SyncAdapter sẽ không hoạt động trong chuỗi ứng dụng .. vì vậy nếu bạn gọi bên trong nó .. dịch vụ sẽ không còn bị xóa nữa .. trừ khi bạn viết mã để loại bỏ nó.


0
<service android:name=".Service2"
            android:process="@string/app_name"
            android:exported="true"
            android:isolatedProcess="true"
            />

Khai báo điều này trong tệp kê khai của bạn. Đặt tên tùy chỉnh cho quy trình của bạn và làm cho quy trình đó được tách biệt và xuất.


0

Chạy một dịch vụ có mục đích sẽ dễ dàng hơn. Dịch vụ tạo một luồng trong ứng dụng nhưng nó vẫn nằm trong ứng dụng.


-5

Chỉ cần ghi đè phương thức onDestroy trong hoạt động hiển thị đầu tiên của bạn như sau khi có splash, bạn có trang chủ và trong khi chuyển hướng từ splash đến trang chủ, bạn đã hoàn thành splash. vì vậy hãy đặt trên trang chủ. và ngừng dịch vụ trong phương pháp đó.

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.