ボタンがクリックされたときにアプリがサービスを開始し、サービスがバックグラウンドで実行されて特定の時刻に通知が表示されるようにします。これを行うには、次のコードがあります。しかし、それは私が理解できないエラーを示しています。私はAndroidが初めてで、これがサービスを使用する最初のアプリです。任意の助けをいただければ幸いです。前もって感謝します。
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
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
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
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.access$1600(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
質問は比較的古いですが、この投稿が他の人にも関連することを願っています。
TL; DR:AlarmManagerを使用してタスクをスケジュールし、IntentServiceを使用します。サンプルコードを参照してください here ;
2時間ごとに通知を送信するシンプルなhelloworldアプリ。通知をクリックすると、アプリでセカンダリアクティビティが開きます。通知トラックを削除します。
スケジュールに基づいていくつかのタスクを実行する必要がある場合。私の場合:1日に1回、サーバーから新しいコンテンツを取得し、取得したコンテンツに基づいて通知を作成し、ユーザーに表示したい。
最初に、notification-serviceを開始するMainActivityと、notificationをクリックして開始されるNotificationActivityの2つのアクティビティを作成します。
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());
}
}
notificationActivityは、思いつくランダムなアクティビティです。 NB!両方のアクティビティをAndroidManifestに追加することを忘れないでください。
次に、 WakefulBroadcastReceiver
ブロードキャストレシーバーを作成しましょう。上記のコードでNotificationEventReceiverを呼び出しました。
ここでは、AlarmManager
を2時間ごとに(または他の頻度で)起動するようにPendingIntent
を設定し、onReceive()
メソッドでこのインテントの処理アクションを指定します。この例では-wakefullyIntentService
を開始します。これは後の手順で指定します。このIntentService
は、通知を生成します。
また、このレシーバーには、後で使用するPendintIntentsの作成などのヘルパーメソッドが含まれます。
NB1!WakefulBroadcastReceiver
を使用しているため、追加の許可をマニフェストに追加する必要があります:<uses-permission Android:name="Android.permission.WAKE_LOCK" />
NB2!確実にしたいので、IntentService
の操作中にデバイスがスリープ状態に戻らないように、ウェイクフルバージョンのブロードキャストレシーバーを使用します。ハローワールドでは、それはそれほど重要ではありません(このサービスで長時間実行される操作はありませんが、この操作中にサーバーから比較的大きなファイルを取得する必要がある場合を想像してください)。 Device Awake こちら の詳細をご覧ください。
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);
}
}
それでは、IntentService
を作成して、実際に通知を作成しましょう。
そこで、startWakefulService
メソッドで渡したNotificationEventReceiverの意図に対する応答であるonHandleIntent()
を指定します。
削除アクションの場合-たとえば、分析に記録できます。開始通知インテントの場合-NotificationCompat.Builder
を使用して、新しい通知を作成し、NotificationManager.notify
で表示します。通知の作成中に、クリックおよび削除アクションの保留インテントも設定しています。かなり簡単。
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());
}
}
ほぼ完了しました。デバイスの再起動後またはタイムゾーンの変更後(たとえば、ユーザーがアメリカからヨーロッパに飛んでいて、通知を表示したくない場合)、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>
このプロジェクトのソースコードは here です。この投稿がお役に立てば幸いです。
エラーはonCreateおよびshowNotificationメソッドのUpdaterServiceManagerにあります。
Service using Activity Context
からnotification
を表示しようとしています。 Every Service has its own Context,
はそれを使用します。特定のpass a Service an Activity's Context.
が必要な理由がわからないActivity's Context to show Notification.
は必要ありません
pdateServiceManager.classのcreateNotificationメソッドを入力します。 CreateNotificationActivityを削除サービスからではありません。
アクティビティではないコンテキストを介してアプリケーションウィンドウ/ダイアログを表示することはできません。有効なアクティビティ参照を渡してみてください