2014-10-07 144 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