2012-10-04 128 views
0

我有一個應用程序,從啓動接收器啓動一個服務,定期從手機的Sqlite數據庫表中刪除行。 BootReceiver工作正常。它實例化的服務有一個無限循環,被Thread.sleep暫停30秒(用於測試),最終它將設置爲每兩個小時左右。它確實刪除了行,但我不相信它是每30秒鐘一次,最終還會導致ANR。它的全部實施方式似乎有點粗糙。有沒有更好的方式來實現我在做什麼?如果不是我怎麼可以停止ANR,因爲我以爲服務不必是異步的,只是網絡電話等安卓服務導致ANR

import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.Intent; 

public class MyBootReceiver extends BroadcastReceiver { 

    @Override 
    public void onReceive(Context context, Intent intent) { 

    Intent myIntent = new Intent(context, SendOutstandingTransactions.class); 
    myIntent.setAction("com.carefreegroup.startatboot.MyService"); 
    context.startService(myIntent); 


    } 

} 

import org.joda.time.DateTime; 

import android.app.Service; 
import android.content.Intent; 
import android.database.Cursor; 
import android.os.IBinder; 
import android.util.Log; 

public class SendOutstandingTransactions extends Service { 

    private static final String TAG = SendOutstandingTransactions.class.getSimpleName(); 
    NfcScannerApplication nfcscannerapplication; 
    Cursor c; 

    @Override 
    public void onCreate() { 
     Log.e(TAG, "inside onCreate of SendOutstandingTransactions"); 
     nfcscannerapplication = (NfcScannerApplication)getApplication(); 
     super.onCreate(); 
    } 

    @Override 
    public void onDestroy() { 
     Log.e(TAG, "inside onDestroy of SendOutstandingTransactions"); 

     super.onDestroy(); 
    } 

    @Override 
    public void onStart(Intent intent, int startId) { 
     super.onStart(intent, startId); 
     Log.e(TAG, "inside onStart of SendOutstandingTransactions"); 

     do{ 
     DateTime now = new DateTime(); 
     //nfcscannerapplication.loginValidate.deleteTransactionsOlderThanThreeDays(now); 
     nfcscannerapplication.loginValidate.deleteTableTransactions(); 
     Log.e(TAG, "just called housekeeping method in service"); 
     try { 
      Thread.sleep(30000); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     }while(true); 




    }// end of onStart 

    @Override 
    public IBinder onBind(Intent intent) { 
     // TODO Auto-generated method stub 
     return null; 
    } 

} 

在清單

<service android:name=".SendOutstandingTransactions" > 
      <intent-filter> 
       <action android:name="com.carefreegroup.startatboot.MyService" /> 
      </intent-filter> 
     </service> 

     <receiver 
      android:name=".MyBootReceiver" 
      android:enabled="true" 
      android:exported="false" > 
      <intent-filter> 
       <action android:name="android.intent.action.BOOT_COMPLETED" /> 
      </intent-filter> 
     </receiver> 

[EDIT1] 我如何啓動服務

// get a Calendar object with current time 
      Calendar cal = Calendar.getInstance(); 
      // add 5 minutes to the calendar object 
      cal.add(Calendar.MINUTE, 1); 
      Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class); 
      intent.putExtra("alarm_message", "sending outstanding transactions"); 
      // In reality, you would want to have a static variable for the request code instead of 192837 
      PendingIntent sender = PendingIntent.getBroadcast(getApplicationContext(), 192837, intent, PendingIntent.FLAG_UPDATE_CURRENT); 

      // Get the AlarmManager service 
      AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE); 
      //am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender); 
      //86400000 = 24 hours 
      //43200000 = 12 hours 
      //3600000 = 1hr 
      //1800000 = 30 mins 
      // 600000 = 10 mins 
      //300000 = 5 mins 

      am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 300000 , sender); 

的alarmReceiver

public class AlarmReceiver extends BroadcastReceiver { 

@Override 
public void onReceive(Context context, Intent intent) { 


    try { 

    Bundle bundle = intent.getExtras(); 
    String message = bundle.getString("alarm_message"); 
    // Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); 
    Intent myIntent = new Intent(context, SendOutstandingTransactions.class); 
    myIntent.setAction("com.carefreegroup.rr3.startatboot.MyService"); 
    context.startService(myIntent); 

    } catch (Exception e) { 
    Toast.makeText(context, "There was an error somewhere, but we still received an alarm", Toast.LENGTH_SHORT).show(); 
    e.printStackTrace(); 

    } 
} 

} 

服務

public class SendOutstandingTransactions extends IntentService { 

     private static final String TAG = SendOutstandingTransactions.class.getSimpleName(); 

instance variables 

     @Override 
     public void onCreate() { 
      super.onCreate(); 


     } 





     @Override 
     protected void onHandleIntent(Intent intent) { 

    //do something 

     }//end of onHandleIntent 




     public SendOutstandingTransactions() { 
      super("SendOutstandingTransactions"); 

     } 
+0

您可能想使用[alarm](http://developer.android.com/reference/android/app/AlarmManager.html)。 – dmon

+0

是嗎? 'Thread.sleep(30000);'在系統線程上傾向於導致ANR。我看不出問題在哪裏? (你可能想要使用IntentService) – njzk2

+0

,我沒有看到while(true)!每次肯定ANR。做得好! – njzk2

回答

4

請注意,與其他應用程序對象一樣,服務在其主機進程的主要線程 中運行。這意味着,如果你的服務是 要做任何CPU密集型(如MP3播放)或阻塞(如網絡)操作,它應該產生自己的線程,在其中 這樣做的工作。關於這方面的更多信息可以在Processes和 主題中找到。 IntentService類可以作爲標準的 實現,該實現具有自己的線程,並在其中計劃要完成的工作 。

來源:http://developer.android.com/reference/android/app/Service.html

解決方案:

移動你的代碼到一個專用的線程。這可以通過使用例如AsyncTask類來完成。

+0

謝謝你一個合適和成熟的答案。是的,我以前使用過AsyncTask,但我想我最近在某處閱讀過,你不需要Async服務。顯然必須是錯的。您將在IntentService或警報之間使用哪一個。有一個比另一個有利嗎? – turtleboy

+0

intentService用於長時間的操作,如網絡連接(如asynctask,但是連續調用並且沒有掛鉤到主線程)。 AlarmManager用於常規任務。兩者都可以聯合使用(例如在預先知道的時間發送數據) – njzk2

+0

@ njzk2感謝您的回覆。那麼我剛剛實施IntentService,並已解決ANR我昨天:)我想要的是定期檢查手機的數據庫,看看是否有任何交易需要發送到Web服務。所以從一個bootreceiver我啓動了這個IntentService,我想無限期地運行。你會使服務使用AlarmManager而不是無限循環。這是最好的組合嗎? – turtleboy