服务崩溃并重新启动

时间:2013-07-21 04:04:41

标签: java android service crash kill

关于它有几个问题,但我总是读同样的事情:“如果系统需要资源,服务将被杀死”或“你无法构建一个永远运行的服务,因为它在后台运行得越多,更多容易被系统杀死“等等。

我面临的问题是:我的服务运行良好并且正如预期的那样,如果我运行我的应用程序然后退出它我的服务仍在运行,但是当我杀死我的应用程序时(通过转到“最近的应用程序”)并且远离它)服务停止。在这一刻,如果我转到设置>> 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上添加的内容

<Activity android:name = ".MyService"/>
<service android:name ="Myservice" android:enabled="true" android: exported="false"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>

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

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

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

修改

如果我在AndroidManifest.xml中的android:isolatedProcess="true"中添加<service>,我会在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不显示任何错误,只有服务崩溃。

3 个答案:

答案 0 :(得分:10)

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

问题是用户从最近的应用程序中移出应用程序后服务崩溃,所以我做的是阻止应用程序出现在该窗口中。将以下内容作为<activity>

的子项添加到AndroidManifest.xml中
android:excludeFromRecents="true"

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

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

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版本将按预期工作,如果您从“最近的应用”页面中删除该应用,该服务不会崩溃。

答案 1 :(得分:3)

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

您可以通过在Service文件的<service>标记中使用android:process在其他流程中创建Manifest.xml来解决此问题。

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

编辑1:

android:isolatedProcess的文档说:

  

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

答案 2 :(得分:1)

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

您的问题来自代码:

  

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

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

  

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

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

  

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

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