1. 程式人生 > >Android有用的任務管理器—tractor

Android有用的任務管理器—tractor

star 用戶體驗 keyword 針對 ++ 限制 esp clear 方便

在平時的android開發工作中,我們常常須要運行耗時操作,有時為了用戶體驗還須要顯示個等待框,我之前的做法都是開一個線程,然後用handler發消息進行顯示和關閉等待框以及相關的ui操作。假設任務比較多的話,頻繁的new Thread會讓代碼看上去比較混亂,並且還不好管理,針對這樣的情況我寫了tractor。

tractor基本的作用有:
1. 代碼變得整潔。不用在到處new Thread和new Handler。
2. 能夠監控任務的運行情況,能夠隨時取消一個或多個任務;
3. 封裝了okhttp。支持大文件上傳,多線程斷點下載。get,post以及其它的網絡請求

效果圖

技術分享

使用說明

類圖

結構事實上非常easy。沒有多少東西。
技術分享

普通任務

//當LoadListenerImpl構造函數傳入context,則顯示progressdialog
 doNormalTask(new LoadListenerImpl(this) {
          @Override
          public void onStart(Object result) {
                  super.onStart(result);
                  setMessage("任務開始運行");
          }

          @Override
public void onSuccess(Object result) { super.onSuccess(result); String response = (String) result; setMessage("任務結束"); } @Override public void onFail(Object result) { super.onFail(result); String response = (String) result; setMessage(response); } @Override
public void onLoading(Object result) { super.onLoading(result); //以後不用寫handler了,這樣就能夠處理了 int response = (int) result; switch (response) { case 1: setMessage("正在運行 response=" + response); break; case 2: setMessage("正在運行 response=" + response); break; case 3: setMessage("正在運行 response=" + response); break; default: break; } } @Override public void onCancel(Object result) { super.onCancel(result); setMessage("任務被取消了"); } @Override public void onCancelClick() { super.onCancelClick(); TaskPool.getInstance().cancelTask(MainActivity.this); } }, this);

在上面的代碼塊中,LoadListenerImpl是LoadListener的實現類,用於監聽任務載入的整個過程,使用LoadListenerImpl而不是LoadListener的優點有兩點:
1.能夠不實現全部的方法,僅僅要依據自己的須要來實現對應的方法即可了;‘
2.LoadListenerImpl中能夠管理ProgressDialog。ProgressDialog能夠用tractor中自帶的,也能夠自定義。
LoadListenerImpl 部分源代碼:

public class LoadListenerImpl implements LoadListener {
    private WeakReference<Context> context;
    private ProgressDialog mProgressDialog;
    private String mMessage = "載入中...";
    private long mDismissTime = 500;

    /**
     * 不顯示progressdialog
     */
    public LoadListenerImpl() {
    }

    /**
     * 顯示progressdialog。其上顯示的文字是默認的
     * @param context
     */
    public LoadListenerImpl(Context context) {
        init(context, null);
    }

    /**
     * 顯示progressdialog,其上顯示的文字是message
     * @param context
     * @param message
     */
    public LoadListenerImpl(Context context, String message) {
        init(context, message);
    }
    /**
     * 設置自定義的progressdialog,假設不設置則使用tractor自帶的
     * @param progressDialog
     */
    public void setProgressDialog(ProgressDialog progressDialog) {
        mProgressDialog = progressDialog;
    }
    ......
}

當然了,你也能夠自己實現LoadListener。畢竟是面向接口編程。


doNarmalTask方法的詳細實現

 /**
     * 發起個普通的任務
     *
     * @param listener
     * @param tag
     */
    public void doNormalTask(LoadListener listener, Object tag) {
        TaskPool.getInstance().execute(new Task(tag, listener) {
            @Override
            public void onRun() {
                SystemClock.sleep(500);
                notifyLoading(1);
                SystemClock.sleep(500);
                notifyLoading(2);
                SystemClock.sleep(500);
                notifyLoading(3);
                SystemClock.sleep(500);
                Random random = new Random();
                //任務是模擬的,所以隨機下
                if (random.nextBoolean()) {
                //notifySuccess(null);
                } else {
                    notifyFail("糟糕,任務失敗了");
                }
            }

            @Override
            public void cancelTask() {

            }
        });
    }

TaskPool.getInstance().execute()方法終於是把task交由線程池來運行。TaskPool僅僅負責加入和取消任務。接下來說Task,在上面的類圖中有說明,Task是實現了Runnable接口,並重寫run(),所以線程池能夠運行Task,我們看下run()方法是怎麽實現的:

public abstract class Task implements Runnable {
    ......
    @Override
    public final void run() {
        start();
        onRun();
        finish();
    }
     ......
     private void start() {
      notifyStart(null);
       ......
    }
    /**
     * 實現這種方法來運行詳細的任務
     */
    public abstract void onRun();
    private void finish() {
        if (isRunning()) {
            // 默認載入成功
            mStatus = Status.SUCCESS;
            notifySuccess(null);
        }
        clear();
    }

run()中分別運行了start(),onRun()和finish(),start()方法中調用了notifyStart(null),finish()中調用了notifySuccess(null),也就是說在開始的時候會通知ui線程任務開始,結束的時候默認通知ui線程任務結束。

onRun()是抽象方法,是給任務調用者來實現運行詳細的任務的。在運行的過程中能夠通過notifyLoading(result)來通知ui任務的進度。notifySuccess(result)和notifyFail(result)通知ui任務成功和失敗,並把須要的數據result作為參數傳給ui線程。

至於Task中的cancelTask()放到後面取消任務的時候再說。

超時任務

 doTimeoutTask(500, new LoadListenerImpl() {
                    @Override
                    public void onStart(Object result) {
                        super.onStart(result);
                        toast("超時任務開始運行");
                    }

                    @Override
                    public void onSuccess(Object result) {
                        super.onSuccess(result);
                        toast("超時任務運行成功");
                    }

                    @Override
                    public void onTimeout(Object result) {
                        super.onTimeout(result);
                        toast("任務超時");
                    }
                }, this);
  .......
  public void doTimeoutTask(long timeout, LoadListener listener, Object tag) {
        TaskPool.getInstance().execute(new Task(timeout, tag, listener) {
            @Override
            public void onRun() {
                SystemClock.sleep(1000);
            }

            @Override
            public void cancelTask() {

            }
        });
    }

能夠看到。超時任務相較於普通任務來說僅僅是Task構造函數多了個timeout參數。這個timeout參數的含義就是任務運行的時間限制。假設超過這個限制就回調onTimeout()方法。

取消任務

在平時的開發過程中,有時開了一個超耗時的操作,在耗時操作未返回的時候頁面就被關閉了。當頁面關閉以後耗時操作才有了返回,這時候須要操作控件的話就有可能會報null或者其它的一些異常,為了避免異常,我們通常須要進行一些頁面是否處於激活狀態的推斷,但是這樣總是非常麻煩的。tractor攻克了這個問題,能夠調用取消任務的方法,就像這樣:

//取消任務的方法,參數能夠是任務的tag,也能夠是task。假設是tag,則取消tag相關的全部任務。是task則取消指定的task。
//能夠在onDestroy()中調用
TaskPool.getInstance().cancelTask(tag|task);

這樣調用以後會調用notifyCancel(null),在ui上顯示給用戶任務已取消的效果,tractor有個特性:當任務有結果時(已經取消,超時,成功和失敗),興許的notifyXXX()就都不會通知到ui線程了,所以假設任務在運行取消任務代碼以後,當任務有結果返回的時候。ui回調也不會被運行。那麽上面說的那個問題也就不存在了,就省的自己去加推斷了。


前面也有提到,取消任務的代碼僅僅能在保證ui上有取消的效果,但是任務實際上還是在運行的。盡管用戶看不到但是資源還是在損耗,所以還不行。
從類圖中能看到Task有onRun()和cancelTask()兩個抽象方法,onRun()是運行詳細任務的,cancelTask()則是運行詳細的取消任務的操作。他是在非ui線程中運行的。詳細怎麽停止任務是由你來決定的。

網絡請求部分

為了讓任務管理器看起來更實用些。我封裝了網絡框架,實現是okhttp,能夠支持head,get,post,多線程下載,大文件上傳以及其它一些http請求。因為是面向接口編程,所以假設以後有更合適的庫,能夠非常方便的就換掉okhttp。這部分的樣例我就不貼出來了,感興趣能夠自己看代碼,非常easy,代碼全在demo module的MainActivity裏。


下載:
技術分享
上傳打文件:
技術分享

最後

假設你有什麽問題和建議能夠留言或者給我發郵件。tractor是托管在github上,點擊此處獲取源代碼。歡迎star or follow!

Android有用的任務管理器—tractor