Android Loader 機(jī)制揍瑟,讓你的數(shù)據(jù)加載更加輕松

前言

在 Android 中白翻,任何耗時(shí)的操作都不能放在 UI 線程中,所以耗時(shí)的操作都需要使用異步加載來(lái)實(shí)現(xiàn)。其實(shí)滤馍,加載耗時(shí)數(shù)據(jù)的常用方式其實(shí)也挺多的岛琼,就讓我們來(lái)看一下

1、Thread + Handler


Thread + Handler

2巢株、AsyncTask


AsyncTask

3槐瑞、Loader


Loader

前面兩種異步加載方式,相信大家是比較熟悉的阁苞,但是第三種方式困檩,可能有些人是沒(méi)怎么接觸過(guò)的,其實(shí)在 ContentProvider 中也可能存在耗時(shí)的操作那槽,這時(shí)候也應(yīng)該使用異步操作悼沿,而 Android 3.0 之后最推薦的異步操作就是 Loader,使用 Loader 機(jī)制能讓我們高效地加載數(shù)據(jù)

一骚灸、Loader 簡(jiǎn)介


Android 3.0 中引入了 Loader 機(jī)制糟趾,讓開(kāi)發(fā)者能輕松在 Activity 和 Fragment 中異步加載數(shù)據(jù),Loader 機(jī)制具有以下特征:

  • 可用于每個(gè) Activity 或 Fragment

  • 支持異步加載數(shù)據(jù)

  • 監(jiān)控?cái)?shù)據(jù)源并在內(nèi)容變化時(shí)傳遞新結(jié)果

  • 在某一配置更改后重建加載器時(shí)甚牲,會(huì)自動(dòng)重新連接上一個(gè)加載器的游標(biāo)义郑。因此,它們無(wú)需重新查詢其數(shù)據(jù)丈钙。

我們用一張圖來(lái)直觀地認(rèn)識(shí)下 Loader 機(jī)制和另外兩種做法之間的區(qū)別


從圖片中可以看出 Loader 機(jī)制的寫(xiě)法是相當(dāng)簡(jiǎn)潔的非驮,可以讓我們進(jìn)行快速的開(kāi)發(fā),而且效率方面也是非常高的雏赦。

二院尔、相關(guān)類和 API 介紹


本節(jié)內(nèi)容大部分來(lái)自官方文檔,詳細(xì)可以 點(diǎn)擊這里

在介紹 Loader 的使用之前喉誊,我們先來(lái)看一下與 Loader 機(jī)制相關(guān)的一些類和接口

類 / 接口 說(shuō)明
LoaderManager 一種與 Activity 或 Fragment 相關(guān)聯(lián)的抽象類邀摆,用于管理一個(gè)或多個(gè) Loader 實(shí)例。這有助于應(yīng)用管理與 Activity 或 Fragment 生命周期相關(guān)的伍茄、運(yùn)行時(shí)間較長(zhǎng)的操作栋盹。它常見(jiàn)的用法是 與 CursorLoader 一起使用,不過(guò)應(yīng)用也可以自由寫(xiě)入自己的加載器敷矫,用于加載其他類型的數(shù)據(jù)
LoaderManager.LoaderCallbacks 回調(diào)接口例获,用于客戶端與 LoaderManager 進(jìn)行交互,例如曹仗,可以使用 onCreateLoader() 回調(diào)方法創(chuàng)建新的加載器
Loader 一種執(zhí)行異步加載數(shù)據(jù)的抽象類榨汤。這是加載器的基類。我們通常會(huì)使用 CursorLoader怎茫,但也可以實(shí)現(xiàn)自己的子類收壕。當(dāng)加載器處于活動(dòng)狀態(tài)時(shí)妓灌,應(yīng)監(jiān)控其數(shù)據(jù)源并在內(nèi)容變化時(shí)傳遞新結(jié)果
AsyncTaskLoader 提供 AsyncTask 來(lái)執(zhí)行工作的抽象加載器
CursorLoader AsyncTaskLoader 的子類,它將查詢 ContentResolver 并返回一個(gè) Cursor蜜宪。使用此加載器是從 ContentProvider 異步加載數(shù)據(jù)的最佳方式虫埂,而不用通過(guò) Activity 或 Fragment 的 API 來(lái)執(zhí)行托管查詢

