Loader詳解

来源:http://www.cnblogs.com/ganchuanpu/archive/2017/04/20/6741528.html
-Advertisement-
Play Games

1.裝載器API概述 Class/Interface 說明 LoaderManager 一個抽像類,關聯到一個Activity或Fragment,管理一個或多個裝載器的實例。這幫助一個應用管理那些與Activity或Fragment的生命周期相關的長時間運行的的操作。最常見的方式是與一個Cursor ...


1.裝載器API概述

Class/Interface

說明

LoaderManager

一個抽像類,關聯到一個Activity或Fragment,管理一個或多個裝載器的實例。這幫助一個應用管理那些與Activity或Fragment的生命周期相關的長時間運行的的操作。最常見的方式是與一個CursorLoader一起使用,然而應用是可以隨便寫它們自己的裝載器以載入其它類型的數據。

每個activity或fragment只有一個LoaderManager。但是一個LoaderManager可以擁有多個裝載器。

LoaderManager.LoaderCallbacks

一個用於客戶端與LoaderManager交互的回調介面。例如,你使用回調方法onCreateLoader()來創建一個新的裝載器。

Loader(裝載器)

一個執行非同步數據載入的抽象類。它是載入器的基類。你可以使用典型的CursorLoader,但是你也可以實現你自己的子類。一旦裝載器被激活,它們將監視它們的數據源並且在數據改變時發送新的結果。

AsyncTaskLoader

提供一個AsyncTask來執行非同步載入工作的抽象類。

CursorLoader

AsyncTaskLoader的子類,它查詢ContentResolver然後返回一個Cursor。這個類為查詢cursor以標準的方式實現了裝載器的協議,它的游標查詢是通過AsyncTaskLoader在後臺線程中執行,從而不會阻塞界面。使用這個裝載器是從一個ContentProvider非同步載入數據的最好方式。相比之下,通過fragment或activity的API來執行一個被管理的查詢就不行了。

2.使用載入器

一個使用裝載器的應用會典型的包含如下組件:

  • 一個Activity或Fragment

  • 一個LoaderManager的實例.

  • 一個載入被ContentProvider所支持的數據的CursorLoader.或者,你可以從Loader或AsyncTaskLoader實現你自己的裝載器來從其它源載入數據.

  • 一個LoaderManager.LoaderCallbacks的實現.這是你創建新的裝載器以及管理你的已有裝載器的引用的地方.

  • 一個顯示裝載器的數據的途徑,例如使用一個SimpleCursorAdapter

  • 一個數據源,比如當是用CursorLoader時,它將是一個ContentProvider

啟動一個裝載器

LoaderManager管理一個Activiry或Fragment中的一個或多個裝載器.但每個activity或fragment只擁有一個LoaderManager

你通常要在activity的onCreate()方法中或fragment的onActivityCreated()方法中初始化一個裝載器.你可以如下創建

// 準備裝載器.可以重連一個已經存在的也可以啟動一個新的.  
getLoaderManager().initLoader(0,null, this);  

initLoader()方法有以下參數:

  • 一個唯一ID來標誌裝載器.在這個例子中,ID是0

  • 可選的參數,用於裝載器初始化時(本例中是null)

  • 一個LoaderManager.LoaderCallbacks的實現.被LoaderManager調用以報告裝載器的事件,在這個例子中,類本實現了這個介面,所以傳的是它自己:this


initLoader()保證一個裝載器被初始化並激活.它具有兩種可能的結果:

  • 如果ID所指的裝載器已經存在,那麼這個裝載器將被重用.

  • 如果裝載器不存在,initLoader()就觸發LoaderManager.LoaderCallbacks的方法onCreateLoader().這是你實例化並返回一個新裝載器的地方.

在這兩種情況中,傳入的LoaderManager.LoaderCallbacks的實現都與裝載器綁定在一起.並且會在裝載器狀態變化時被調用.如果在調用這個方法時,調用者正處於啟動狀態,並且所請求的裝載器已存在並產生了數據,那麼系統會馬上調用onLoadFinished()(也就是說在initLoader()還在執行時).所以你必須為這種情況的發生做好準備.


註意initLoader()返回所創建的裝載器,但是你不需保存一個對它的引用.LoaderManager自動管理裝載器的生命.LoaderManager會在需要時開始和停止裝載動作,並且維護裝載器的狀態和它所關聯的內容.這意味著,你很少與裝載器直接交互.你通常都是使用LoaderManager.LoaderCallbacks的方法們在某個事件發生時介入到數據載入的過程中.

  

3.回調及完整例子

onLoadFinished

這個方法是在前面已創建的裝載器已經完成其載入過程後被調用.這個方法保證會在應用到裝載器上的數據被釋放之前被調用.在此方法中,你必須刪除所有對舊數據的使用(因為它將很快會被刪除),但是不要自己去釋放它們,因為它們的裝載器會做這些事情.

裝載器一旦瞭解到應用不再使用數據時,將馬上釋放這些數據.例如,如果數據是一個從CursorLoader來的游標,你不應調用游標的close().如果游標被放置在一個CursorAdapter中,你應使用swapCursor()方法,以使舊的游標不被關閉.例如:

//這個Adapter被用於顯示列表的數據.  
SimpleCursorAdapter mAdapter;  
...  
  
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);  
}  

onLoaderReset

當一個已創建的裝載器被重置從而使其數據無效時,此方法被調用.此回調使你能發現什麼時候數據將被釋放於是你可以釋放對它的引用.

