2014-10-07 140 views
1

我在嘗試使用後臺服務,以便每30分鐘檢查應用程序上的新內容,並在有新內容時通知用戶有通知。問題在於該服務似乎並不是根本就開始的。我不完全確定我有什麼錯。後臺服務未啓動android

我已按照此article執行通知服務和此問題以及 - Trying to start a service on boot on Android

AndroidManifest.xml中

<uses-permission android:name="android.permission.INTERNET" /> 
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> 
<uses-permission android:name="android.permission.WAKE_LOCK" /> 
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 

<application 
    android:allowBackup="true" 
    android:icon="@drawable/ic_launcher" 
    android:label="@string/app_name" 
    android:theme="@style/AppTheme" > 
    <activity 
     android:name="com.____.MainActivity" 
     android:label="@string/app_name" > 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN" /> 

      <category android:name="android.intent.category.LAUNCHER" /> 
     </intent-filter> 
    </activity> 

    <receiver android:name="com.____.BootReceiver"> 
     <intent-filter> 
      <action android:name="android.intent.action.BOOT_COMPLETED" /> 
     </intent-filter> 
    </receiver> 
    <service android:name="com.____.NotificationService"/> 
</application> 

BootReceiver應該啓動服務

public class BootReceiver extends BroadcastReceiver { 

    @Override 
    public void onReceive(Context context, Intent intent) { 
     Intent startServiceIntent = new Intent(context, NotificationService.class); 
     context.startService(startServiceIntent); 
    } 
} 

服務NotificationService現在被設置爲顯示一個簡單的通知

public class NotificationService extends Service { 

    private WakeLock mWakeLock; 

    /** 
    * Simply return null, since our Service will not be communicating with 
    * any other components. It just does its work silently. 
    */ 
    @Override 
    public IBinder onBind(Intent intent) { 
     return null; 
    } 

    /** 
    * This is where we initialize. We call this when onStart/onStartCommand is 
    * called by the system. We won't do anything with the intent here, and you 
    * probably won't, either. 
    */ 
    private void handleIntent(Intent intent) { 
     // obtain the wake lock 
     PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE); 
     mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My App"); 
     mWakeLock.acquire(); 

     // check the global background data setting 
     ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); 
     if (cm.getActiveNetworkInfo() == null) { 
      stopSelf(); 
      return; 
     } 

     // do the actual work, in a separate thread 
     new PollTask().execute(); 
    } 

    private class PollTask extends AsyncTask<Void, Void, Void> { 
     /** 
     * This is where YOU do YOUR work. There's nothing for me to write here 
     * you have to fill this in. Make your HTTP request(s) or whatever it is 
     * you have to do to get your updates in here, because this is run in a 
     * separate thread 
     */ 
     @SuppressLint("NewApi") @Override 
     protected Void doInBackground(Void... params) { 
      // do stuff! 

      // get last added date time of offer 
      // every 60 minutes check for new offers 

      Notification notification = new Notification.Builder(getApplicationContext()) 
       .setContentText("New Content Available") 
       .setSmallIcon(R.drawable.ic_launcher) 
       .setWhen(0) 
       .build(); 

      return null; 
     } 

     /** 
     * In here you should interpret whatever you fetched in doInBackground 
     * and push any notifications you need to the status bar, using the 
     * NotificationManager. I will not cover this here, go check the docs on 
     * NotificationManager. 
     * 
     * What you HAVE to do is call stopSelf() after you've pushed your 
     * notification(s). This will: 
     * 1) Kill the service so it doesn't waste precious resources 
     * 2) Call onDestroy() which will release the wake lock, so the device 
     * can go to sleep again and save precious battery. 
     */ 
     @Override 
     protected void onPostExecute(Void result) { 
      // handle your data 
      stopSelf(); 
     } 
    } 

    /** 
    * This is deprecated, but you have to implement it if you're planning on 
    * supporting devices with an API level lower than 5 (Android 2.0). 
    */ 
    @Override 
    public void onStart(Intent intent, int startId) { 
     handleIntent(intent); 
    } 

    /** 
    * This is called on 2.0+ (API level 5 or higher). Returning 
    * START_NOT_STICKY tells the system to not restart the service if it is 
    * killed because of poor resource (memory/cpu) conditions. 
    */ 
    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     handleIntent(intent); 
     return START_NOT_STICKY; 
    } 

    /** 
    * In onDestroy() we release our wake lock. This ensures that whenever the 
    * Service stops (killed for resources, stopSelf() called, etc.), the wake 
    * lock will be released. 
    */ 
    public void onDestroy() { 
     super.onDestroy(); 
     mWakeLock.release(); 
    } 
} 