以上便是 Loader 機(jī)制相關(guān)的類,但并不是我們創(chuàng)建的每個(gè)加載器都要用到上述所有的類和接口圃验。但是掉伏,為了初始化加載器以及實(shí)現(xiàn)一個(gè) Loader 類(如 CursorLoader),我們需要引用 LoaderManager澳窑。

2.1 加載器的使用

使用加載器的應(yīng)用通常包括:

  • Activity 或 Fragment

  • LoaderManager 的實(shí)例

  • 一個(gè) CursorLoader斧散,用于加載由 ContentProvider 支持的數(shù)據(jù)。當(dāng)然我們也可以實(shí)現(xiàn)自己的 Loader 或 AsyncTaskLoader 子類摊聋,從其他的數(shù)據(jù)源中加載數(shù)據(jù)

  • 一個(gè) LoaderManager.LoaderCallbacks 實(shí)現(xiàn)颅湘,可以使用它來(lái)創(chuàng)建新的加載器,并管理對(duì)現(xiàn)有加載器的引用

  • 顯示加載器數(shù)據(jù)的方法栗精,如 SimpleCursorAdapter

  • 使用 CursorLoader 時(shí)的數(shù)據(jù)源闯参,如 ContentProvider

啟動(dòng)加載器

LoaderManager 可在 Activity 或 Fragment 內(nèi)管理一個(gè)或多個(gè) Loader 實(shí)例,每個(gè) Activity 或 Fragment 中只有一個(gè) LoaderManager悲立。通過(guò)我們會(huì)在 Activity 的 onCreate() 方法或 Fragment 中的 onActivityCreate() 方法內(nèi)初始化 Loader

getSupportLoaderManager().initLoader(0鹿寨,null,this);

initLoader() 方法采用以下參數(shù):

  • 用于標(biāo)識(shí)加載器的唯一 ID薪夕,在代碼示例中脚草,ID 為 0

  • 在構(gòu)建時(shí)提供給加載器的可選參數(shù)(在代碼示例中,為 null)

  • LoaderManager.LoaderCallbacks 實(shí)現(xiàn)原献,LoaderManager 將調(diào)用該實(shí)現(xiàn)來(lái)報(bào)告加載器事件馏慨。在此示例中,本地類實(shí)現(xiàn)了 LoaderManager.LoaderCallbacks 接口姑隅,因此直接傳遞它對(duì)自身的引用 this

initLoader() 調(diào)用確保加載器已經(jīng)初始化且處于活動(dòng)狀態(tài)写隶,這可能會(huì)出現(xiàn)兩種結(jié)果:

  • 如果指定 ID 的加載器已經(jīng)存在,那么將重復(fù)使用上次創(chuàng)建的加載器

  • 如果指定 ID 的加載器不存在讲仰,則 initLoader() 將觸發(fā) LoaderManager.LoaderCallbacks 中的 onCreateLoader() 方法慕趴,在這個(gè)方法中,我們可以實(shí)現(xiàn)代碼以實(shí)例化并返回新的加載器

無(wú)論何種情況鄙陡,給定的 LoaderManager.LoaderCallbacks 實(shí)現(xiàn)均與加載器相關(guān)聯(lián)冕房,且在加載器狀態(tài)變化時(shí)調(diào)用。如果在調(diào)用時(shí)趁矾,調(diào)用程序處于啟動(dòng)狀態(tài)耙册,且請(qǐng)求的加載器已存在并生成了數(shù)據(jù),則系統(tǒng)將立即調(diào)用 onLoadFinish()

