繁体   English   中英

服务崩溃并重新启动

[英]Service crashing and restarting

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

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

问题是用户从最近的应用程序中删除应用程序后服务崩溃,所以我所做的是阻止应用程序出现在该窗口中。 将以下内容作为<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版本将按预期工作,如果您从“最近的应用”页面中删除该应用,该服务将不会崩溃。

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

您可以通过在Manifest.xml文件的<service>标记中使用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)将返回作为第二个参数传递的整数。 密钥失败时的默认值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM