資料預取小輪子

冰冰棒冰冰發表於2018-03-24

在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 來配置TaskIdGeneratorTaskExecutor,實現自己特殊的業務場景

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);
複製程式碼

相關文章