我正在尝试使用后台服务,以便每30分钟检查一次应用程序上的新内容,并在有任何新内容时通知用户。问题是该服务似乎根本不是它的起点。我不完全确定我的错误。
我已按照此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();
}
}
永远不会触发在 BootRecevier 和 NotificationService 中使用断点调试应用。也许我误解了后台服务的工作方式。
更新
我发现这个article关于为什么没有调用BroadcastRecevier。其中一个要点是 PendingIntent requestCode missing
我已按如下方式更新了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更改为'unique'requestCode
54321以某种方式开始触发服务。问题是,当应用程序关闭时,该服务不会继续工作......不确定这是完全不同的事情。
更新2
我已更新 NotificationService 中的doInBackground
方法,使用此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 :(得分:0)
您需要声明在清单中接收意图的权限。
的AndroidManifest.xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
http://developer.android.com/reference/android/Manifest.permission.html#RECEIVE_BOOT_COMPLETED
在用户至少启动一次应用程序后,您才会收到设备启动的通知。
答案 1 :(得分:-1)
我最近遇到了同样的问题,我使用的是5.1.1安卓智能手机。我解决此问题的方法是在调用setSmallIcon()时使用ic_launcher in mipmap
替换ic_launcher in drawable
。
然而,由于确切的原因,我猜它与mipmap和drawable之间的区别有关。