在我的应用程序中,有一个警报服务,我发现如果用户将日期或时间更改为过去的时间。我预期的时候不会触发我的闹钟。
因此,我可能需要重新设置所有警报。 android中是否有日期和时间更改监听器?
答案 0 :(得分:81)
创建一个意图过滤器:
static {
s_intentFilter = new IntentFilter();
s_intentFilter.addAction(Intent.ACTION_TIME_TICK);
s_intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
s_intentFilter.addAction(Intent.ACTION_TIME_CHANGED);
}
和广播接收器:
private final BroadcastReceiver m_timeChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_TIME_CHANGED) ||
action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
doWorkSon();
}
}
};
注册接收者:
public void onCreate() {
super.onCreate();
registerReceiver(m_timeChangedReceiver, s_intentFilter);
}
修改强>
取消注册:
public void onDestroy() {
super.onDestroy();
unregisterReceiver(m_timeChangedReceiver);
}
答案 1 :(得分:19)
如果您想在应用未运行时收听的时间更改,我会在清单中注册:
<receiver android:name="com.your.pacakge.TimeChangeBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.TIME_SET"/>
<action android:name="android.intent.action.TIMEZONE_CHANGED"/>
</intent-filter>
</receiver>
如果您这样做,请不要在代码中使用registerReceiver
和unregisterReceiver
明确注册接收者。
同样,这只是对已接受答案的补充。
答案 2 :(得分:0)
为了检测日期的变化,您需要注册以下操作:
这是我写的一种解决方案,因此您要做的就是扩展该类,并在Activity / Fragment上注册和注销它:
abstract class DateChangedBroadcastReceiver : BroadcastReceiver() {
private var curDate = LocalDate.now()
/**called when the receiver detected the date has changed. You should still check it yourself, because you might already be synced with the new date*/
abstract fun onDateChanged(previousDate: LocalDate, newDate: LocalDate)
@Suppress("MemberVisibilityCanBePrivate")
fun register(context: Context, date: LocalDate) {
curDate = date
val filter = IntentFilter()
filter.addAction(Intent.ACTION_TIME_CHANGED)
filter.addAction(Intent.ACTION_DATE_CHANGED)
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED)
context.registerReceiver(this, filter)
val newDate = LocalDate.now()
if (newDate != curDate) {
curDate = newDate
onDateChanged(date, newDate)
}
}
/**a convenient way to auto-unregister when activity/fragment has stopped. This should be called on the onResume method of the fragment/activity*/
fun registerOnResume(activity: AppCompatActivity, date: LocalDate, fragment: androidx.fragment.app.Fragment? = null) {
register(activity, date)
val lifecycle = fragment?.lifecycle ?: activity.lifecycle
lifecycle.addObserver(object : LifecycleObserver {
@Suppress("unused")
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
// Log.d("AppLog", "onPause, so unregistering")
lifecycle.removeObserver(this)
activity.unregisterReceiver(this@DateChangedBroadcastReceiver)
}
})
}
override fun onReceive(context: Context, intent: Intent) {
val newDate = LocalDate.now()
// Log.d("AppLog", "got intent:" + intent.action + " curDate:" + curDate + " newDate:" + newDate)
if (newDate != curDate) {
// Log.d("AppLog", "cur date is different, so posting event")
val previousDate = curDate
curDate = newDate
onDateChanged(previousDate, newDate)
}
}
}
如果您不能使用LocalDate(因为它使用的是相对较新的API:26,目前在大约21%的设备上使用),则可以改用以下方法:
abstract class DateChangedBroadcastReceiver : BroadcastReceiver() {
private var curDate = Calendar.getInstance()
/**called when the receiver detected the date has changed. You should still check it yourself, because you might already be synced with the new date*/
abstract fun onDateChanged(previousDate: Calendar, newDate: Calendar)
companion object {
fun toString(cal: Calendar): String {
return "${cal.get(Calendar.YEAR)}-${cal.get(Calendar.MONTH)}-${cal.get(Calendar.DAY_OF_MONTH)}"
}
fun resetDate(date: Calendar) {
date.set(Calendar.HOUR_OF_DAY, 0)
date.set(Calendar.MINUTE, 0)
date.set(Calendar.SECOND, 0)
date.set(Calendar.MILLISECOND, 0)
}
fun areOfSameDate(date: Calendar, otherDate: Calendar) =
date.get(Calendar.DAY_OF_YEAR) == otherDate.get(Calendar.DAY_OF_YEAR) &&
date.get(Calendar.YEAR) == otherDate.get(Calendar.YEAR)
}
@Suppress("MemberVisibilityCanBePrivate")
fun register(context: Context, date: Calendar) {
curDate = date.clone() as Calendar
resetDate(curDate)
val filter = IntentFilter()
filter.addAction(Intent.ACTION_TIME_CHANGED)
filter.addAction(Intent.ACTION_DATE_CHANGED)
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED)
context.registerReceiver(this, filter)
val newDate = Calendar.getInstance()
resetDate(newDate)
if (!areOfSameDate(newDate, curDate)) {
val previousDate = curDate.clone() as Calendar
curDate = newDate
onDateChanged(previousDate, curDate)
}
}
/**a convenient way to auto-unregister when activity/fragment has stopped. This should be called on the onResume method of the fragment/activity*/
fun registerOnResume(activity: AppCompatActivity, date: Calendar, fragment: Fragment? = null) {
register(activity as Context, date)
val lifecycle = fragment?.lifecycle ?: activity.lifecycle
lifecycle.addObserver(object : LifecycleObserver {
@Suppress("unused")
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
// Log.d("AppLog", "onPause, so unregistering")
lifecycle.removeObserver(this)
activity.unregisterReceiver(this@DateChangedBroadcastReceiver)
}
})
}
override fun onReceive(context: Context, intent: Intent) {
val newDate = Calendar.getInstance()
resetDate(newDate)
// Log.d("AppLog", "got intent:${intent.action} curDate:${toString(curDate)} newDate:${toString(newDate)}")
if (!areOfSameDate(newDate, curDate)) {
// Log.d("AppLog", "cur date is different, so posting event")
val previousDate = curDate.clone() as Calendar
curDate = newDate
onDateChanged(previousDate, newDate)
}
}
}
用法示例:
class MainActivity : AppCompatActivity() {
var curDate = Calendar.getInstance()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onResume() {
super.onResume()
object : DateChangedBroadcastReceiver() {
override fun onDateChanged(previousDate: Calendar, newDate: Calendar) {
Log.d("AppLog", "MainActivity: ${DateChangedBroadcastReceiver.toString(previousDate)} -> ${DateChangedBroadcastReceiver.toString(newDate)}")
curDate = newDate.clone() as Calendar
//TODO handle date change
}
}.registerOnResume(this, curDate)
}
}
答案 3 :(得分:0)
Ben的答案的Java版本,有一个较小的修正。该修复程序是关于添加 ACTION_TIME_TICK 作为我们应该照顾广播接收者的动作之一。
public abstract class DayChangedBroadcastReceiver extends BroadcastReceiver {
private Date date = new Date();
private DateFormat dateFormat = new SimpleDateFormat("yyMMdd", Locale.getDefault());
public abstract void onDayChanged();
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Date currentDate = new Date();
if (action != null && !isSameDay(currentDate) &&
(action.equals(Intent.ACTION_TIME_CHANGED)
|| action.equals(Intent.ACTION_TIMEZONE_CHANGED)
|| action.equals(Intent.ACTION_TIME_TICK))) {
date = currentDate;
onDayChanged();
}
}
private boolean isSameDay(Date currentDate) {
return dateFormat.format(currentDate).equals(dateFormat.format(date));
}
public static IntentFilter getIntentFilter() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_TIME_TICK);
intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
intentFilter.addAction(Intent.ACTION_TIME_CHANGED);
return intentFilter;
}
}
答案 4 :(得分:0)
在清单中注册BroadcastReceiver时的另一项补充
当您当前没有活动警报时,也许您想停止收听广播,并在出现活动警报时稍后重新启用它。
val receiver = ComponentName(context, SampleBootReceiver::class.java)
context.packageManager.setComponentEnabledSetting(
receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
// or PackageManager.COMPONENT_ENABLED_STATE_DISABLED to disable it
PackageManager.DONT_KILL_APP
)
答案 5 :(得分:-1)
使用的Android默认TextClock视图
<TextClock
android:id="@+id/textClock"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:format12Hour="hh:mm:ss a"
android:gravity="center_horizontal"
android:textColor="#d41709"
android:textSize="44sp"
android:textStyle="bold" />
在此处更改日期格式
android:format12Hour="hh:mm:ss a"