簡體   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