Правильное уведомление 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(), Дайте мне знать, если что-либо из этого неясно в комментариях, я постараюсь уточнить.

Другие вопросы по тегам