31

3.0 ile AsyncTaskLoader, CursorLoader ve diğer özel Loader örneklerini kullanarak veri yüklemesini gerçekleştiren fantezi LoaderManager aldık. Ama bunlar için dokümanlar üzerinden okuma yapamadım sadece şu noktayı anlayamadım: bunlar, veri yükleme için eski AsyncTask'u kullanmaktan nasıl daha iyi?Android 3.0 - LoaderManager örneklerini tam olarak kullanmanın avantajları nelerdir?

+0

Kontrol dışarı [** Bu yazı **] (http : //www.androiddesignpatterns.com/2012/06/app-force-close-honeycomb-ics.html) ... ilk bölüm, 'LoaderManager' kullanımının kullanımdan kaldırılan 'startManagingCursor 'üzerinden avantajlarını listeliyor ... – user1422551

+1

[** 'LoaderManager'ı anlama **] (http://www.androiddesignpatterns.com/2012/07/understanding-loadermanager.html), öğrenmek için harika bir gönderidir. –

cevap

53

Eh onlar çok daha az hata eğilimli uygulamak ve yaşam döngüsü yönetimi konusunda her şeyin çaresine için çok basittir.

public static class CursorLoaderListFragment extends ListFragment 
     implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { 

    // This is the Adapter being used to display the list's data. 
    SimpleCursorAdapter mAdapter; 

    // If non-null, this is the current filter the user has provided. 
    String mCurFilter; 

    @Override public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 

     // Give some text to display if there is no data. In a real 
     // application this would come from a resource. 
     setEmptyText("No phone numbers"); 

     // We have a menu item to show in action bar. 
     setHasOptionsMenu(true); 

     // Create an empty adapter we will use to display the loaded data. 
     mAdapter = new SimpleCursorAdapter(getActivity(), 
       android.R.layout.simple_list_item_2, null, 
       new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS }, 
       new int[] { android.R.id.text1, android.R.id.text2 }, 0); 
     setListAdapter(mAdapter); 

     // Prepare the loader. Either re-connect with an existing one, 
     // or start a new one. 
     getLoaderManager().initLoader(0, null, this); 
    } 

    @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     // Place an action bar item for searching. 
     MenuItem item = menu.add("Search"); 
     item.setIcon(android.R.drawable.ic_menu_search); 
     item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 
     SearchView sv = new SearchView(getActivity()); 
     sv.setOnQueryTextListener(this); 
     item.setActionView(sv); 
    } 

    public boolean onQueryTextChange(String newText) { 
     // Called when the action bar search text has changed. Update 
     // the search filter, and restart the loader to do a new query 
     // with this filter. 
     mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; 
     getLoaderManager().restartLoader(0, null, this); 
     return true; 
    } 

    @Override public boolean onQueryTextSubmit(String query) { 
     // Don't care about this. 
     return true; 
    } 

    @Override public void onListItemClick(ListView l, View v, int position, long id) { 
     // Insert desired behavior here. 
     Log.i("FragmentComplexList", "Item clicked: " + id); 
    } 

    // These are the Contacts rows that we will retrieve. 
    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { 
     Contacts._ID, 
     Contacts.DISPLAY_NAME, 
     Contacts.CONTACT_STATUS, 
     Contacts.CONTACT_PRESENCE, 
     Contacts.PHOTO_ID, 
     Contacts.LOOKUP_KEY, 
    }; 

    public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
     // This is called when a new Loader needs to be created. This 
     // sample only has one Loader, so we don't care about the ID. 
     // First, pick the base URI to use depending on whether we are 
     // currently filtering. 
     Uri baseUri; 
     if (mCurFilter != null) { 
      baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 
        Uri.encode(mCurFilter)); 
     } else { 
      baseUri = Contacts.CONTENT_URI; 
     } 

     // Now create and return a CursorLoader that will take care of 
     // creating a Cursor for the data being displayed. 
     String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" 
       + Contacts.HAS_PHONE_NUMBER + "=1) AND (" 
       + Contacts.DISPLAY_NAME + " != ''))"; 
     return new CursorLoader(getActivity(), baseUri, 
       CONTACTS_SUMMARY_PROJECTION, select, null, 
       Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); 
    } 

    public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 
     // Swap the new cursor in. (The framework will take care of closing the 
     // old cursor once we return.) 
     mAdapter.swapCursor(data); 
    } 

    public void onLoaderReset(Loader<Cursor> loader) { 
     // This is called when the last Cursor provided to onLoadFinished() 
     // above is about to be closed. We need to make sure we are no 
     // longer using it. 
     mAdapter.swapCursor(null); 
    } 
} 

doğru bu tam bir örnek uygulamaya:

Tıpkı kullanıcı etkileşimli eylem çubuğunda bir sorgu giriş alanında aracılığıyla set sonucu filtreleme olanağı sağlayan imleç sorgusunun sonucunu göstermek için, örnek kodlara bakmak AsyncTask ile kendinizi çok daha fazla kod içerecek ... ve o zaman bile, bir şeyleri eksiksiz ve iyi bir şekilde uygulayacak mısınız? Örneğin, uygulamanız yüklenen İmleci etkinlik yapılandırması değişikliklerinde koruyacak ve yeni örnekler oluşturulduğunda yeniden sorgulanmaya ihtiyaç duymayacak mı? LoaderManager/Loader sizin için otomatik olarak yapacağı gibi, etkinlik yaşam döngüsüne bağlı olarak İmleç doğru bir şekilde oluşturulup kapanmaya da özen gösterecektir.

Ayrıca, bu kodu kullanarak size hiç emin uzun çalışan iş yapma düşünmek ana UI iş parçacığı kapalı gerçekleştirilen gerektirmez dikkat edin. LoaderManager ve CursorLoader sizin için tüm bunlara dikkat ederek, imleç ile etkileşirken ana parçayı asla bloke etmeyeceğinizi garanti eder. Bunu doğru bir şekilde yapmak için aslında iki İmleç nesnesinin aynı anda noktalarda aktif olması gerekir, böylece gösterilecek olan bir sonraki öğe yüklenirken mevcut İmleç ile etkileşimli bir UI görüntülemeye devam edebilirsiniz. LoaderManager hepsini sizin için yapar.

Bu çok daha basit bir API'dir - AsyncTask hakkında bilgi sahibi olmanıza gerek yok ve arka planda ne koşması gerektiğini düşünün, etkinlik yaşam döngüsü hakkında düşünmenize gerek yok veya eski "yönetilen imleç" API'lerini Aktivitede kullanma (hangi zaten LoaderManager gibi işe yaramadı).

(Btw sen 1.6 aşağı Android'in eski sürümlerinde tam LoaderManager API kullanmasına izin yeni "destek" statik kütüphane unutmayın!)

+0

Harika cevap! Evet, yeni başlayanların AsyncTask'ı kötüye kullanması için hala çok kolaydı - yapılandırma değişikliklerini kolayca halledemedi ve bellek sızıntılarına neden olmadığından emin olmak için 'onProgressUpdate' vb. Bir İçeriğe ihtiyacınız varsa dikkatli olmalısınız. . –

+10

Belki de benim, ama bu kolay olmaktan uzak görünüyor! – Ants

+0

@hackbod Hem Android 4.0'ı hem de destek kütüphanesini denedim ve yapılandırma değişiklikleri arasında imleç _is not_ ifadesine benziyor. Hatta bununla ilgili bir hata buldum: http://code.google.com/p/android/issues/detail?id=25112 – inazaruk

İlgili konular