Правильное уведомление AsyncTaskLoader об изменениях данных из фонового потока
Я хочу реализовать AsyncTaskLoader
для моего пользовательского источника данных:
public class DataSource {
public interface DataSourceObserver {
void onDataChanged();
}
...
}
DataSource
будет вести список зарегистрированных наблюдателей и уведомлять их об изменениях. CustomLoader
будет реализовывать DataSourceObserver
, Вопрос в том, как правильно уведомить CustomLoader
поскольку Loader.onContentChanged()
должен быть вызван из потока пользовательского интерфейса, но в моем случае DataSource
операции (и призывы к DataSourceObserver.onDataChanged()
) будет сделано из фоновых тем.
Обновленный с идеей от совета Селвина:
public class CustomLoader extends AsyncTaskLoader<...> implements DataSource.DataSourceObserver {
private final Handler observerHandler;
public CustomLoader(Context context) {
super(context);
observerHandler = new Handler()
}
@Override
public void onDataChanged() {
observerHandler.post(new Runnable() {
@Override
public void run() {
onContentChanged();
}
});
}
}
1 ответ
Я имел большой успех при использовании местных трансляций в случае, который очень похож на ваш. Метод включает в себя AsyncTaskLoader
реализация, которая зарегистрирует BroadcastReceiver
прослушивание определенной строки, которая описывает, что изменилось. это BroadcastReceiver
держит ссылку на Loader
и звонки onContentChanged
, Когда данные нуждаются в обновлении, выполните локальную трансляцию с вышеупомянутой строкой и BroadcastReceiver
услышит это и вызовет нагрузку. Вот пример кода, он может не работать идеально, если вы уроните его, я обобщил некоторые имена классов, но, надеюсь, вы поймете идею:
Приемник вещания, который будет использоваться в вашей загрузке:
public class LoaderBroadcastReceiver extends BroadcastReceiver
{
private Loader loader;
public LoaderBroadcastReceiver(Loader loader)
{
this.loader = loader;
}
@Override
public void onReceive(Context context, Intent intent)
{
loader.onContentChanged();
}
}
Реализация загрузчика регистрирует получателя в onStartLoading()
private LoaderBroadcastReceiver loaderBroadcastReceiver = null;
@Override
protected void onStartLoading()
{
//... some code here
if(loaderBroadcastReceiver == null)
{
loaderBroadcastReceiver = new LoaderBroadcastReceiver(this);
LocalBroadcastManager.getInstance(getContext()).registerReceiver(loaderBroadcastReceiver, new IntentFilter("NEWDATASTRING"));
}
//... some more code here
}
Наконец, вот как onDataChanged в DataSource сделает трансляцию. Для отправки трансляции понадобится контекст. Поскольку это может быть вызвано из произвольного потока, я бы использовал ваш ApplicationContext, так как контекст из действия может вызвать проблемы, если действие уничтожено.
public class DataSource
{
public interface DataSourceObserver
{
void onDataChanged(Context applicationContext)
{
LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("NEWDATASTRING"));
}
}
...
}
Возможно, вы захотите немного поиграть с ним, чтобы увидеть, как он работает для вас. Вы можете использовать разные строки, чтобы различать разные данные, которые нужно загрузить. Вы также захотите отменить регистрацию приемника в какой-то момент, возможно, в onReset()
, Дайте мне знать, если что-либо из этого неясно в комментариях, я постараюсь уточнить.