有一點(diǎn)要注意的是毫捣,initLoader() 方法將返回已創(chuàng)建的 Loader详拙,但我們不用捕獲它的引用帝际。LoaderManager 將自動(dòng)管理加載器的生命周期。LoaderManager 將根據(jù)需要啟動(dòng)和停止加載溪厘,并維護(hù)加載器的狀態(tài)及其相關(guān)內(nèi)容胡本。這意味著我們將很少與加載器直接進(jìn)行交互牌柄。當(dāng)特定事件發(fā)生時(shí)畸悬,我們通常會(huì)使用 LoaderManager.LoaderCallbacks 方法干預(yù)加載進(jìn)程。

重啟加載器

當(dāng)我們使用 initLoader()珊佣,它將使用含有指定 ID 的現(xiàn)有加載器(如有)蹋宦。如果沒(méi)有它會(huì)創(chuàng)建一個(gè)。但有時(shí)咒锻,我們想舍棄這些舊數(shù)據(jù)并重新開(kāi)始冷冗。

要舍棄舊數(shù)據(jù),我們需要使用 restartLoader()惑艇,例如蒿辙,當(dāng)用戶的查詢更改時(shí),SearchView.OnQueryTextListener 實(shí)現(xiàn)將重啟加載器滨巴。加載器需要重啟思灌,以便它能夠使用修正后的搜索過(guò)濾器執(zhí)行新查詢:

public boolean onQueryTextChanged(String newText){
      mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
      getSupportLoaderManager().restartLoader(0, null, this);
      return true;
}

使用 LoaderManager 回調(diào)

LoaderManager.LoaderCallbacks 是一個(gè)支持客戶端與 LoaderManager 交互的回調(diào)接口

加載器(特別是 CursorLoader)在停止運(yùn)行后,仍需保留其數(shù)據(jù)恭取,這樣既可保留 Activity 或 Fragment 的 onStop() 和 onStart() 方法中的數(shù)據(jù)泰偿。當(dāng)用戶返回應(yīng)用時(shí),無(wú)需等待它重新加載這些數(shù)據(jù)蜈垮。

LoaderManager.LoaderCallbacks 接口包括以下方法

  • onCreateLoader():針對(duì)指定的 ID 進(jìn)行實(shí)例化并返回新的 Loader

  • onLoadFinished():將在先前創(chuàng)建的加載器完成加載時(shí)調(diào)用

  • onLoaderReset():將在先前創(chuàng)建的加載器重置且其數(shù)據(jù)因此不可用時(shí)調(diào)用

onCreateLoader()

當(dāng)我們嘗試訪問(wèn)加載器時(shí)(例如耗跛,通過(guò) initLoader()),該方法將檢查是否已存在由該 ID 指定的加載器攒发。如果沒(méi)有调塌,它將觸發(fā) LoaderManager.LoaderCallbacks 中的 onCreateLoader() 方法。在此方法中惠猿,我們可以創(chuàng)建加載器烟阐,通過(guò)這個(gè)方法將返回 CursorLoader,但我們也可以實(shí)現(xiàn)自己的 Loader 子類紊扬。

在下面的示例中蜒茄,onCreateLoader() 方法創(chuàng)建了 CursorLoader。我們必須使用它的構(gòu)造方法來(lái)構(gòu)建 CursorLoader餐屎。構(gòu)造方法 需要對(duì) ContentProvider 執(zhí)行查詢時(shí)所需的一系列完整信息

    public CursorLoader(Context context, Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        super(context);
        mObserver = new ForceLoadContentObserver();
        mUri = uri;
        mProjection = projection;
        mSelection = selection;
        mSelectionArgs = selectionArgs;
        mSortOrder = sortOrder;
    }
