2013-11-29 5 views
19

Я использую Loader в своем приложении и на основе результата, полученного из запроса, выполняемого на COntacts, используя этот Loader. Я выполняю некоторые вычисления и сохраняю их обратно в Sqlite DB. Я хочу, чтобы эта операция была асинхронной, однако я запутался в использовании задачи Async, поскольку у меня есть много разных типов данных для возврата или я должен использовать простой обработчик или AsyncTaskLoader, я хочу, чтобы это было просто, поскольку я новичок в Погрузчики. Я попытался найти примеры для AsyncTaskLoader, но, похоже, ракетостроение, простой и простой функциональный пример любого из трех в контексте моего сценария было бы очень полезно.Основной пример AsyncTaskLoader. (Android)

+0

В примерах SDK вы можете увидеть пример AsyncTaskLoader: ApiDemos/src/com/example/android/apis/app/LoaderCustom.java –

+0

Я нашел очень хороший учебник, который поможет вам понять с нуля. Он имеет четыре части и отличный способ узнать о погрузчиках. [Жизнь перед погрузчиками (часть 1)] (http://www.androiddesignpatterns.com/2012/07/loaders-and-loadermanager-background.html) – Sufian

ответ

24

Если вы хотите использовать AsyncTaskLoader, here's хороший образец для вас.

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(); 
     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 
    } 
} 
+0

вы забыли «вернуть» из 'isReset()' –

+0

Приняли этот ответ, так как это ссылка на код без каких-либо ссылок на внешние сайты. – Skynet

+0

может кто-нибудь сказать мне, почему forceload() необходимо? – Mohanakrrishna

12

Поскольку сотовая библиотека и библиотека совместимости v4 можно использовать AsyncTaskLoader. Из того, что я понимаю, AsyncTaskLoader может выжить через изменения конфигурации, такие как экраны экрана. Но используя AsyncTask, вы можете испортить изменения конфигурации.

Основная информация: AsyncTaskLoader является подклассом Loader. Этот класс выполняет ту же функцию, что и AsyncTask, но немного лучше, он также может быть полезен при обработке изменений конфигурации (ориентация экрана).

Здесь очень хороший пример и пояснения. http://www.javacodegeeks.com/2013/01/android-loaders-versus-asynctask.html

У Google есть довольно хороший пример непосредственно в Документах API. Шаблоны Android Design предоставляют более подробную информацию и аргументы за Loaders.

Этот учебник определенно поможет вам. http://www.javacodegeeks.com/2013/08/android-custom-loader-to-load-data-directly-from-sqlite-database.html

+3

Значит, мне нужно написать три класса, где я должен был их использовать? Или, в частности, простой обработчик! Боль в A – Skynet

+0

использует IntentFilter. Один класс. отсортировано – jonney

+0

Я новичок в загрузчиках, и я нашел пример очень полезным, но застрял в месте, чтобы понять его.Если я добавлю некоторые данные на какой-либо щелчок на кнопке, данные не получат уведомление о listfragment, но он показывает, как только я закрою приложение и снова открою приложение или изменю конфигурацию, можете ли вы рассказать мне, что мне не хватает для уведомления адаптера? Пример такой же, просто добавив dataSource.add() при нажатии кнопки –

6

Мне нравится этот краткий пример AsyncTask and 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(); 
    } 
} 
+0

Это проще. Благодаря! – TatiOverflow

9

Вот шаг за шагом учебник для реализации AsyncTaskLoader.или проверить эту же статью на Medium

  1. Реализовать LoaderManager.LoaderCallbacks<String> на MainActivity и создать static int уникально идентифицировать загрузчик и создать ключ String, чтобы передать строку 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"; 
    //...} 
    
  2. Переопределение 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 
    } 
    
  3. внутри 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(); 
         } 
        }; 
    } 
    
  4. Внутри 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; 
        } 
    
  5. Внутри onCreate инициализации загрузчик с OPERATION_SEARCH_LOADER в качестве идентификатора, нуль для расслоения, а это для контекста

    getSupportLoaderManager().initLoader(OPERATION_SEARCH_LOADER, null, this); 
    
  6. Теперь называют этот метод, когда и где вы хотите, чтобы вызвать погрузчик

    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); 
        } 
    } 
    

Walla, вы сделали, чтобы напомнить вам NetworkUtils.getResponseFromHttpUrl(url); моя пользовательская функция, которая взять строку преобразовать его в URL, который в свою очередь используется для создания HTTPUrlConnection

+1

Спасибо за шаг за шагом. НО Человек! Google действительно является мастером создания свернутых кодов. Особенно в Android. Все кажется чрезмерно сложным без причины. – TatiOverflow

+0

@TatiOverflow, в первую очередь отличное имя пользователя, во-вторых, основное использование AsyncTaskLoader - использовать его с CursorLoader и ContentProvider, но теперь у Google появилось гораздо более простое решение под названием Android Architecture Component https://developer.android.com/topic/ library/architecture/index.html –

+0

Спасибо. Я прочитаю об этом. – TatiOverflow

1

Упрощая трудно, может быть,

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 для отображения данных, ответ на this question кажется очень хорошим.

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

Смежные вопросы