2011-05-28 69 views
3

我在做什麼?罕見的崩潰用於AppWidget更新

我更新使用IntentService的AppWidget。

什麼問題?

一切都工作得很好,除了一些稀有次大概每隔12-15小時或者我可以說是隨機的,小部件的更新不會發生。在通過這種情況進行調試之後,看起來是問題的logcat消息。

05-27 20:21:13.122: WARN/ActivityManager(97): Scheduling restart of crashed service com.myapp.android/.myAppWidget$UpdateService in 5000ms 

以下是一些更爲logcat的消息 - 這是真的很難複製這一點,因爲這一段時間發生一次,但發生這種情況時,我重新啓動我使用調試模式通過USB端口連接真實設備上的應用程序。

05-27 20:21:16.712: DEBUG/AndroidRuntime(24419): --- registering native functions --- 
05-27 20:21:16.742: INFO/global(24420): Default buffer size used in BufferedInputStream constructor. It would be better to be explicit if an 8k buffer is required. 
05-27 20:21:16.842: DEBUG/Configuration(24420): active site = local 
05-27 20:21:16.872: DEBUG/FREESPACE(24420): Bytes to fill: 580550656 
05-27 20:21:16.942: VERBOSE/AlarmManager(97): Adding Alarm{46389f38 type 2 com.google.android.apps.maps} Jan 01 09:30:42 am 
05-27 20:21:17.032: INFO/ActivityManager(97): Start proc com.myApp.android for broadcast com.myApp.android/.myAppWidget: pid=24431 uid=10080 gids={1015, 3003} 
05-27 20:21:17.092: DEBUG/dalvikvm(24420): GC_FOR_MALLOC freed 3967 objects/320968 bytes in 162ms 
05-27 20:21:17.172: DEBUG/FREESPACE(24420): Bytes to fill: 580550656 
05-27 20:21:17.252: ERROR/UpdateService(24431): Service Started.. 
05-27 20:21:17.332: INFO/ActivityManager(97): Force stopping package com.myApp.android uid=10080 
05-27 20:21:17.332: INFO/Process(97): Sending signal. PID: 24431 SIG: 9 
05-27 20:21:17.332: WARN/ActivityManager(97): Scheduling restart of crashed service com.myApp.android/.myAppWidget$UpdateService in 5000ms 
05-27 20:21:17.332: INFO/ActivityManager(97): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.myApp.android/.myApp3 } 
05-27 20:21:17.372: INFO/ActivityManager(97): Start proc com.myApp.android for activity com.myApp.android/.myApp3: pid=24444 uid=10080 gids={1015, 3003} 
05-27 20:21:17.402: DEBUG/AndroidRuntime(24419): Shutting down VM 

以下是的onReceive(),的onUpdate()和onHandleIntent()的代碼段延伸IntentService

@Override 
public void onReceive(Context context, Intent intent) { 
    check_intent = intent.getAction(); 

    if (check_intent.equals("android.appwidget.action.APPWIDGET_UPDATE")) { 
     if (!getLock(context).isHeld()) { // fail-safe for crash restart 
      getLock(context).acquire(); 
     } 
     try { 
      this.onUpdate(context, intent); 
     } finally { 
      getLock(context).release(); 
     } 
    }  
    if (check_intent.equals("android.appwidget.action.APPWIDGET_ENABLED")) { 
     this.onEnabled(context); 
    } 
    if (check_intent.equals("android.appwidget.action.APPWIDGET_DELETED")) { 
     this.onDeleted(context); 
    } 
    if (check_intent.equals("android.appwidget.action.APPWIDGET_DISABLED")) { 
     this.onDisabled(context); 
    } 
    super.onReceive(context, intent); 
} 

這裏UpdateService類onUpdate其中startService方法被稱爲

public void onUpdate(Context context, Intent intent) { 

    mAppPreferences = PreferenceManager.getDefaultSharedPreferences(context); 
    int saved_num_widgets = mAppPreferences.getInt(NUM_WIDGETS, 0); 

    if (saved_num_widgets > 0) {  
     Intent widgetUpdate = new Intent(context, myAppWidget.class); 
     widgetUpdate.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 
     AlarmManager alarms = 
      (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); 
     PendingIntent newPending = 
      PendingIntent.getBroadcast(context, 
             0, 
             widgetUpdate, 
             PendingIntent.FLAG_CANCEL_CURRENT); 
     alarms.set(AlarmManager.ELAPSED_REALTIME, 
        SystemClock.elapsedRealtime() + PERIOD, 
        newPending); 
     context.startService(new Intent(context, UpdateService.class)); 
    } else { 
     //Show Notification   
    } 
} 

最後這裏是代碼onHandleIntent()

