在Android開發中,預取資料可以說是一個比較通用的功能,通過預取資料可以有效的減少使用者等待的時間,提升使用者體驗,是一種常見的以空間換取時間的策略。雖然說預取資料這個功能比較好實現,但一直沒有發現一個好用的開源庫實現,於是自己花了點時間寫了一個,儘量做到簡單優雅、輕量和侵入性低GITHUB地址
Prefetch
一個通用的資料預取庫
- 簡單優雅、輕量和侵入性低
- 如果之前使用
RxJava
,那麼完全可以重用之前的資料載入邏輯
預覽
Gradle依賴
implementation 'com.tubb:prefetch:1.1.0'
複製程式碼
如何使用
- 先要繼承 FetchTask 類, 定義好資料載入任務,可以看到
execute()
方法返回的是RxJava
中的Obserable
型別,預設的執行執行緒為Schedulers.io()
,執行結果通知執行緒為AndroidSchedulers.mainThread()
,當然這兩者都可以通過覆寫相應的方法來指定
public class UserInfoFetchTask extends FetchTask<UserInfo> {
@Override
public Observable<UserInfo> execute() {
return Observable.create(new ObservableOnSubscribe<UserInfo>() {
@Override
public void subscribe(ObservableEmitter<UserInfo> emitter) throws Exception {
// just for test
Thread.sleep(5000);
UserInfo userInfo = new UserInfo();
userInfo.name = "BingBing";
emitter.onNext(userInfo);
}
});
}
}
複製程式碼
protected Scheduler subscribeOnScheduler() {
return SchedulerProvider.io();
}
protected Scheduler observeOnScheduler() {
return SchedulerProvider.ui();
}
複製程式碼
- 然後就可以執行定義好的任務,框架會幫你生成一個
taskId
,作為任務的唯一標識,後續註冊資料載入結果監聽器要指定對應的taskId
public class MainActivity extends AppCompatActivity {
private long taskId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onResume() {
super.onResume();
// prefetch user info data
taskId = Prefetch.instance().executeTask(new UserInfoFetchTask());
}
public void viewClick(View view) {
Intent intent = new Intent(this, UserInfoActivity.class);
intent.putExtra("taskId", taskId);
startActivity(intent);
}
}
複製程式碼
- 註冊資料載入結果監聽器,拿到預取到的資料
public class UserInfoActivity extends AppCompatActivity implements FetchTask.Listener<UserInfo> {
private static final String TAG = "Prefetch";
private long taskId;
private TextView tv_user_name;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_info);
tv_user_name = findViewById(R.id.tv_user_name);
taskId = getIntent().getLongExtra("taskId", 0L);
}
@Override
protected void onResume() {
super.onResume();
Prefetch.instance().registerListener(taskId, this);
}
@Override
protected void onPause() {
super.onPause();
Prefetch.instance().unregisterListener(taskId);
}
@Override
public void onExecuting() {
tv_user_name.setText(String.format("%s task executing", taskId));
}
@Override
public void onSuccess(UserInfo userInfo) {
tv_user_name.setText(userInfo.name);
Prefetch.instance().finishTask(taskId);
}
@Override
public void onError(Throwable throwable) {
tv_user_name.setText(String.format("%s task error", taskId));
Log.e(TAG, taskId + " task", throwable);
Prefetch.instance().finishTask(taskId);
}
}
複製程式碼
Custom
可以通過PrefetchConfig 來配置TaskIdGenerator 和 TaskExecutor,實現自己特殊的業務場景
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
// init Prefetch
Prefetch.instance().init(new PrefetchConfig.Builder()
.taskIdGenerator(new UUIDTaskIdGenerator())
.taskExecutor(new TestTaskExecutor())
.build());
}
}
複製程式碼
注意事項
- 一個預取任務只能執行一次,如果想重用,必須結束已經執行過的預取任務
Prefetch.instance().finishTask(taskId);
複製程式碼
- 必須正確的登出資料載入結果監聽器,否則會導致記憶體洩漏,可能會洩漏
Activity
,或其他監聽器物件持有者例項
Prefetch.instance().unregisterListener(taskId);
複製程式碼