參數(shù)名 作用
uri 用于檢索內(nèi)容的 URI
projection 返回的列的列表檀葛。傳遞 null 時(shí),將返回所有列腹缩,這樣的話效率會(huì)很低
selection 一種用于聲明返回那些行的過(guò)濾器屿聋,采用 SQL WHERE 子句格式空扎。傳遞 null 時(shí),將為指定的 URI 返回所有行
selectionArgs 我們可以在 selection 中包含 ?润讥,它將按照在 selection 中顯示的順序替換為 selectionArgs 中的值
sortOrder 行的排序依據(jù)转锈,采用 SQL ORDER BY 子句格式。傳遞 null 時(shí)楚殿,將使用默認(rèn)排序順序(可能并未排序)

示例代碼:

public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    Uri baseUri;
    if (mCurFilter != null) {
        baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
                  Uri.encode(mCurFilter));
    } else {
        baseUri = Contacts.CONTENT_URI;
    }

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

onloadFinished

當(dāng)先前創(chuàng)建的加載器完成加載時(shí)撮慨,將會(huì)調(diào)用此方法。該方法必須在為此加載器提供的最后一個(gè)數(shù)據(jù)釋放之前調(diào)用脆粥。此時(shí)砌溺,我們應(yīng)該移除所有使用的舊數(shù)據(jù)(因?yàn)樗鼈兒芸炀蜁?huì)被釋放),但不要自行釋放這些數(shù)據(jù)变隔,因?yàn)檫@些數(shù)據(jù)歸加載器所有规伐,加載器會(huì)處理它們耕餐。

當(dāng)加載器發(fā)現(xiàn)應(yīng)用不再使用這些數(shù)據(jù)時(shí)戴卜,將會(huì)釋放它們篷帅。例如桥帆,如果數(shù)據(jù)是來(lái)自 CursorLoader 的一個(gè)游標(biāo)猫态,則我們不應(yīng)手動(dòng)對(duì)其調(diào)用 close()脸哀。如果游標(biāo)放置在 CursorAdapter 中腊尚,則應(yīng)使用 swapCursor() 方法鹿蜀,使舊 Cursor 不會(huì)關(guān)閉

SimpleCursorAdapter mAdapter;

public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    mAdapter.swapCursor(data);
}

onLoadReset

該方法將在 先前創(chuàng)建的加載器重置數(shù)據(jù)因此不可用 時(shí)調(diào)用夏哭,通過(guò)此回調(diào)检柬,我們可以了解何時(shí)將釋放數(shù)據(jù),因此能夠及時(shí)移除其引用竖配。

此實(shí)現(xiàn)調(diào)用值為 null 的 swapCursor()

SimpleCursorAdapter mAdapter;

public void onLoaderReset(Loader<Cursor> loader) {
    mAdapter.swapCursor(null);
}

三何址、Loader 機(jī)制的使用場(chǎng)景和使用方式


Loader 機(jī)制一般用于數(shù)據(jù)加載,特別是用于加載 ContentProvider 中的內(nèi)容进胯,比起 Handler + Thread 或者 AsyncTask 的實(shí)現(xiàn)方式用爪,Loader 機(jī)制能讓代碼更加的簡(jiǎn)潔易懂,而且是 Android 3.0 之后最推薦的加載方式胁镐。

Loader 機(jī)制的 使用場(chǎng)景 有:

  • 展現(xiàn)某個(gè) Android 手機(jī)有多少應(yīng)用程序

  • 加載手機(jī)中的圖片和視頻資源

  • 訪問(wèn)用戶聯(lián)系人

下面用一個(gè)加載手機(jī)中的圖片文件夾的例子偎血,看看在實(shí)際開(kāi)發(fā)中如何運(yùn)用 Loader 機(jī)制進(jìn)行高效加載。

3.1 實(shí)現(xiàn)自己的加載器

