使用 MailOtto 做完美預加載
最近我開源了一個專注懶事件的事件總線 MailOtto: https://github.com/drakeet/MailOtto 并寫了一個用它來做預加載的實踐案例:第一個頁面預先為第四個頁面發起數據加載請求,等用戶進入第四個頁面,那加載好的數據才會分發給它,若在數據下來前進入第四個頁面,也會等完成的時候自動接收到。
這個數據需要 8 秒,如果進入到第四個頁面才開始加載,體驗就很不好,就算只要 1 秒,也會有一個文本從無到有閃動的過程。如果在第一個頁面停留超過 8 秒,它足夠完成全程預加載,進入第四個頁面里面就能直接拿到數據,可謂完美預加載。
本文就是來介紹一下這個實踐案例。
先上這個實踐的源碼,它位于 MailOtto 下的 sample 模塊:sample, 演示 apk 下載
MainActivity 作為模擬一個用戶可能停留比較長時間的頁面,這樣我們就可以在這個頁面背后進行為后續的某個頁面內容做預加載。
public void onPreload(final View view) {
((TextView)view).append(": loading...");
mHandler.postDelayed(new InnerRunnable(view), 8 * 1000);
}
以上代碼模擬了一個耗時 8 * 1000 毫秒的后臺任務,為了避免 Runnable 匿名內部類引用 MainActivity.this 造成內存泄漏,我使用了一個 InnerRunnable 靜態內部類:
public static class InnerRunnable implements Runnable {
WeakReference<TextView> textViewPreference;
public InnerRunnable(View textView) {
this.textViewPreference = new WeakReference<>((TextView) textView);
}
@Override public void run() {
if (textViewPreference.get() != null) {
textViewPreference.get().append(": done!");
}
Mailbox.getInstance().post(new Mail("A mail from MainActivity", TargetActivity.class));
}
}
之后路過兩個無謂的 NextActivity:在這個靜態內部類中,run 方法會在 8s 后被調用,從而將加載下來的數據交給 Mailbox “郵遞員”。
startActivity(NextActivity.getIntent(this, /*page = */2));
到進入第四個頁面,即 TargetActivity,我們只要告訴“郵遞員”:我在家,送信給我吧!“郵遞員”就會自動調用你的 @OnMailReceived:這兩個頁面基本什么都沒干,純粹是為了演示跨頁面懶通訊,為什么要演示這個內容呢,因為這是為了體現 MailOtto 在跨頁面運輸方面天生比 Intent 方式容易得多,而且它支持懶發送懶接收。
Mailbox.getInstance().atHome(this);
@OnMailReceived public void onPreloadDataReady(Mail mail) {
mTextView.setText(mail.content.toString());
}
另外,為了防止單例造成內存泄漏,需要在頁面結束的時候應該對 Mailbox 標示 “我已經離開了”:這時候那加載好的數據才會分發給 TargetActivity,若在數據下來前進入 TargetActivity,也會等完成的時候自動接收到。所以我們不必再進行一堆判斷或重新請求。
Mailbox.getInstance().leave(this);
到此為止,我的例子就結束了。當然這個庫絕不僅限于做預加載,只是今天突然發現它天生地適合做預加載,另外它也可以用于取代 startActivityForResult,同時擁有 Otto/EventBus 的功能。