Android关闭应用程序后正确重启服务

5
我正在开发一款电子邮件应用程序,它依赖于后台服务才能自动拉取新邮件。当应用程序处于打开状态(或在运行的应用程序列表中)时,这个功能是完美的。但是,一旦我关闭应用程序/将其从最近的应用程序列表中移除,服务也会停止。可以通过进入设备上的“开发者设置”来确认此事实,并查看没有为我的应用程序运行进程或服务。
我已经在 StackOverflow 上阅读了无数的帖子,但没有一个看起来能够解决问题。有时会调用onTaskRemoved()并重新启动服务,但其他情况下则不会被调用,或者尽管操作系统已经安排重新启动服务,但服务却被操作系统强制关闭,而我总是需要让这个服务运行以获取新的邮件。
以下是我的当前代码:
我的服务:
 @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);

        Log.i(TAG, "onStartCommand()");

        ...

        Log.d(TAG, "SERVICE IS RUNNING");

        if (host != null) {
            Log.d(TAG, "STARTING PUSH SERVICE");

            Handler handler = new Handler();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    Log.d(TAG, "BR: " + ((BugReporting) getApplication()));
                    sharedRunnable = ((BugReporting) getApplication()).getSharedRunnable();

                    MailPush mailPush = new MailPush(getApplicationContext(), sharedRunnable);
                    Log.d(TAG, "sharedRunnable 1: " + sharedRunnable);
                    mailPush.checkInboxEmail(host, email, password);
                    //mailPush.checkSentEmail(host, email, password);
                }
            };
            handler.postDelayed(runnable, 5000);//0.5 seconds

        }

        return START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate()");
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Log.i(TAG, "onTaskRemoved()");

        PendingIntent service = PendingIntent.getService(
                getApplicationContext(),
                1001,
                new Intent(getApplicationContext(), MyService.class),
                PendingIntent.FLAG_ONE_SHOT);

        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy()");
        startService(new Intent(this, MyService.class));
    }

重新启动接收器:

 public class AutoStart extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        context.startService(new Intent(context, MyService.class));
    }
}

清单文件:

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

...

        <receiver
                android:name="uk.co.tundracorestudios.securemail.notification.AutoStart"
                android:enabled="true"
                android:exported="true"
                android:process=":remote">
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED" />
                </intent-filter>
            </receiver>

            <service
                android:name="uk.co.tundracorestudios.securemail.notification.MyService"
                android:enabled="true"
                android:exported="true"
                android:label="@string/mail_service"
                android:stopWithTask="false"/>

我尝试将 MyService 作为不同的 process 运行,但这样会限制我从应用程序类中获取已保存的 sharedRunnable,否则可以通过以下方式访问:
 updateListRunnable = ((BugReporting) getApplication()).getSharedRunnable();

因此,我想问,如何确保我的service即使应用程序关闭或设备重启时仍然持续运行/工作,并且仍然可以访问位于getApplication()中的组件?
当我尝试将MyService作为一个单独的process运行时,上面的updateListRunnable总是会返回null,而当应用程序和service在同一个process中运行时,它会返回正确的runnable

你有解决方案吗? - Dinh Quang Tuan
2个回答

4

我之前遇到过类似的问题,在我的服务的onDestroy()方法中使用了以下代码:

public void onDestroy() {
    Intent restartService = new Intent(getApplicationContext(),this.getClass());
    PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(),1,restartService,PendingIntent.FLAG_ONE_SHOT);
    AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    alarmManager.set(AlarmManager.ELAPSED_REALTIME,5000,pendingIntent);
    super.onDestroy();
}

当服务被销毁时,我设置了一个5秒的闹钟,它将重新启动我的服务。这样,当用户从最近使用列表中删除服务时,服务将停止,但会再次启动。


正确。onTaskRemoved 不是服务生命周期方法的一部分:https://developer.android.com/guide/components/services.html#LifecycleonTaskRemoved 的描述在这里:https://developer.android.com/reference/android/app/Service.html#onTaskRemoved(android.content.Intent) - Ryan
非常感谢 nullvoid!我已经尝试了互联网上提供的所有解决方案,这个解决了我的问题,这样强制关闭的应用程序就可以收到通知了。几乎进行了一个月的奋斗!感谢您分享您的解决方案! - Lozy
嗯..服务有onDestroy()方法吗? - Azizjon Kholmatov

0

对我而言,使用AlarmManager从onDestroy重启服务并不起作用,但是从onTaskRemoved启动服务可以。当您在服务正在运行时杀死应用程序时,将触发onTaskRemoved函数。

@Override
        public void onTaskRemoved(Intent rootIntent) {
            Log.d(TAG, "onTaskRemoved: removed");
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(System.currentTimeMillis() + 10000);
((AlarmManager) getSystemService(Context.ALARM_SERVICE)).setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), PendingIntent.getService(getApplicationContext(), 0, new Intent(getApplicationContext(), RegisterReceiverService.class), 0));
            super.onTaskRemoved(rootIntent);
        }

基本上,一旦您关闭应用程序,服务将在10秒后启动。 注意:如果您想使用

AlarmManager.ELAPSED_REALTIME_WAKEUP

您可以重新启动服务的最短时间为15分钟。

请记得使用BroadcastReceiver在重启后启动服务。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接