@Override 
protected void onHandleIntent(Intent intent) { 
    // here is where your long running task goes 

    RemoteViews updateViews = buildUpdate(this); 
    // Push update for this widget to the home screen 
    if (updateViews != null) { 
     ComponentName thisWidget = new ComponentName(this, myAppWidget.class); 
     AppWidgetManager manager = AppWidgetManager.getInstance(this); 
     manager.updateAppWidget(thisWidget, updateViews); 
    } else { 
     updateViews = new RemoteViews(getApplicationContext().getPackageName(), 
             R.layout.tuwidget); 
     updateViews.setImageViewResource(R.id.ad, R.drawable.myApp_null_game); 
     Intent defineIntent1 = new Intent(getApplicationContext(), myApp3.class); 
     PendingIntent pendingIntent1 = 
      PendingIntent.getActivity(getApplicationContext(), 
             0 /* no requestCode */, 
             defineIntent1, 
             0 /* no flags */); 
     updateViews.setOnClickPendingIntent(R.id.tuwidget, pendingIntent1); 
     ComponentName thisWidget = new ComponentName(this,myAppWidget.class); 
     AppWidgetManager manager = AppWidgetManager.getInstance(this); 
     manager.updateAppWidget(thisWidget, updateViews); 
    } 

} 

我也想提一提的UpdateService類從IntentService擴展是

  1. 我不使用onStartCommand
  2. 的onCreate()是如下

    @Override 
    public void onCreate() { 
        super.onCreate(); 
        Log.e("UpdateService", "Service Started.. "); 
    } 
    

的小部件以正確的時間間隔更新,一切正常,沒有強制關閉,但我完全失去了爲什麼更新不會發生有時候。

我沒有爲buildUpdate的函數,返回RemoteViews因爲我110%肯定這部分工作沒有問題,更新窗口小部件提供的代碼。

更新:我注意到,每當發生此問題時,我看到IntentService的早期實例仍在應用程序中運行 - >運行服務,這意味着onDestroy()有時不會被調用,並且服務不會自動停止正如它應該的那樣。有趣的是什麼,我所做的就是創建一個共享縣以存儲服務的運行狀態或停止,並從的onCreate()和的onDestroy()將其切換。現在擺在我調用startService()我檢查共享PREF的狀態,如果該服務的實例仍在運行我叫stopService(),然後再startService()。我仍然在測試它,但是在編寫這個解決方法之後,問題還沒有發生!

+0

@Aakash:「通過這裏的情況調試後,logcat消息似乎是問題」 - 不,這表明你有問題。如果服務崩潰了,可能會在日誌中的此行之前有一個與該崩潰相關的堆棧跟蹤。如果沒有,您將需要添加更多的'Log'語句來嘗試隔離發生崩潰的位置。順便說一句,你正在獲取並釋放'WakeLock',其中一個已經被'AlarmManager'(例如觸發'updatePeriodMillis()'的警報)佔據。 – CommonsWare 2011-05-28 11:41:16

+0

啊!我感覺好多了Mr.Mark救我! OK對onReceive中的wakelock感到抱歉,我只是在調試不同的場景。因此記錄了一些消息並進行了一些調試,可以看到在偶然的崩潰中,我的服務已經啓動,然後什麼也沒有發生。增加了一些更多的logcat消息。 – Aakash 2011-05-28 13:11:23

+0

@Aakash:對於「強制停止包」日誌消息,有各種各樣的觸發器,我無法確定哪些可能會跳過。抱歉! – CommonsWare 2011-05-28 13:37:27

回答

1

此日誌表明有人叫進活動管理器殺你的應用程序:

05-27 20:21:17.332: INFO/ActivityManager(97): Force stopping package com.myApp.android uid=10080 
05-27 20:21:17.332: INFO/Process(97): Sending signal. PID: 24431 SIG: 9 

此前的Android 2。2,這將是強制停止API,例如任務管理器用於終止應用程序並停止所有服務等。檢查以確保您的設備上沒有安裝任何任務管理器類別的應用程序,這些應用程序正在執行惡劣的事情。

從2.2開始,任務管理器使用的API被更改爲僅允許它們終止後臺進程。看起來這就是這裏發生的事情 - 進程正在被殺死,但是整個應用程序並沒有被強制停止,因爲服務將在稍後重新啓動。 (基本上,如果設備內存嚴重不足,系統無法保持所有後臺服務運行一段時間,則這種情況完全相同也是正常情況。)

因爲您看到了這一點,我們實際上在正常操作情況下:

05-27 20:21:17.332: WARN/ActivityManager(97): Scheduling restart of crashed service com.myApp.android/.myAppWidget$UpdateService in 5000ms 

也就是說,您的進程在後臺被殺害。好的,這很好,很正常,我們將重新安排您的服務重新啓動。這就是爲什麼服務仍然保留在運行服務UI中,因爲它仍然啓動,它現在只是不會有進程運行。

在這種情況下,是的,你的onDestroy()不會被調用,因爲整個服務消失了。這又是正常的。

所以從日誌中我並沒有看到有什麼錯誤與發生了什麼事情(除了某些應用程序可能導致它發生的事情比你平常經歷的更頻繁)。你的應用程序肯定需要處理這種情況,而不是崩潰。 :)

+0

這是一個非常棒的信息,它幫助我處理了intentservice持續運行且小部件不會更新的罕見實例。 – Aakash 2011-06-28 17:19:08