在Android开发中,预取数据可以说是一个比较通用的功能,通过预取数据可以有效的减少用户等待的时间,提升用户体验,是一种常见的以空间换取时间的策略。虽然说预取数据这个功能比较好实现,但一直没有发现一个好用的开源库实现,于是自己花了点时间写了一个,尽量做到简单优雅、轻量和侵入性低
Prefetch
一个通用的数据预取库
- 简单优雅、轻量和侵入性低
- 如果之前使用
RxJava
,那么完全可以重用之前的数据加载逻辑
预览
Gradle依赖
1 | implementation 'com.tubb:prefetch:1.1.0' |
如何使用
- 先要继承 FetchTask 类, 定义好数据加载任务,可以看到
execute()
方法返回的是RxJava
中的Obserable
类型,默认的执行线程为Schedulers.io()
,执行结果通知线程为AndroidSchedulers.mainThread()
,当然这两者都可以通过覆写相应的方法来指定1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class UserInfoFetchTask extends FetchTask<UserInfo> {
public Observable<UserInfo> execute() {
return Observable.create(new ObservableOnSubscribe<UserInfo>() {
public void subscribe(ObservableEmitter<UserInfo> emitter) throws Exception {
// just for test
Thread.sleep(5000);
UserInfo userInfo = new UserInfo();
userInfo.name = "BingBing";
emitter.onNext(userInfo);
}
});
}
}
1 | protected Scheduler subscribeOnScheduler() { |
然后就可以执行定义好的任务,框架会帮你生成一个
taskId
,作为任务的唯一标识,后续注册数据加载结果监听器要指定对应的taskId
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class MainActivity extends AppCompatActivity {
private long taskId;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
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);
}
}注册数据加载结果监听器,拿到预取到的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43public class UserInfoActivity extends AppCompatActivity implements FetchTask.Listener<UserInfo> {
private static final String TAG = "Prefetch";
private long taskId;
private TextView tv_user_name;
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);
}
protected void onResume() {
super.onResume();
Prefetch.instance().registerListener(taskId, this);
}
protected void onPause() {
super.onPause();
Prefetch.instance().unregisterListener(taskId);
}
public void onExecuting() {
tv_user_name.setText(String.format("%s task executing", taskId));
}
public void onSuccess(UserInfo userInfo) {
tv_user_name.setText(userInfo.name);
Prefetch.instance().finishTask(taskId);
}
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,实现自己特殊的业务场景1
2
3
4
5
6
7
8
9
10
11public class App extends Application {
public void onCreate() {
super.onCreate();
// init Prefetch
Prefetch.instance().init(new PrefetchConfig.Builder()
.taskIdGenerator(new UUIDTaskIdGenerator())
.taskExecutor(new TestTaskExecutor())
.build());
}
}
注意事项
一个预取任务只能执行一次,如果想重用,必须结束已经执行过的预取任务
1
Prefetch.instance().finishTask(taskId);
必须正确的注销数据加载结果监听器,否则会导致内存泄漏,可能会泄漏
Activity
,或其他监听器对象持有者实例1
Prefetch.instance().unregisterListener(taskId);