Android 使用 Service 运行后台并创建通知
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20501225/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using Service to run background and create notification
提问by user2648852
I want my app to start Service when the button is clicked and the Service should run in background to show a notification at a particular time of day. I have the following code to do this. But it shows errors which I don't understand. I am new to Android and this is my first app using Service. Any help would be appreciated. Thanks in advance.
我希望我的应用程序在单击按钮时启动服务,并且服务应该在后台运行以在一天中的特定时间显示通知。我有以下代码来做到这一点。但它显示了我不明白的错误。我是 Android 新手,这是我第一个使用服务的应用程序。任何帮助,将不胜感激。提前致谢。
AndroidManifest.xml
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.newtrial"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.newtrial.CreateNotificationActiviy"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.newtrial.ResultActivity"
android:label="@string/title_activity_result" >
</activity>
<service android:enabled="true" android:name=".UpdaterServiceManager" />
</application>
</manifest>
CreateNotificationActiviy.java
创建通知活动.java
package com.example.newtrial;
import android.os.Bundle;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class CreateNotificationActiviy extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.create_notification_activiy);
Button b=(Button)findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
startService(new Intent(CreateNotificationActiviy.this, UpdaterServiceManager.class));
}
});
}
public void createNotification(View view) {
// Prepare intent which is triggered if the
// notification is selected
Intent intent = new Intent(this, ResultActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);
// Build notification
// Actions are just fake
Notification noti = new Notification.Builder(this)
.setContentTitle("Notification Title")
.setContentText("Click here to read").setSmallIcon(R.drawable.ic_launcher)
.setContentIntent(pIntent)
.build();
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// hide the notification after its selected
noti.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, noti);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.create_notification_activiy, menu);
return true;
}
}
UpdaterServiceManager.java
更新服务管理器.java
package com.example.newtrial;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
public class UpdaterServiceManager extends Service {
private final int UPDATE_INTERVAL = 60 * 1000;
private Timer timer = new Timer();
private static final int NOTIFICATION_EX = 1;
private NotificationManager notificationManager;
CreateNotificationActiviy not;
public UpdaterServiceManager() {
not=new CreateNotificationActiviy();
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
// code to execute when the service is first created
super.onCreate();
Log.i("MyService", "Service Started.");
showNotification();
}
public void showNotification()
{
final Calendar cld = Calendar.getInstance();
int time = cld.get(Calendar.HOUR_OF_DAY);
if(time>12)
{
not.createNotification(null);
}
else
{
AlertDialog.Builder alert=new AlertDialog.Builder(this);
alert.setMessage("Not yet");
alert.setTitle("Error");
alert.setPositiveButton("OK", null);
alert.create().show();
}
}
@Override
public void onDestroy() {
if (timer != null) {
timer.cancel();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startid)
{
return START_STICKY;
}
private void stopService() {
if (timer != null) timer.cancel();
}
}
ResultActivity.java
结果活动.java
package com.example.newtrial;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
public class ResultActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
TextView tv=(TextView)findViewById(R.id.textView1);
tv.setText("After notification is clicked" );
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.result, menu);
return true;
}
}
Logcat
逻辑猫
12-10 12:14:04.286: I/Process(872): Sending signal. PID: 872 SIG: 9
12-10 12:14:11.774: I/MyService(893): Service Started.
12-10 12:14:12.094: D/AndroidRuntime(893): Shutting down VM
12-10 12:14:12.094: W/dalvikvm(893): threadid=1: thread exiting with uncaught exception (group=0x414c4700)
12-10 12:14:12.124: E/AndroidRuntime(893): FATAL EXCEPTION: main
12-10 12:14:12.124: E/AndroidRuntime(893): java.lang.RuntimeException: Unable to create service com.example.newtrial.UpdaterServiceManager: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
12-10 12:14:12.124: E/AndroidRuntime(893): at android.app.ActivityThread.handleCreateService(ActivityThread.java:2587)
12-10 12:14:12.124: E/AndroidRuntime(893): at android.app.ActivityThread.access00(ActivityThread.java:141)
12-10 12:14:12.124: E/AndroidRuntime(893): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1338)
12-10 12:14:12.124: E/AndroidRuntime(893): at android.os.Handler.dispatchMessage(Handler.java:99)
12-10 12:14:12.124: E/AndroidRuntime(893): at android.os.Looper.loop(Looper.java:137)
12-10 12:14:12.124: E/AndroidRuntime(893): at android.app.ActivityThread.main(ActivityThread.java:5103)
12-10 12:14:12.124: E/AndroidRuntime(893): at java.lang.reflect.Method.invokeNative(Native Method)
12-10 12:14:12.124: E/AndroidRuntime(893): at java.lang.reflect.Method.invoke(Method.java:525)
12-10 12:14:12.124: E/AndroidRuntime(893): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
12-10 12:14:12.124: E/AndroidRuntime(893): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
12-10 12:14:12.124: E/AndroidRuntime(893): at dalvik.system.NativeStart.main(Native Method)
12-10 12:14:12.124: E/AndroidRuntime(893): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
12-10 12:14:12.124: E/AndroidRuntime(893): at android.view.ViewRootImpl.setView(ViewRootImpl.java:563)
12-10 12:14:12.124: E/AndroidRuntime(893): at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:269)
12-10 12:14:12.124: E/AndroidRuntime(893): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
12-10 12:14:12.124: E/AndroidRuntime(893): at android.app.Dialog.show(Dialog.java:281)
12-10 12:14:12.124: E/AndroidRuntime(893): at com.example.newtrial.UpdaterServiceManager.showNotification(UpdaterServiceManager.java:65)
12-10 12:14:12.124: E/AndroidRuntime(893): at com.example.newtrial.UpdaterServiceManager.onCreate(UpdaterServiceManager.java:41)
12-10 12:14:12.124: E/AndroidRuntime(893): at android.app.ActivityThread.handleCreateService(ActivityThread.java:2577)
12-10 12:14:12.124: E/AndroidRuntime(893): ... 10 more
回答by Konstantin Loginov
The question is relatively old, but I hope this post still might be relevant for others.
这个问题相对较旧,但我希望这篇文章仍然适用于其他人。
TL;DR:use AlarmManager to schedule a task, use IntentService, see the sample code here;
TL;DR:使用AlarmManager调度任务,使用IntentService,示例代码见这里;
What this test-application(and instruction) is about:
这个测试应用程序(和说明)是关于什么的:
Simple helloworld app, which sends you notification every 2 hours. Clicking on notification - opens secondary Activity in the app; deleting notification tracks.
简单的 helloworld 应用程序,每 2 小时向您发送一次通知。点击通知 - 在应用程序中打开辅助活动;删除通知轨道。
When should you use it:
你应该什么时候使用它:
Once you need to run some task on a scheduled basis. My own case: once a day, I want to fetch new content from server, compose a notification based on the content I got and show it to user.
一旦您需要按计划运行某些任务。我自己的情况:每天一次,我想从服务器获取新内容,根据我获得的内容撰写通知并将其显示给用户。
What to do:
该怎么办:
First, let's create 2 activities: MainActivity, which starts notification-service and NotificationActivity, which will be started by clicking notification:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp"> <Button android:id="@+id/sendNotifications" android:onClick="onSendNotificationsButtonClick" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start Sending Notifications Every 2 Hours!" /> </RelativeLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void onSendNotificationsButtonClick(View view) { NotificationEventReceiver.setupAlarm(getApplicationContext()); } }
and NotificationActivity is any random activity you can come up with. NB!Don't forget to add both activities into AndroidManifest.
Then let's create
WakefulBroadcastReceiver
broadcast receiver, I called NotificationEventReceiverin code above.Here, we'll set up
AlarmManager
to firePendingIntent
every 2 hours (or with any other frequency), and specify the handled actions for this intent inonReceive()
method. In our case - wakefullystartIntentService
, which we'll specify in the later steps. ThisIntentService
would generate notifications for us.Also, this receiver would contain some helper-methods like creating PendintIntents, which we'll use later
NB1!As I'm using
WakefulBroadcastReceiver
, I need to add extra-permission into my manifest:<uses-permission android:name="android.permission.WAKE_LOCK" />
NB2!I use it wakeful version of broadcast receiver, as I want to ensure, that the device does not go back to sleep during my
IntentService
's operation. In the hello-world it's not that important (we have no long-running operation in our service, but imagine, if you have to fetch some relatively huge files from server during this operation). Read more about Device Awake here.NotificationEventReceiver.java
public class NotificationEventReceiver extends WakefulBroadcastReceiver { private static final String ACTION_START_NOTIFICATION_SERVICE = "ACTION_START_NOTIFICATION_SERVICE"; private static final String ACTION_DELETE_NOTIFICATION = "ACTION_DELETE_NOTIFICATION"; private static final int NOTIFICATIONS_INTERVAL_IN_HOURS = 2; public static void setupAlarm(Context context) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent alarmIntent = getStartPendingIntent(context); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, getTriggerAt(new Date()), NOTIFICATIONS_INTERVAL_IN_HOURS * AlarmManager.INTERVAL_HOUR, alarmIntent); } @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Intent serviceIntent = null; if (ACTION_START_NOTIFICATION_SERVICE.equals(action)) { Log.i(getClass().getSimpleName(), "onReceive from alarm, starting notification service"); serviceIntent = NotificationIntentService.createIntentStartNotificationService(context); } else if (ACTION_DELETE_NOTIFICATION.equals(action)) { Log.i(getClass().getSimpleName(), "onReceive delete notification action, starting notification service to handle delete"); serviceIntent = NotificationIntentService.createIntentDeleteNotification(context); } if (serviceIntent != null) { startWakefulService(context, serviceIntent); } } private static long getTriggerAt(Date now) { Calendar calendar = Calendar.getInstance(); calendar.setTime(now); //calendar.add(Calendar.HOUR, NOTIFICATIONS_INTERVAL_IN_HOURS); return calendar.getTimeInMillis(); } private static PendingIntent getStartPendingIntent(Context context) { Intent intent = new Intent(context, NotificationEventReceiver.class); intent.setAction(ACTION_START_NOTIFICATION_SERVICE); return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } public static PendingIntent getDeleteIntent(Context context) { Intent intent = new Intent(context, NotificationEventReceiver.class); intent.setAction(ACTION_DELETE_NOTIFICATION); return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } }
Now let's create an
IntentService
to actually create notifications.There, we specify
onHandleIntent()
which is responses on NotificationEventReceiver's intent we passed instartWakefulService
method.If it's Delete action - we can log it to our analytics, for example. If it's Start notification intent - then by using
NotificationCompat.Builder
we're composing new notification and showing it byNotificationManager.notify
. While composing notification, we are also setting pending intents for click and remove actions. Fairly Easy.NotificationIntentService.java
public class NotificationIntentService extends IntentService { private static final int NOTIFICATION_ID = 1; private static final String ACTION_START = "ACTION_START"; private static final String ACTION_DELETE = "ACTION_DELETE"; public NotificationIntentService() { super(NotificationIntentService.class.getSimpleName()); } public static Intent createIntentStartNotificationService(Context context) { Intent intent = new Intent(context, NotificationIntentService.class); intent.setAction(ACTION_START); return intent; } public static Intent createIntentDeleteNotification(Context context) { Intent intent = new Intent(context, NotificationIntentService.class); intent.setAction(ACTION_DELETE); return intent; } @Override protected void onHandleIntent(Intent intent) { Log.d(getClass().getSimpleName(), "onHandleIntent, started handling a notification event"); try { String action = intent.getAction(); if (ACTION_START.equals(action)) { processStartNotification(); } if (ACTION_DELETE.equals(action)) { processDeleteNotification(intent); } } finally { WakefulBroadcastReceiver.completeWakefulIntent(intent); } } private void processDeleteNotification(Intent intent) { // Log something? } private void processStartNotification() { // Do something. For example, fetch fresh data from backend to create a rich notification? final NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setContentTitle("Scheduled Notification") .setAutoCancel(true) .setColor(getResources().getColor(R.color.colorAccent)) .setContentText("This notification has been triggered by Notification Service") .setSmallIcon(R.drawable.notification_icon); PendingIntent pendingIntent = PendingIntent.getActivity(this, NOTIFICATION_ID, new Intent(this, NotificationActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); builder.setContentIntent(pendingIntent); builder.setDeleteIntent(NotificationEventReceiver.getDeleteIntent(this)); final NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE); manager.notify(NOTIFICATION_ID, builder.build()); } }
Almost done. Now I also add broadcast receiver for BOOT_COMPLETED, TIMEZONE_CHANGED, and TIME_SET events to re-setup my AlarmManager, once device has been rebooted or timezone has changed (For example, user flown from USA to Europe and you don't want notification to pop up in the middle of the night, but was sticky to the local time :-) ).
NotificationServiceStarterReceiver.java
public final class NotificationServiceStarterReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { NotificationEventReceiver.setupAlarm(context); } }
We need to also register all our services, broadcast receivers in AndroidManifest:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="klogi.com.notificationbyschedule"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".notifications.NotificationIntentService" android:enabled="true" android:exported="false" /> <receiver android:name=".broadcast_receivers.NotificationEventReceiver" /> <receiver android:name=".broadcast_receivers.NotificationServiceStarterReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.TIMEZONE_CHANGED" /> <action android:name="android.intent.action.TIME_SET" /> </intent-filter> </receiver> <activity android:name=".NotificationActivity" android:label="@string/title_activity_notification" android:theme="@style/AppTheme.NoActionBar"/> </application> </manifest>
首先,我们创建2个Activity:MainActivity,启动notification-service和NotificationActivity,点击notification就会启动:
活动_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp"> <Button android:id="@+id/sendNotifications" android:onClick="onSendNotificationsButtonClick" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start Sending Notifications Every 2 Hours!" /> </RelativeLayout>
主活动.java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void onSendNotificationsButtonClick(View view) { NotificationEventReceiver.setupAlarm(getApplicationContext()); } }
NotificationActivity 是您可以想出的任何随机活动。注意!不要忘记将这两个活动添加到 AndroidManifest 中。
然后让我们创建
WakefulBroadcastReceiver
广播接收器,我在上面的代码中调用了NotificationEventReceiver。在这里,我们将设置
AlarmManager
为PendingIntent
每 2 小时触发一次(或以任何其他频率),并在onReceive()
方法中指定此意图的处理操作。在我们的例子中 -唤醒启动IntentService
,我们将在后面的步骤中指定。这IntentService
将为我们生成通知。此外,此接收器将包含一些辅助方法,例如创建 PendintIntents,我们稍后将使用它们
注意!在使用时
WakefulBroadcastReceiver
,我需要在清单中添加额外权限:<uses-permission android:name="android.permission.WAKE_LOCK" />
注意!我使用广播接收器的唤醒版本,因为我想确保设备在我
IntentService
的操作期间不会重新进入睡眠状态。在 hello-world 中它不是那么重要(我们的服务中没有长时间运行的操作,但是想象一下,如果您必须在此操作期间从服务器获取一些相对较大的文件)。在此处阅读有关设备唤醒的更多信息。通知事件接收器.java
public class NotificationEventReceiver extends WakefulBroadcastReceiver { private static final String ACTION_START_NOTIFICATION_SERVICE = "ACTION_START_NOTIFICATION_SERVICE"; private static final String ACTION_DELETE_NOTIFICATION = "ACTION_DELETE_NOTIFICATION"; private static final int NOTIFICATIONS_INTERVAL_IN_HOURS = 2; public static void setupAlarm(Context context) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent alarmIntent = getStartPendingIntent(context); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, getTriggerAt(new Date()), NOTIFICATIONS_INTERVAL_IN_HOURS * AlarmManager.INTERVAL_HOUR, alarmIntent); } @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Intent serviceIntent = null; if (ACTION_START_NOTIFICATION_SERVICE.equals(action)) { Log.i(getClass().getSimpleName(), "onReceive from alarm, starting notification service"); serviceIntent = NotificationIntentService.createIntentStartNotificationService(context); } else if (ACTION_DELETE_NOTIFICATION.equals(action)) { Log.i(getClass().getSimpleName(), "onReceive delete notification action, starting notification service to handle delete"); serviceIntent = NotificationIntentService.createIntentDeleteNotification(context); } if (serviceIntent != null) { startWakefulService(context, serviceIntent); } } private static long getTriggerAt(Date now) { Calendar calendar = Calendar.getInstance(); calendar.setTime(now); //calendar.add(Calendar.HOUR, NOTIFICATIONS_INTERVAL_IN_HOURS); return calendar.getTimeInMillis(); } private static PendingIntent getStartPendingIntent(Context context) { Intent intent = new Intent(context, NotificationEventReceiver.class); intent.setAction(ACTION_START_NOTIFICATION_SERVICE); return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } public static PendingIntent getDeleteIntent(Context context) { Intent intent = new Intent(context, NotificationEventReceiver.class); intent.setAction(ACTION_DELETE_NOTIFICATION); return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } }
现在让我们创建一个
IntentService
来实际创建通知。在那里,我们指定
onHandleIntent()
哪些是对我们在方法中传递的NotificationEventReceiver意图的响应startWakefulService
。如果是删除操作 - 例如,我们可以将其记录到我们的分析中。如果它是开始通知意图 - 那么通过使用
NotificationCompat.Builder
我们正在编写新通知并通过NotificationManager.notify
. 在编写通知时,我们还为单击和删除操作设置了待处理的意图。相当容易。通知意图服务.java
public class NotificationIntentService extends IntentService { private static final int NOTIFICATION_ID = 1; private static final String ACTION_START = "ACTION_START"; private static final String ACTION_DELETE = "ACTION_DELETE"; public NotificationIntentService() { super(NotificationIntentService.class.getSimpleName()); } public static Intent createIntentStartNotificationService(Context context) { Intent intent = new Intent(context, NotificationIntentService.class); intent.setAction(ACTION_START); return intent; } public static Intent createIntentDeleteNotification(Context context) { Intent intent = new Intent(context, NotificationIntentService.class); intent.setAction(ACTION_DELETE); return intent; } @Override protected void onHandleIntent(Intent intent) { Log.d(getClass().getSimpleName(), "onHandleIntent, started handling a notification event"); try { String action = intent.getAction(); if (ACTION_START.equals(action)) { processStartNotification(); } if (ACTION_DELETE.equals(action)) { processDeleteNotification(intent); } } finally { WakefulBroadcastReceiver.completeWakefulIntent(intent); } } private void processDeleteNotification(Intent intent) { // Log something? } private void processStartNotification() { // Do something. For example, fetch fresh data from backend to create a rich notification? final NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setContentTitle("Scheduled Notification") .setAutoCancel(true) .setColor(getResources().getColor(R.color.colorAccent)) .setContentText("This notification has been triggered by Notification Service") .setSmallIcon(R.drawable.notification_icon); PendingIntent pendingIntent = PendingIntent.getActivity(this, NOTIFICATION_ID, new Intent(this, NotificationActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); builder.setContentIntent(pendingIntent); builder.setDeleteIntent(NotificationEventReceiver.getDeleteIntent(this)); final NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE); manager.notify(NOTIFICATION_ID, builder.build()); } }
快完成了。现在,我还为 BOOT_COMPLETED、TIMEZONE_CHANGED 和 TIME_SET 事件添加广播接收器以重新设置我的 AlarmManager,一旦设备重新启动或时区已更改(例如,用户从美国飞往欧洲并且您不希望弹出通知在半夜,但对当地时间很敏感:-))。
NotificationServiceStarterReceiver.java
public final class NotificationServiceStarterReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { NotificationEventReceiver.setupAlarm(context); } }
我们还需要在 AndroidManifest 中注册我们所有的服务和广播接收器:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="klogi.com.notificationbyschedule"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".notifications.NotificationIntentService" android:enabled="true" android:exported="false" /> <receiver android:name=".broadcast_receivers.NotificationEventReceiver" /> <receiver android:name=".broadcast_receivers.NotificationServiceStarterReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.TIMEZONE_CHANGED" /> <action android:name="android.intent.action.TIME_SET" /> </intent-filter> </receiver> <activity android:name=".NotificationActivity" android:label="@string/title_activity_notification" android:theme="@style/AppTheme.NoActionBar"/> </application> </manifest>
That's it!
就是这样!
The source code for this project you can find here. I hope, you will find this post helpful.
您可以在此处找到此项目的源代码。我希望,你会发现这篇文章很有帮助。
回答by Jawad Zeb
Your error is in UpdaterServiceManager in onCreate and showNotification method.
您的错误出现在 onCreate 和 showNotification 方法中的 UpdaterServiceManager 中。
You are trying to show notification
from Service using Activity Context
. Whereas Every Service has its own Context,
just use the that. You don't need to pass a Service an Activity's Context.
I don't see why you need a specific Activity's Context to show Notification.
您正在尝试显示notification
从Service using Activity Context
。而 Every Service has its own Context,
只是使用那个。你不需要pass a Service an Activity's Context.
我不明白你为什么需要一个特定的Activity's Context to show Notification.
Put your createNotification method in UpdateServiceManager.class. And remove CreateNotificationActivitynot from Service.
将您的createNotification 方法放在 UpdateServiceManager.class 中。并从服务中删除 CreateNotificationActivity。
You cannot display an application window/dialog through a Context that is not an Activity. Try passing a valid activity reference
您不能通过不是活动的上下文显示应用程序窗口/对话框。尝试传递有效的活动参考