使用斷點調試應用程序BootRecevierNotificationService從不觸發。也許我誤解了後臺服務的工作方式。

UPDATE

,我發現這個article關於爲什麼BroadcastRecevier不會被調用。其中提到的一點是的PendingIntent requestCode失蹤

我已經更新了BootRecevier如下來測試服務......叫每1分鐘:

@Override 
public void onReceive(Context context, Intent intent) { 
    int minutes = 1; 
    AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 
    Intent i = new Intent(context, NotificationService.class); 
    PendingIntent pi = PendingIntent.getService(context, 54321, i, 0); 
    am.cancel(pi); 

    if (minutes > 0) { 
     am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 
      SystemClock.elapsedRealtime() + minutes*60*1000, 
      minutes*60*1000, pi); 
    } 
} 

改變0到一個「獨一無二」 requestCode 54321以某種方式開始觸發服務。問題在於,當應用程序關閉時服務不會繼續工作......不確定這是完全不同的事情。

UPDATE 2

我已經更新在NotificationServicedoInBackground方法,使用這種example顯示通知:

@SuppressLint("NewApi") @Override 
protected Void doInBackground(Void... params) { 

    Context mContext = getApplicationContext(); 

    // invoke default notification service 
    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mContext); 

    mBuilder.setContentTitle("[Notification Title]"); 
    mBuilder.setContentText("[Notification Text]"); 
    mBuilder.setTicker(mContext.getString(R.string.app_name)); 
    mBuilder.setSmallIcon(R.drawable.ic_launcher); 

    Intent resultIntent = new Intent(mContext, MainActivity.class); 

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(mContext); 
    stackBuilder.addParentStack(MainActivity.class); 

    stackBuilder.addNextIntent(resultIntent); 
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_ONE_SHOT); 

    mBuilder.setContentIntent(resultPendingIntent); 

    NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 
    mNotificationManager.notify(1, mBuilder.build()); 

    return null; 
} 

我測試它在仿真器上和背景即使應用程序關閉,服務也能正常工作。但是,在實際設備上測試應用程序不會顯示任何通知。

+0

如果您希望立即啓動服務,您可以嘗試手動啓動服務。 (當操作系統殺死它時,我有一個粘性的消息服務,需要一些時間來重新啓動,但如果我需要立即啓動,我運行此代碼) context.startService(new Intent(context,YourService.class)); – Warwicky 2014-10-07 21:28:58

回答

0

您需要聲明清單中接收意圖的權限。

AndroidManifest。XML

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

http://developer.android.com/reference/android/Manifest.permission.html#RECEIVE_BOOT_COMPLETED

您將只能接收設備後用戶啓動的通知,已經開始您的應用程序至少一次。

+0

是的,那已經存在了......我會更新我的問題以防萬一 – 2014-10-07 21:33:32

+1

您必須在' Blundell 2014-10-07 21:34:54

+0

你說得對,對不起:) – 2014-10-07 21:40:11

-1

我碰巧在最近有同樣的問題,我正在使用5.1.1 android智能手機。我解決這個問題的方法是在調用setSmallIcon()時使用ic_launcher in mipmap來替換ic_launcher in drawable

但是,出於確切原因,我想這與mipmap和drawable之間的區別有關。

Ref:mipmap vs drawable folders