Событие изменения даты системы Android

Я знаю, что этот вопрос задавался много раз, но я не могу найти правильное направление. Я зарегистрировал BroadcastReceiver, который я хочу активировать, когда Android System Date изменяется автоматически, но не срабатывает. Я использовал следующие подходы:

1

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_TIME_CHANGED);
registerReceiver(new DateTimeChangeReceiver (), intentFilter);

2->AndroidManifest.xml

<receiver android:name=".DateTimeChangeReceiver ">
<intent_filter>
    <action android:name="android.intent.action.DATE_CHANGED"/>
</intent_filter>
</receiver>

DateTimeChangeReceiver

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class DateTimeChangeReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub
        Toast.makeText(context, "Date changed", Toast.LENGTH_SHORT).show();
    }

}

В обоих случаях приемник не срабатывает. Он показывает уведомление только тогда, когда время устанавливается вручную. Может ли кто-нибудь указать мне, что мне не хватает?

Заранее спасибо.


person Mustansar Saeed    schedule 29.05.2014    source источник


Ответы (2)


Есть трансляции этих событий. Документы ACTION_TIME_CHANGED и ACTION_DATE_CHANGED ACTION на http://developer.android.com/reference/android/content/Intent.html#ACTION_DATE_CHANGED

Потенциальная ошибка и некоторые сведения о реализации доступны на странице http://code.google.com/p/android/issues/detail?id=2880

person Ramki Anba    schedule 29.05.2014

Я сделал хороший способ обнаружить и обновить пользовательский интерфейс, когда это необходимо, когда дата изменилась. Он основан на широковещательном приемнике, который должен быть зарегистрирован в методе onStart и не зарегистрирован в методе onStop (отмена регистрации выполняется автоматически в моем коде).

build.gradle

implementation 'com.jakewharton.threetenabp:threetenabp:1.0.5'

LocalDateEx.kt

object LocalDateEx {
    /**an alternative of LocalDate.now(), as it requires initialization using AndroidThreeTen.init(context), which takes a bit time (loads a file)*/
    @JvmStatic
    fun getNow(): LocalDate = Calendar.getInstance().toLocalDate()

}

fun Calendar.toLocalDate(): LocalDate = LocalDate.of(get(Calendar.YEAR), get(Calendar.MONTH) + 1, get(Calendar.DAY_OF_MONTH))

DateChangedBroadcastReceiver.kt

abstract class DateChangedBroadcastReceiver : BroadcastReceiver() {
    private var curDate = LocalDateEx.getNow()

    /**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 = LocalDateEx.getNow()
        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 onStart method of the fragment/activity*/
    fun registerOnStart(activity: AppCompatActivity, date: LocalDate, fragment: Fragment? = null) {
        register(activity, date)
        val lifecycle = fragment?.lifecycle ?: activity.lifecycle
        lifecycle.addObserver(object : LifecycleObserver {
            @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
            fun onStop() {
                Log.d("AppLog", "onStop, so unregistering")
                lifecycle.removeObserver(this)
                activity.unregisterReceiver(this@DateChangedBroadcastReceiver)
            }
        })
    }

    override fun onReceive(context: Context, intent: Intent) {
        val newDate = LocalDateEx.getNow()
        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)
        }
    }

}

MainActivity.kt

class MainActivity : AppCompatActivity() {
    var today = LocalDateEx.getNow()
    val receiver = object : DateChangedBroadcastReceiver() {
        override fun onDateChanged(previousDate: LocalDate, newDate: LocalDate) {
            Log.d("AppLog", "onDateChangedEvent:" + newDate + " previousDate:" + previousDate)
            if (newDate != today) {
                today = newDate
                textView.text = "date updated:" + today
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("AppLog", "onCreate")
        setContentView(R.layout.activity_main)
        textView.text = today.toString()
    }

    override fun onStart() {
        super.onStart()
        receiver.registerOnStart(this, today)
    }
}

activity_main.xml

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:layout_gravity="center"/>

</FrameLayout>

В качестве альтернативы вышеизложенному, используя только класс календаря Android, без необходимости использовать другую библиотеку:

fun Calendar.equalInDateAlone(cal: Calendar): Boolean =
        get(Calendar.YEAR) == cal.get(Calendar.YEAR) && get(Calendar.MONTH) == cal.get(Calendar.MONTH) && get(Calendar.DAY_OF_MONTH) == cal.get(Calendar.DAY_OF_MONTH)

fun Calendar.resetTimeFields(): Calendar {
    set(Calendar.HOUR_OF_DAY, 0)
    set(Calendar.SECOND, 0)
    set(Calendar.MINUTE, 0)
    set(Calendar.MILLISECOND, 0)
    return this
}

abstract class DateChangedBroadcastReceiver : BroadcastReceiver() {
    private var curDate = Calendar.getInstance().resetTimeFields()

    /**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)

    @Suppress("MemberVisibilityCanBePrivate")
    fun register(context: Context, date: Calendar) {
        curDate = (date.clone() as Calendar).resetTimeFields()
        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().resetTimeFields()
        if (!newDate.equalInDateAlone(curDate)) {
            curDate = newDate.clone() as Calendar
            onDateChanged(date, newDate)
        }
    }

    /**a convenient way to auto-unregister when activity/fragment has stopped. This should be called on the onStart method of the fragment/activity*/
    @Suppress("unused")
    fun registerOnStart(activity: AppCompatActivity, date: Calendar, fragment: Fragment? = null) {
        register(activity, date)
        val lifecycle = fragment?.lifecycle ?: activity.lifecycle
        lifecycle.addObserver(object : LifecycleObserver {
            @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
            fun onStop() {
//                Log.d("AppLog", "onStop, so unregistering")
                lifecycle.removeObserver(this)
                activity.unregisterReceiver(this@DateChangedBroadcastReceiver)
            }
        })
    }

    override fun onReceive(context: Context, intent: Intent) {
        val newDate = Calendar.getInstance().resetTimeFields()
//        Log.d("AppLog", "got intent:" + intent.action + " curDate:" + curDate.toSimpleDateString() + " newDate:" + newDate.toSimpleDateString())
        if (!newDate.equalInDateAlone(curDate)) {
//            Log.d("AppLog", "cur date is different, so posting event")
            val previousDate = curDate
            curDate = newDate
            onDateChanged(previousDate, newDate)
        }
    }

}
person android developer    schedule 14.02.2018