服务崩溃并重新启动

有几个问题,但我总是读同样的事情:“如果系统需要资源,服务将被杀死”或“你不能建立一个永远运行的服务,因为它在后台运行的越多,更容易受到影响到系统杀死它“等等

我面临的问题是:我的服务运行正常并且正如预期的那样,如果我运行我的应用程序然后退出它我的服务仍在运行,但是当我杀死我的应用程序时(通过转到“最近的应用程序”并转换它离开)服务停止。 在这一刻,如果我进入设置>> aplications >>运行,我会看到该服务正在重启。 过了一会儿,它回来了,我的服务运行没有问题。

我谷歌它,我找到了一些我能做的事情,但让我先看看我的代码:

我通过这种方式启动我的服务(点击一下按钮后):

Intent intent = new Intent (MainActivity.this, MyService.class); startService(intent); 

我还有3个额外的整数,所以我有这样的东西:

 final Integer i, i2, i3; i = 5; //for example i2 = 10; //for example i3 = 15; //for example final Intent intent = new Intent (MainActivity.this, MyService.class); intent.putExtra("INTEGER1", i); intent.putExtra("INTEGER2", i2); intent.putExtra("INTEGER3", i3); startService(intent); 

在MyService中,我有以下方面:

 public class MyService extends Service { AlarmManager am; BroadcastReceiver br; PendingIntent pi; Integer i, i2, i3; @Override public void onCreate() { super.onCreate(); am = (AlarmManager) getSystemService(Context.ALARM_SERVICE); pi = PendingIntent.getBroadcast(this, 0, new Intent("anyany"); 0) //Why those zeros? br = new BroadcastReceiver () { public void onReceive (Context context, Intent i) { new thread(new Runnable() { public void run() { //do something } }).start(); } }; } @Override public void onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); try { i = intent.getIntExtra("INTENT1", 0) // I don't understant yet why this zero are here i2 = intent.getIntExtra("INTENT2", 0) i3 = intent.getIntExtra("INTENT3", 0); } catch(NullPointerException e) {} this.registerReceiver(br, new IntentFilter("anyany")); new thread(new Runnable() { public void run() { am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock. elapsedRealtime() + i*1000, i2*1000, pi); } }).start(); return START_REDELIVER_INTENT; //so I can get my Extra even with my Activity closed } 

我的onDestroy:

 @Override public void onDestroy() { unregisterReceiver(br); super.onDestroy(); } 

我也有onBind()方法(没有@Override),但它返回null。 我谷歌很多,我试图在前台运行该服务,所以我这样做(在de onStartCommand内):

 Notification n = new Notification(R.drawable.ic_laucher), getText(R.string.app_name), System.currentTimeMillis()); PendingIntent npi = PendingIntent.getActivity(this, MainActivity.class); n.setLatestEventInfo(this, getText(R.string.notification_title), getText(R.string.notification_message), npi); startForeground(3563, n); 

我的通知出现了,当我点击它我的应用程序运行,但我的服务问题没有修复(我相信它仍然不在前台运行)。 通知也重新启动。

我还删除了Try catch并为整数定义了一个值(所以我没有使用getIntExtra()方法),但没有改变

经过几次测试后,我试图查看日志,当我杀死我的应用程序时,我有以下消息:调度崩溃服务的重新启动。

因此,出于某种原因,当我的MainActivity死亡时,我的服务崩溃,为什么? 这里的意图不是要改变一个无法杀死的神的服务(我不认为这根本不可能,WhatsApp运行了105个小时!)但是在我的应用程序死后我的服务不会被破坏。

我不知道这是否有帮助,但这是我在Manifest.xml上添加的内容

    

最小API = 9,目标API = 17.运行时服务的大小:大约3MB。

希望我很清楚并抱歉我的英语。

PS:整个代码都按预期运行,所以如果你看到任何sintax错误可以自由编辑它。

编辑

如果我在AndroidManifest.xml的中添加android:isolatedProcess="true" ,我在logCat中收到此错误: java.lang.RuntimeException: Unable to create a service in com.mycompany.myapp.myservice: java.lang.SecurityException: Isolated process not allow ed to call getIntentSender

当我使用它启动我的服务时,MainActivity不会显示任何错误,只有服务崩溃。

我终于找到了解决方案! 我从服务中删除了AlarmManager,服务不再兑现,但我必须使用它

问题是用户从最近的应用程序中移出应用程序后服务崩溃,所以我做的是阻止应用程序出现在该窗口中。 将以下内容作为的子项添加到AndroidManifest.xml中

 android:excludeFromRecents="true" 

现在,当用户从您的应用程序退出时,它不会出现在最近的应用程序窗口中,这意味着系统在退出后立即杀死活动,因此它不会浪费任何资源。

PS:不要忘记将服务设置为在单独的进程中运行,将以下内容添加到AndroidManifest.xml中,作为的子进程

 android:process=":remote" 

编辑 – 找到真正的解决方案

经过大量的研究和研究(几个月的研究),我深入研究了android API,这里是一个被发现的,这是仅在API 16+中出现的预期行为,android arquiteture的变化改变了PendingIntents的方式由系统广播,所以Google添加了标志FLAG_RECEIVER_FOREGROUND ,你必须将这个标志传递给你在PendingIntent.getBroadcast()上用作参数的意图,这里是例子:

 if(Build.VERSION.SDK_INT >= 16) //The flag we used here was only added at API 16 myIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); //use myIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); if you want to add more than one flag to this intent; PendingIntent pi = PendingIntent.getBroadcast(context, 1, myIntent, 0); // the requestCode must be different from 0, in this case I used 1; 

早于API 16的Android版本将按预期工作,如果您从“最近的应用”页面中删除该应用,该服务不会崩溃。

正如文档所说, Service在其被调用者的主线程中运行,通常是UI线程。 所以发生的事情是当你杀死你的应用程序时,你会杀死你的应用程序进程,因此服务也会被杀死。

您可以通过在Manifest.xml文件的标记中使用android:process在不同的进程中创建Service来解决此问题。

但是,通常,如果Service需要独立于被调用者并且可能由不同的应用程序使用,则在其自己的进程中启动Service 。 如果您的Service仅供您自己的应用程序使用,那么请坚持使用默认行为,并且不要杀死您的应用程序。

编辑1:

android:isolatedProcess的文档说:

如果设置为true,则此服务将在与系统其余部分隔离的特殊进程下运行,并且没有自己的权限。 与它的唯一通信是通过Service API(绑定和启动)。

从另一个SO答案(链接) ,这是预期的行为。 但可以肯定的是,这里有人会有解决方法或解决方案。

您的代码问题:

pi = PendingIntent.getBroadcast(this,0,new Intent(“anyany”); 0)//为什么那些为零?

你看到的第一个零被称为requesCode并被描述为目前没有被使用:

requestCode:发件人的私有请求代码(当前未使用)。

第二个零实际上应该是给定的标志之一(这里) 。

i = intent.getIntExtra(“INTENT1”,0)//我不明白为什么这个零点在这里

getIntExtra(String, int)方法不需要将0作为其第二个参数:它可以是任何整数。 getIntExtra(String, int)返回与您提供的String键对应的整数。 如果此键不存在(或从未执行过),则getIntExtra(String, int)将返回我们传递的整数作为第二个参数。 它是密钥失败时的默认值。