下麵這個實現調用參數為null的swapCursor()

// 這個Adapter被用於顯示列表的數據.  
SimpleCursorAdapter mAdapter;  
...  
  
public void onLoaderReset(Loader<Cursor> loader) {  
    //此處是用於上面的onLoadFinished()的游標將被關閉時執行, 我們需確保我們不再使用它.  
    mAdapter.swapCursor(null);  
}  


例子
作為一個例子,這裡完整實現了一個Fragment顯示一個包含從聯繫人contentprovider 返回查詢數據的ListView的內容的功能.它使用一個CursorLoader來管理對provider的查詢.

public static class CursorLoaderListFragment extends ListFragment  
        implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {  
  
    // 這是用於顯示列表數據的Adapter  
    SimpleCursorAdapter mAdapter;  
  
    // 如果非null,這是當前的搜索過慮器  
    String mCurFilter;  
  
    @Override public void onActivityCreated(Bundle savedInstanceState) {  
        super.onActivityCreated(savedInstanceState);  
  
        // 如果列表中沒有數據,就給控制項一些文字去顯示.在一個真正的應用  
        // 中這應用資源中取得.  
        setEmptyText("No phone numbers");  
  
        // 我們在動作欄中有一個菜單項.  
        setHasOptionsMenu(true);  
  
        // 創建一個空的adapter,我們將用它顯示載入後的數據  
        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);  
  
        // 準備loader.可能是重連到一個已存在的或開始一個新的  
        getLoaderManager().initLoader(0, null, this);  
    }  
  
    @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {  
        // 放置一個動作欄項用於搜索.  
        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) {  
        // 在動作欄上的搜索字串改變時被調用.更新  
        //搜索過濾器,並重啟loader來執行一個新的查詢  
        mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;  
        getLoaderManager().restartLoader(0, null, this);  
        return true;  
    }  
  
    @Override public boolean onQueryTextSubmit(String query) {  
        // 我們不關心這個方法  
        return true;  
    }  
  
    @Override public void onListItemClick(ListView l, View v, int position, long id) {  
        // 寫入你想寫的代碼  
        Log.i("FragmentComplexList", "Item clicked: " + id);  
    }  
  
    // 這是我們想獲取的聯繫人中一行的數據.  
    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) {  
        // 當一個新的loader需被創建時調用.本例僅有一個Loader,  
        //所以我們不需關心ID.首先設置base URI,URI指向的是聯繫人  
        Uri baseUri;  
        if (mCurFilter != null) {  
            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,  
                    Uri.encode(mCurFilter));  
        } else {  
            baseUri = Contacts.CONTENT_URI;  
        }  
  
        // 現在創建並返回一個CursorLoader,它將負責創建一個  
        // Cursor用於顯示數據  
        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) {  
        // 將新的cursor換進來.(框架將在我們返回時關心一下舊cursor的關閉)  
        mAdapter.swapCursor(data);  
    }  
  
    public void onLoaderReset(Loader<Cursor> loader) {  
        //在最後一個Cursor準備進入上面的onLoadFinished()之前.  
        // Cursor要被關閉了,我們需要確保不再使用它.  
        mAdapter.swapCursor(null);  
    }  
}  

  

參考地址:http://blog.csdn.net/llp1992/article/details/40630361

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 轉載請註明出處 http://www.cnblogs.com/cnwutianhao/p/6746981.html 前幾天客戶提需求,對App增加一個功能,這個功能目前市面上已經很常見,那就是應用內切換語言。啥意思,就是 英、中、法、德、日。。。語言隨意切換。 (本案例採用Data-Bingding ...
  • 關於三個構造函數使用時機的說法 也就是說,系統預設只會調用Custom View的前兩個構造函數,至於第三個構造函數的調用,通常是我們自己在構造函數中主動調用的(例如,在第二個構造函數中調用第三個構造函數). ...
  • Activity代碼 自定義view 看下自定義view 類,主要onDraw()方法中. 繪製中分為三部分, 第一部分為上部分半透明區域 第二部分為下部分全透明區域 第三部分就是中間的progress值變化 ...
  • 一.對android:configChanges屬性,一般認為有以下幾點:1、不設置Activity的android:configChanges時,切屏會重新調用各個生命周期,切橫屏時會執行一次,切豎屏時會執行兩次2、設置Activity的android:configChanges="orienta ...
  • ex : Precondition : R_CHARGER_1 是 int type R_CHARGER_2 是 int type val 是 int type val = (((R_CHARGER_1+R_CHARGER_2) 100 val)/R_CHARGER_2)/100; 為什麼要乘100 ...
  • 基於Android 7.0源碼,深入解析init進程及main函數的邏輯功能 ...
  • ReactJS 是否準備好 有時候我們常常需要監聽 ReactJS 的的載入情況。 比如說,當獲取一條推送,應用還沒有起來,通過點擊推送啟動應用後,而推送中包含一些我們感興趣的欄位需要處理,我們如果直接把這條通知發送給 ReactJS,會有一個問題,就是應用是剛啟動的,ReactJS 還沒有成功載入 ...
  • 微信 小程式開始火了,app跨平臺的革命再次高漲,不得不說,不用再擔心android和ios雙版本開發成本,及h5的開發 和apicloud一樣,不需要關註平臺問題,只需要關註前端js、css就能大aodroin和ios上完美相容,贊贊贊~ 那麼apicloud 和 微信小程式又有什麼區別和共通呢? ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...