gpt4 book ai didi

android - 每天同一时间通知

转载 作者:行者123 更新时间:2023-11-29 17:45:51 26 4
gpt4 key购买 nike

我想要什么

我想要每天同一时间收到通知。
我已经阅读了一些帖子和教程/示例,但它无法正常工作。

版本 1

错误:Android 进程/服务在重新/启动后每 ~3 分钟终止一次

11-07 07:33:05.725  4611  6121 I ActivityManager: Process at.htl3r.appmosphere (pid 5238) has died.
11-07 07:33:05.725 4611 6121 W ActivityManager: Scheduling restart of crashed service at.htl3r.appmosphere/.notify.NotifyService in 14648ms
11-07 07:33:20.400 4611 4632 I ActivityManager: Start proc at.htl3r.appmosphere for service at.htl3r.appmosphere/.notify.NotifyService: pid=5463 uid=10096 gids={50096}

---

11-07 07:33:41.580 4611 4623 I ActivityManager: Process at.htl3r.appmosphere (pid 5463) has died.
11-07 07:33:41.580 4611 4623 W ActivityManager: Scheduling restart of crashed service at.htl3r.appmosphere/.notify.NotifyService in 73293ms
11-07 07:33:44.310 4611 5385 F ProcessStats: Starting service ServiceState{43760cf0 at.htl3r.appmosphere.notify.NotifyService pkg=at.htl3r.appmosphere proc=43760cf0} without owner

这是两种方式(最后一行有和没有所有者)
这个错误只出现在我的 S3 上,所以极端,在我的 N7 (2013) 上是不是好一点

每次重启后我都会收到通知。 (只是一个想法:而且如果我删除它,发生崩溃的可能性会更高。)

每3分钟收到一个通知有点烦人^-^

代码

version 1 - with service

更新 1

Larry Schiefer 告诉的那样更新了代码
new full log

更新 2

通知管理器
请参阅下面的最新版本
version from this update

通知接收者

public class NotifyReceiver extends BroadcastReceiver {
private static final String TAG = "NotifyReceiver";

public static final int ID_NEWHINTAVAILABLE = 1;

@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive");
SharedPreferences spref = PreferenceManager.getDefaultSharedPreferences(context);

NotificationManager mNM = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent i = new Intent(context.getApplicationContext(), MainActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(context, 0, i, 0);

Notification.Builder mNotifyBuilder = new Notification.Builder(context);

mNotifyBuilder.setSmallIcon(R.drawable.ic_stat_name);
mNotifyBuilder.setContentTitle(context.getString(R.string.app_name));
mNotifyBuilder.setContentText(context.getString(R.string.notification_contenttext));
mNotifyBuilder.setContentIntent(pIntent);

mNotifyBuilder.setAutoCancel(true);

// has to have an icon - now the app icon
// auto cancel after click: in main use cancel(int id);
// mNotifyBuilder.addAction(R.drawable.ic_stat_name, getString(R.string.notification_action), pIntent);

// mNotifyBuilder.setTicker(getString(R.string.app_name));
// mNotifyBuilder.setTicker(getString(R.string.app_name)+" "+getString(R.string.notification_contenttext));

// mNotifyBuilder.setWhen(System.currentTimeMillis());

// mNotifyBuilder.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS);
// http://stackoverflow.com/questions/2724871/how-to-bring-up-list-of-available-notification-sounds-on-android
String sound = spref.getString(SettingsFragment.pref_notify_sound, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION).toString());
mNotifyBuilder.setSound(Uri.parse(sound));

if (spref.getBoolean(SettingsFragment.pref_notify_vibrate, true)) {
// mNotifyBuilder.setVibrate(new long[] { 0, 1000 });
mNotifyBuilder.setDefaults(Notification.DEFAULT_VIBRATE);
}
if (spref.getBoolean(SettingsFragment.pref_notify_light, true)) {
mNotifyBuilder.setLights(Color.GREEN, 3000, 3000);
}

Notification mNotify = mNotifyBuilder.build();

mNM.notify(ID_NEWHINTAVAILABLE, mNotify);

NotifyManager.startAlarm(context, true);
// wenn aktiviert: ausgeführt & neu gestartet
// bei Deaktiviertung: abgebrochen - demnach kein Neustart
}
}

更新 3

自动启动工作..
但现在,它也死了这段代码没有任何改变;只有上面的代码

<receiver android:name="at.htl3r.appmosphere.notify.Autostart" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>

自动启动.java

public class Autostart extends BroadcastReceiver {
private static final String TAG = "autostart";

@Override
public void onReceive(Context context, Intent intent) {
if (NotifyManager.isNotificationEnabled(context)) {
NotifyManager.startAlarm(context);
Log.i(TAG, "started");
}
}
}

分类目录
s3 - full
n7

12-14 23:15:19.227  1452  1679 I ActivityManager: Start proc at.htl3r.appmosphere for broadcast at.htl3r.appmosphere/.notify.Autostart: pid=5837 uid=10391 gids={50391, 3003}
12-14 23:15:42.300 1452 4109 I ActivityManager: Killing 5837:at.htl3r.appmosphere/u0a391 (adj 15): empty #17
12-15 06:43:47.501 18799 18819 D JsonParser: at.htl3r.appmosphere: publishState=6
12-15 06:43:47.501 18799 18819 D JsonParser: Skipping app 0 with state != 1: package name=at.htl3r.appmosphere: state=6

更新 4

通知管理器

public class NotifyManager {
private static final String TAG = "NotifyManager";

/**
* {@link #startAlarm(Context, boolean)}<br>
* default: restart: true
*
* @param context Context of activity
* @return alarm started: true<br>
* is running: false
*/
public static boolean startAlarm(Context context) {
return startAlarm(context, false);
}

/**
* @param context Context of activity
* @param restart start the alarm even when already running
* @return true if started | false if running and not started
*/
public static boolean startAlarm(Context context, boolean restart) {// todo restart alarm on settings change
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
SharedPreferences spref = PreferenceManager.getDefaultSharedPreferences(context);

String time = spref.getString(SettingsFragment.pref_notify_time, TimePreference.notify_default);
int hour = Integer.parseInt(time.split("\\:")[0]);
int minute = Integer.parseInt(time.split("\\:")[1]);

Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.HOUR_OF_DAY, hour);
// alternative: HOUR and AM_PM
if (calendar.getTimeInMillis() < Calendar.getInstance().getTimeInMillis()) {
calendar.add(Calendar.DAY_OF_MONTH, 1);
}

// String time = new SimpleDateFormat("hh:mm", Locale.getDefault()).format(calendar.getTime());

if (!isAlarmRunning(context) || restart) {
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), getPendingIntent(context));
Log.d(TAG, "Start Alarm at " + time);
// Toast.makeText(context, "Start Alarm at " + time, Toast.LENGTH_LONG).show();
return true;
}
Log.d(TAG, "Service already running");
return false;
}

/**
* @param context Context of activity
* @return true if running and canceled
*/
public static boolean cancelAlarm(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

if (isAlarmRunning(context)) {
alarmManager.cancel(getPendingIntent(context));
Log.d(TAG, "Cancel Alarm");
NotifyManager.isAlarmRunning(context);
// Toast.makeText(context, "Cancel Alarm from " + time, Toast.LENGTH_LONG).show();
return true;
}
Log.d(TAG, "Service already canceled");
return false;
}

/**
* @param context Context of activity
* @return if alarm is running
*/
public static boolean isAlarmRunning(Context context) {
Intent intent_service = new Intent(context, NotifyReceiver.class);
Log.d(TAG, "isAlarmRunning:" + (PendingIntent.getBroadcast(context, 0, intent_service, PendingIntent.FLAG_NO_CREATE) != null));
return (PendingIntent.getBroadcast(context, 0, intent_service, PendingIntent.FLAG_NO_CREATE) != null);
}

/**
* @param context Context of activity
* @return PendingIntent
*/
public static PendingIntent getPendingIntent(Context context) {
Intent intent = new Intent(context, NotifyReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE);

// If it exists return it
if (pi != null)
return pi;

// It doesn't exist, make it (last parameter to 0 for reusable):
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
}

/**
* @return yyMMdd
*/
public static String getCurrentTimeStamp() {
SimpleDateFormat sdfDate = new SimpleDateFormat("yyMMdd", Locale.getDefault());
Date now = new Date();
String strDate = sdfDate.format(now);
return strDate;
}

/**
* @param context Context of the activity
* @return if notification is enabled or not
*/
public static boolean isNotificationEnabled(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SettingsFragment.pref_notify, true);
}
}

最佳答案

A点:服务代码缺少关键组件

在上面的代码中,服务有一个onCreateonDestroy,它们会在服务创建和销毁时触发。然而,如果一个服务被触发并且它已经在运行,那么它就不会通过onCreate。但是,它将通过 onstartCommand(onStart pre android 2.0)。您的代码的实际结构应该是:

onCreate() {
// Stuff you only do when this class is instantiated the first time
// and don't need to do if it is called (started in android terminology)
// thereafter
}

// The next two are >=2.0 and then <2.0
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startHandleIntent(intent);
return START_STICKY; // If you want the service to hang around
}

@Override
public void onStart(Intent intent, int startId) {
startHandleIntent(intent);
}

void startHandleIntent(Intent intent) {
// Do things that shiould happen every time here
// eg. in your case, the notification
}

B 点:这并不是真正设计服务的目的

您不能长期依赖一项服务。不活跃的服务通常会被删除,以便为其他事情腾出空间。考虑到该服务做的很少,使用 BroadcastReceiver 可能会更好,它是专门为偶尔需要触发但实际上并不需要存在的事物而设计的。所以:

  1. 使用 BroadcastRecevier 捕捉触发器并发出通知。像这样:

    class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
    // Issue the notidfication
    <...>

    // Reissue a request for a future alarm call here if needed
    <...>
    }
    }

    请记住在 list 中将其设置为接收广播:

    <application>
    ... other stuff ...
    <receiver android:name=".MyBroadcastReceiver" android:enabled="true">
    <intent-filter>
    <action android:name="com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION"/>
    </intent-filter>
    </receiver>
    </application>
  2. 要触发它,您需要一个会触发广播的 Intent :

    Intent intent = new Intent("com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION");
    context.sendBroadcast(intent);

    如果您将其设置为稍后通过 PendingIntent 调用(如果您想要可重用的 PendingIntent 用于重复发生的事件,请将最终标志更改为零):

    Intent intent = new Intent("com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION");
    PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT)

    如果稍后您希望更改或取消某些操作,或者如果您只是想知道从系统的角度来看是否存在 Pending Intent:

    Intent intent = new Intent("com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION");
    PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE);
    if (pi != null) {
    // It exists. If you want then to cancel the alarm that triggers it:
    alarmManager.cancel(pi);
    }
    else {
    // It doesn't exist. If you need to create a reusable PendingIntent:
    PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
    }

    就我个人而言,我会使用这种方法而不是 initializePendingIntent,即:

    public static PendingIntent getPendingIntent() {
    Intent intent = new Intent("com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION");
    PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE);

    // If it exists return it
    if (pi != null) return pi;

    // It doesn't exist, make it (last parameter to 0 for reusable):
    return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
    }
  3. 使用 SharedPreferences(正如您已经在做的那样)跟踪正在发生的事情(警报时间)

我的偏好是只创建一个带有一次性 Intent 的一次性警报,以便下一个警报何时响起。如果它发生变化,请删除此警报并创建一个新警报。当它触发时,创建一个新的。通过这种方式,您可以最大限度地减少必须长时间存活的事物的数量。

关于android - 每天同一时间通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26808230/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com