[英]Date and time change listener in Android?
在我的应用程序中,有一个警报服务,我发现如果用户将其日期或时间更改为过去的时间。 我的警报不会在我预期的时间触发。
所以,我可能不得不再次重置所有警报。 android中是否有日期和时间更改侦听器?
创建一个意图过滤器:
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);
}
如果您想在应用未运行时收听时间变化,我会在清单中注册:
<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
显式注册接收器。
同样,这只是对已接受答案的补充。
为了检测日期的变化,您需要注册这些操作:
这是我写的一个解决方案,所以你所要做的就是扩展类,并在 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)
}
}
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;
}
}
在 Manifest 中注册 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
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.