昨天去福州XX公司面試,上機題。
題目: 實現 計數從0開始 每秒增加10 回調到Activity 中顯示,加到100停止。要求用單例實現,綁定Activity生命周期。
還有一題是listview的相關,單選,考慮性能更新指定item,現在都用Recyclerview,還做listview干嘛。。。
ps:本文寫的是rxjava的實現
考慮了如下幾種實現方式:
1.Timer TimeTask 實現計時 這是java的方法
但更新UI還得用Handler 或者RunOnUIThread才行(不太好用的感覺,和方法2一樣)
2.Handler 或者View 的postDelayRunnable (面試上機測試,我就用了這個吃力不討好的方法)
可以直接在主線程跟新UI
3.CountDownTimer 最簡單的實現方法 也在主線程調用,但只是除了時間差一點外,使用起來方便簡單
看日志Thread[main,5,main]--1955--1 10秒倒計時有接近45ms的誤差
Thread[main,5,main]--1842--1 100秒就有將近147秒的誤差
CountDownTimer timer=new CountDownTimer(10000,1000) {
@Override
public void onTick(long millisUntilFinished) {
Log.i(TAG, "onTick: "+Thread.currentThread()+"--"+millisUntilFinished+"--"+millisUntilFinished/1000);
}
@Override
public void onFinish() {
}
};
timer.start();
4.RxJava interval實現
1.使用
//觀察者
observer = new CounManager.MyObserver<Long>() {
@Override
public void onNext(@NonNull Long aLong) {
tv.setText(aLong + "時間間隔" + (System.currentTimeMillis() - last));
Log.i(TAG, "onNext: "+(System.currentTimeMillis() - last));
last = System.currentTimeMillis();
}
@Override
public void onComplete() {
Toast.makeText(MainActivity.this, "計數完成", 0).show();
d.dispose();
}
};
//啟動計時
CounManager.getInstance()
.setmax(998)
.setStep(10)
.setStart(5)
.setListener(observer)
.startCount();
RxUtils.StrictClick(tv)
.subscribe(aVoid -> {
CounManager.getInstance().startCount();
Log.i(TAG, "onCreate: " + Thread.currentThread());
});
}
@Override
protected void onPause() {
super.onPause();
//暫停
CounManager.getInstance().stop();
}
@Override
protected void onResume() {
super.onResume();
//繼續
CounManager.getInstance().startCount();
}
@Override
protected void onDestroy() {
super.onDestroy();
//重置
CounManager.getInstance().destory();
}
2.代碼
public class CounManager {
public static final String TAG = "CounManager";
MyObserver<Long> consumer;
private int startcount = 0;
private int tempstart = 0;
private int step = 1;
private int max = 100;
public synchronized CounManager startCount() {
//沒有設置observer返回
if (consumer == null)
return this;
//已經啟動了任務,沒有結束
if(consumer.d!=null&&!consumer.d.isDisposed())
return this;
Observable.interval(0, 1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.take(getCount())
.map(a -> startcount + step * a)
.doOnNext(aLong -> tempstart = aLong.intValue())
.doOnComplete(() -> {
startcount = 0;
tempstart = 0;
})
.doOnDispose(() -> {
startcount = tempstart;
tempstart = 0;
})
.map(a -> a > max ? max : a)
.subscribe(consumer);
return this;
}
public CounManager stop() {
if (consumer != null && !consumer.d.isDisposed())
consumer.d.dispose();
return this;
}
public CounManager destory() {
if (!consumer.d.isDisposed())
consumer.d.dispose();
reset();
return this;
}
private void reset() {
startcount=0;
tempstart=0;
max=100;
step=1;
consumer.d = null;
consumer = null;
}
/**
* 屬性配置
* @return
*/
private int getCount() {
return (max - startcount) / step + ((max - startcount) % step == 0 ? 0 : 1) + 1;
}
public CounManager setStart(int startcount) {
this.startcount = startcount;
return this;
}
public CounManager setmax(int max) {
this.max = max;
return this;
}
public CounManager setListener(MyObserver<Long> ab) {
this.consumer = ab;
return this;
}
public CounManager setStep(int step) {
this.step = step;
return this;
}
/**
* 單例子
*
* @return
*/
private CounManager(){ }
public static CounManager getInstance() {
return SingleHolder.counManager;
}
private static class SingleHolder {
private static CounManager counManager = new CounManager();
}
/**
* observer
* @param <T>
*/
public static abstract class MyObserver<T> implements Observer<T> {
public Disposable d;
@Override
public void onSubscribe(@NonNull Disposable d) {
this.d = d;
}
@Override
public void onError(@NonNull Throwable e) {
Log.i(TAG, "onError: " + e.getMessage());
}
}
}
github 地址
個人總結:CountDownTimer 實現最簡單 ,按倒計時,每秒加10。
其他方法都挺復雜的
而且我還選了一個看起來簡單卻挺復雜的方法
不知道還有沒有更好的方法,請告知,繼續等了通知,haha。