AsyncTaskLoader простой пример. (Андроид)
Я использую загрузчик в своем приложении и на основе результата, который я получаю от запроса, который я выполняю на контактах с помощью этого загрузчика, я выполняю некоторые вычисления и сохраняю их в БД Sqlite. Я хочу, чтобы эта операция была асинхронной, однако я путаюсь между использованием асинхронной задачи, поскольку у меня много разных типов данных для возврата или я должен использовать простой обработчик или AsyncTaskLoader, я хочу, чтобы это было просто, поскольку я новичок в загрузчиках. Я попытался найти вокруг примеры AsyncTaskLoader но, похоже, ракетостроение, основной и простой функциональный пример любого из трех в контексте моего сценария был бы очень полезен.
6 ответов
Если вы хотите использовать AsyncTaskLoader, здесь хороший образец для вас.
EDIT: я решил сделать более простое решение (на основе этот РЕПО):
public abstract class AsyncTaskLoaderEx<T> extends AsyncTaskLoader<T> {
private static final AtomicInteger sCurrentUniqueId = new AtomicInteger(0);
private T mData;
public boolean hasResult = false;
public static int getNewUniqueLoaderId() {
return sCurrentUniqueId.getAndIncrement();
}
public AsyncTaskLoaderEx(final Context context) {
super(context);
onContentChanged();
}
@Override
protected void onStartLoading() {
if (takeContentChanged())
forceLoad();
//this part should be removed from support library 27.1.0 :
//else if (hasResult)
// deliverResult(mData);
}
@Override
public void deliverResult(final T data) {
mData = data;
hasResult = true;
super.deliverResult(data);
}
@Override
protected void onReset() {
super.onReset();
onStopLoading();
if (hasResult) {
onReleaseResources(mData);
mData = null;
hasResult = false;
}
}
protected void onReleaseResources(T data) {
//nothing to do.
}
public T getResult() {
return mData;
}
}
использование:
в вашей деятельности:
getSupportLoaderManager().initLoader(TASK_ID, TASK_BUNDLE, new LoaderManager.LoaderCallbacks<Bitmap>() {
@Override
public Loader<Bitmap> onCreateLoader(final int id, final Bundle args) {
return new ImageLoadingTask(MainActivity.this);
}
@Override
public void onLoadFinished(final Loader<Bitmap> loader, final Bitmap result) {
if (result == null)
return;
//TODO use result
}
@Override
public void onLoaderReset(final Loader<Bitmap> loader) {
}
});
внутренний статический класс , или обычный класс:
private static class ImageLoadingTask extends AsyncTaskLoaderEx<Bitmap> {
public ImageLoadingTask (Context context) {
super(context);
}
@Override
public Bitmap loadInBackground() {
//TODO load and return bitmap
}
}
Update: начиная с библиотеки поддержки 27.1.0, все немного изменилось (ссылка здесь):
в версии 27.1.0 onStartLoading () вызывается каждый раз, когда действие запускается. Поскольку вы вызываете deliverResult () в onStartLoading (), вы trigger onLoadFinished(). Это работает по назначению.
вы должны удалить вызов deliverResult() из onStartLoading() поскольку это не требуется (загрузчики уже доставляют результаты, вычисленные в loadInBackground () без каких-либо дополнительных работ, необходимых на вашем часть.)
я обновил код выше для этого изменения.
так как Honeycomb и библиотека совместимости v4 можно использовать AsyncTaskLoader
. Из того, что я понимаю,AsyncTaskLoader
может выжить через изменения конфигурации, такие как сальто экрана. Но используя AsyncTask
вы можете испортить изменения конфигурации.
ключевая информация: AsyncTaskLoader
является наследником Loader
. Этот класс выполняет ту же функцию, что и AsyncTask, но немного лучше, он также может быть полезен при обработке изменений конфигурации (ориентация экрана).
очень хорошая пример и объяснение приведены здесь. http://www.javacodegeeks.com/2013/01/android-loaders-versus-asynctask.html
Google имеет довольно хороший пример непосредственно в документах API. Android Design Patterns предоставляет более подробную информацию и обоснование загрузчиков.
этот учебник определенно поможет вам. http://www.javacodegeeks.com/2013/08/android-custom-loader-to-load-data-directly-from-sqlite-database.html
вот шаг за шагом учебник для реализации
AsyncTaskLoader
. или проверьте эту же статью на средний
-
реализовать
LoaderManager.LoaderCallbacks<String>
на MainActivity и создатьstatic int
чтобы однозначно идентифицировать загрузчик и Создать Строковый ключ для передачи строкового url-адреса загрузчикуpublic class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<String>{ public static final int OPERATION_SEARCH_LOADER = 22; public static final String OPERATION_QUERY_URL_EXTRA = "query"; //...}
-
переопределить
onCreateLoader
,onLoadFinished
иonLoaderReset
функции внутри В MainActivity@Override public Loader<String> onCreateLoader(int id, final Bundle args) { //Here we will initiate AsyncTaskLoader return null; } @Override public void onLoadFinished(Loader<String> loader, String operationResult) { //Think of this as AsyncTask onPostExecute method, the result from onCreateLoader will be available in operationResult variable and here you can update UI with the data fetched. Log.d("MAINACTIVITY","result : "+ operationResult); } @Override public void onLoaderReset(Loader<String> loader) { //Don't bother about it, Android Studio will override it for you }
-
внутри
onCreateLoader()
вернутьAsyncTaskLoader<String>
как анонимный внутренний класс сthis
в качестве параметра конструктора и переопределенияloadInBackground
&onStartLoading
внутри анонимной внутренний класс@Override public Loader<String> onCreateLoader(int id, final Bundle args) { return new AsyncTaskLoader<String>(this) { @Override public String loadInBackground() { //Think of this as AsyncTask doInBackground() method, here you will actually initiate Network call return null; } @Override protected void onStartLoading() { //Think of this as AsyncTask onPreExecute() method,start your progress bar,and at the end call forceLoad(); forceLoad(); } }; }
-
внутри
loadInBackground
сделать сетевой вызов с помощью HTTPUrlConnection или OKHttp или все, что вы используете.@Override public String loadInBackground() { String url = args.getString(OPERATION_QUERY_URL_EXTRA);//This is a url in string form if (url!=null&&"".equals(url)) { return null;//if url is null, return } String operationResult=""; try { operationResult = NetworkUtils.getResponseFromHttpUrl(url);//This just create a HTTPUrlConnection and return result in strings } catch (IOException e) { e.printStackTrace(); } return operationResult; }
-
внутри
onCreate
инициализировать загрузчик с OPERATION_SEARCH_LOADER как идентификатор, null для пакета, и это для контекстаgetSupportLoaderManager().initLoader(OPERATION_SEARCH_LOADER, null, this);
-
теперь вызвать этот метод, когда и где вы хотите, чтобы вызвать погрузчик
private void makeOperationSearchQuery(String url) { // Create a bundle called queryBundle Bundle queryBundle = new Bundle(); // Use putString with OPERATION_QUERY_URL_EXTRA as the key and the String value of the URL as the value queryBundle.putString(OPERATION_QUERY_URL_EXTRA,url); // Call getSupportLoaderManager and store it in a LoaderManager variable LoaderManager loaderManager = getSupportLoaderManager(); // Get our Loader by calling getLoader and passing the ID we specified Loader<String> loader = loaderManager.getLoader(OPERATION_SEARCH_LOADER); // If the Loader was null, initialize it. Else, restart it. if(loader==null){ loaderManager.initLoader(OPERATION_SEARCH_LOADER, queryBundle, this); }else{ loaderManager.restartLoader(OPERATION_SEARCH_LOADER, queryBundle, this); } }
Валла, ты закончил, просто чтобы напомнить тебе NetworkUtils.getResponseFromHttpUrl(url);
моя пользовательская функция, которая принимает строку, преобразует ее в URL
, который в свою очередь используется для создания HTTPUrlConnection
Мне нравится этот краткий пример AsyncTask и AsyncTaskLoader.
class FooLoader extends AsyncTaskLoader {
public FooLoader(Context context, Bundle args) {
super(context);
// do some initializations here
}
public String loadInBackground() {
String result = "";
// ...
// do long running tasks here
// ...
return result;
}
}
class FooLoaderClient implements LoaderManager.LoaderCallbacks {
Activity context;
// to be used for support library:
// FragmentActivity context2;
public Loader onCreateLoader(int id, Bundle args) {
// init loader depending on id
return new FooLoader(context, args);
}
public void onLoadFinished(Loader loader, String data) {
// ...
// update UI here
//
}
public void onLoaderReset(Loader loader) {
// ...
}
public void useLoader() {
Bundle args = new Bundle();
// ...
// fill in args
// ...
Loader loader =
context.getLoaderManager().initLoader(0, args, this);
// with support library:
// Loader loader =
// context2.getSupportLoaderManager().initLoader(0, args, this);
// call forceLoad() to start processing
loader.forceLoad();
}
}
упрощение трудно, может быть
private void loadContent() {
getLoaderManager().initLoader(1000, new Bundle(),
new LoaderManager.LoaderCallbacks<List<String>>() {
@Override
public Loader<List<String>> onCreateLoader(int id, Bundle args) {
return new AsyncTaskLoader<List<String>>(MainActivity.this.getApplicationContext()) {
@Override
public List<String> loadInBackground() {
Log.i("B", "Load background data ");
ArrayList<String> data = new ArrayList<>();
for (int i = 0; i < 5000; i++) {
data.add("Data." + i + " " + System.currentTimeMillis());
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return data;
}
};
}
@Override
public void onLoadFinished(Loader<List<String>> loader, List<String> data) {
Log.i("B", "Here are your data loaded" + data);
if (!loader.isAbandoned()) {
mAdapter.setData(data); // Read also about RecyclerView
}
}
@Override
public void onLoaderReset(Loader<List<String>> loader) {
Log.i("B", "Loader reset");
}
}).forceLoad();
}
@Override
protected void onDestroy() {
// Abandon the loader so that it should not attempt to modify already dead GUI component
getLoaderManager().getLoader(1000).abandon();
super.onDestroy();
}
сделайте это частью своей деятельности. Образец имитирует задержку, но упрощает распознавание новых записей, поскольку они будут иметь другой суффикс метки времени. Конечно, Вам также нужен RecyclerView для отображения данных, ответ на этот вопрос кажется очень хорошим.
загрузчиком в этом примере является внутренний класс, который сохраняет ссылку на родительское действие. Это должен быть внешний статический класс без таких справка в производстве.
Я предпочитаю использовать болты-Android. это очень просто.
https://github.com/BoltsFramework/Bolts-Android
Task.callInBackground(new Callable<Void>() {
public Void call() {
// Do a bunch of stuff.
}
}).continueWith(...);