加載器是我們加載數(shù)據(jù)的工具盯漂,通過(guò)將對(duì)應(yīng)的 URI 以及其他的查詢條件傳遞給加載器颇玷,便可讓加載器在后臺(tái)高效地加載數(shù)據(jù),等數(shù)據(jù)加載完成了便會(huì)返回一個(gè) Cursor.

public class AlbumLoader extends CursorLoader {

    private static final Uri QUERY_URI = "content://media/external/file";

    private static final String[] PROJECTION = {
            "_id",
            "bucket_id",
            "bucket_display_name",
            "_data",
            "COUNT(*) AS " + "count"};

    private static final String SELECTION =
            "(media_type=? OR media_type =?) AND _size>0) GROUP BY (bucket_id"

    private static final String[] SELECTION_ARGS = {
            String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE),
            String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO)
    };

    private static final String BUCKET_ORDER_BY = "datetaken DESC";

    private AlbumLoader(Context context, String selection, String[] selectionArgs) {
        super(context, QUERY_URI, PROJECTION, SELECTION, SELECTION_ARGS, BUCKET_ORDER_BY);
    }

    public static CursorLoader newInstance(Context context) {
        String selection = SELECTION;
        String[] selectionArgs = SELECTION_ARGS;
        return new AlbumLoader(context, selection, selectionArgs);
    }

    @Override
    public Cursor loadInBackground() {
        return super.loadInBackground();
    }
}

3.2 實(shí)現(xiàn) LoaderCallbacks 進(jìn)行客戶端的交互

為了降低代碼的耦合度就缆,繼承 LoaderManager.Loadercallbacks 實(shí)現(xiàn) AlbumLoader 的管理類帖渠,將 Loader 的各種狀態(tài)進(jìn)行管理。

通過(guò)外部傳入 Context竭宰,采用弱引用的方式防止內(nèi)存泄露空郊,獲取 LoaderManager份招,并在 AlbumCollection 內(nèi)部定義了相應(yīng)的接口,將加載完成后返回的 Cursor 回調(diào)出去狞甚,讓外部的 Activity 或 Fragment 進(jìn)行相應(yīng)的處理锁摔。

public class AlbumCollection implements LoaderManager.LoaderCallbacks<Cursor> {

    private static final int LOADER_ID = 1;
    private WeakReference<Context> mContext;
    private LoaderManager mLoaderManager;
    private AlbumCallbacks mCallbacks;

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        Context context = mContext.get();
        return AlbumLoader.newInstance(context);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        Context context = mContext.get();
        mCallbacks.onAlbumLoad(data);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        Context context = mContext.get();
        mCallbacks.onAlbumReset();
    }

    public void onCreate(FragmentActivity activity, AlbumCallbacks callbacks){
        mContext = new WeakReference<Context>(activity);
        mLoaderManager = activity.getSupportLoaderManager();
        mCallbacks = callbacks;
    }

    public void loadAlbums(){
        mLoaderManager.initLoader(LOADER_ID, null, this);
    }

    public interface AlbumCallbacks{
        void onAlbumLoad(Cursor cursor);
        void onAlbumReset();
    }
}

3.3 主界面中的邏輯

看到這代碼是不是覺(jué)得特別簡(jiǎn)潔,讓 MainActivity 中繼承了 AlbumCollection 中的 AlbumCallback 接口哼审,接著 onCreate() 中實(shí)例化了 AlbumCollection谐腰,然后讓 AlbumCollection 開(kāi)始加載數(shù)據(jù)。

等數(shù)據(jù)加載完成后棺蛛,便將包含數(shù)據(jù)的 Cursor 回調(diào)在 onAlbumLoad() 方法中怔蚌,我們便可以進(jìn)行 UI 的更新巩步。

可以看到采用 Loader 機(jī)制旁赊,可以讓我們的 Activity 或 Fragment 中的代碼變得相當(dāng)?shù)暮?jiǎn)潔、清晰椅野,而且代碼耦合程度也相當(dāng)?shù)汀?/p>

