繁体   English   中英

Android 中的日期和时间更改侦听器?

[英]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>

如果这样做,请不要在代码中使用registerReceiverunregisterReceiver显式注册接收器。

同样,这只是对已接受答案的补充。

为了检测日期的变化,您需要注册这些操作:

这是我写的一个解决方案,所以你所要做的就是扩展类,并在 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM