【问题标题】:Android restart service correctly after app is closed应用关闭后Android正确重启服务
【发布时间】:2017-01-16 09:37:45
【问题描述】:

我目前正在开发一个电子邮件应用程序,它依赖于背景service,以便能够自动获取新电子邮件。当应用程序打开(或在应用程序的运行列表中)时,这非常有效,但只要我关闭应用程序/将其从最近的应用程序列表中删除,service 也会停止。这可以通过进入设备上的“开发人员设置”并查看没有为我的应用程序运行的进程或服务来确认。

我已经阅读了 StackOverflow 上的无数线程,但似乎没有一个能起到作用。有时会调用onTaskRemoved() 并重新启动服务,但有时根本不会调用它或调用它,日志显示操作系统已安排重启service,但随后service由操作系统获取forced closed,而我总是需要运行此服务来检索新电子邮件。

我目前的代码如下:

我的服务:

 @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();

因此,我想问,即使在应用程序关闭或设备为rebooted 时,我如何确保我的service 持续运行/工作,同时仍然可以访问位于getApplication() 中的组件?

当我尝试将MyService 作为单独的process 运行时,上面的updateListRunnable 将始终返回null,而当应用程序和service 在同一个process 中运行时,它将返回正确的runnable

【问题讨论】:

  • 你有你的解决方案吗?

标签: java android service background-service long-running-processes


【解决方案1】:

不久前我遇到了类似的问题,并在我的服务的 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 秒的警报,这将再次启动我的服务。这样,当用户从最近删除它时,您的服务将停止,但它会重新启动。

【讨论】:

【解决方案2】:

对我来说,使用来自 onDestroy 的 AlarmManager 重新启动服务不起作用,但从 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 启动服务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多