public class MainActivity extends AppCompatActivity implements AlbumCollection.AlbumCallbacks{

    private AlbumCollection mCollection;
    private AlbumAdapter mAdapter;
    private RecyclerView mRvAlbum;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mCollection = new AlbumCollection();
        mCollection.onCreate(this, this);
        mCollection.loadAlbums();
    }

    @Override
    public void onAlbumLoad(Cursor cursor) {
        mRvAlbum = (RecyclerView) findViewById(R.id.main_rv_album);
        mRvAlbum.setLayoutManager(new LinearLayoutManager(this));
        mRvAlbum.setAdapter(new AlbumAdapter(cursor));
    }

    @Override
    public void onAlbumReset() {

    }

}

以上便是本文的全部?jī)?nèi)容终畅,代碼我已經(jīng)放上 Github 了,需要完整代碼的 點(diǎn)擊這里竟闪。覺(jué)得有幫助的話离福,希望能幫忙給個(gè)喜歡,歡迎關(guān)注炼蛤。


猜你喜歡

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末理朋,一起剝皮案震驚了整個(gè)濱河市絮识,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嗽上,老刑警劉巖次舌,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異兽愤,居然都是意外死亡彼念,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門浅萧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)逐沙,“玉大人,你說(shuō)我怎么就攤上這事洼畅》园福” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵土思,是天一觀的道長(zhǎng)务热。 經(jīng)常有香客問(wèn)我忆嗜,道長(zhǎng),這世上最難降的妖魔是什么崎岂? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任捆毫,我火速辦了婚禮,結(jié)果婚禮上冲甘,老公的妹妹穿的比我還像新娘绩卤。我一直安慰自己,他們只是感情好江醇,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布濒憋。 她就那樣靜靜地躺著,像睡著了一般陶夜。 火紅的嫁衣襯著肌膚如雪凛驮。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天条辟,我揣著相機(jī)與錄音黔夭,去河邊找鬼。 笑死羽嫡,一個(gè)胖子當(dāng)著我的面吹牛本姥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播杭棵,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼婚惫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了魂爪?” 一聲冷哼從身側(cè)響起先舷,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎甫窟,沒(méi)想到半個(gè)月后密浑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡粗井,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年尔破,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浇衬。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡懒构,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出耘擂,到底是詐尸還是另有隱情胆剧,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站秩霍,受9級(jí)特大地震影響篙悯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜铃绒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一鸽照、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧颠悬,春花似錦矮燎、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至灾票,卻和暖如春峡谊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背铝条。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工靖苇, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留席噩,地道東北人班缰。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像悼枢,于是被迫代替她去往敵國(guó)和親埠忘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,303評(píng)論 25 707
  • 1 背景## 在Android中任何耗時(shí)的操作都不能放在UI主線程中馒索,所以耗時(shí)的操作都需要使用異步實(shí)現(xiàn)莹妒。同樣的,在...
    我是昵稱閱讀 1,221評(píng)論 0 3
  • Android開(kāi)發(fā)者都經(jīng)歷過(guò)APP UI開(kāi)發(fā)不當(dāng) 會(huì)造成overDraw绰上,導(dǎo)致APP UI渲染過(guò)慢旨怠,但是很多人卻沒(méi)...
    Tamic閱讀 15,942評(píng)論 30 104
  • 我的朋友一直不多鉴腻,就是那種說(shuō)起朋友兩個(gè)字時(shí)瞬間就浮現(xiàn)在我腦海里的那種朋友。 小學(xué)時(shí)百揭,朋友是一起釣龍蝦捉青蛙的鄰里爽哎,...
    HHHYeart閱讀 1,689評(píng)論 0 1
  • 彼此的距離開(kāi)始慢慢拉近 那問(wèn)你 是恰好 還是不夠近…
    Freelexi閱讀 240評(píng)論 0 1