Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> bolts全收集流程攻略解析

bolts全收集流程攻略解析

編輯:關於Android編程

bolts簡介及使用教程:

bolts是Parse被FaceBook收購後開源的一個工具庫組合,

Parse聲稱,與Android" target="_blank">Android AsyncTask和iOS NSOperation相比,Tasks有若干優勢,其中包括:

l連續執行數個任務不會像只使用回調函數時那樣創建嵌套的“金字塔(pyramid)”代碼。

lTasks是完全可組合的,允許開發人員執行分支、並行和復雜的錯誤處理。

l開發人員可以按照執行順序安排基於任務的代碼,而不必將邏輯分解到分散的回調函數中。

github地址 https://github.com/BoltsFramework/Bolts-Android

疑似官方解釋:http://gold.xitu.io/entry/55cdcca040ac79db35731770

我們先來看一下如何使用

gradle下加入

dependencies {
compile 'com.parse.bolts:bolts-android:1.2.0'
}

 

代碼裡面使用:

Task.call(new Callable() {
    @Override
    public Boolean call() throws Exception {
        // 處理一些具體的動作
        return false;
    }
}, Task.BACKGROUND_EXECUTOR);

 

第一個參數是一個Callable,conCurrent包的,常與線程池、Future搭配使用。

這裡有兩個線程可以供我們使用Task.UI_THREAD_EXECUTOR、Task.BACKGROUND_EXECUTOR,不傳這個參數的話默認為Task.IMMEDIATE_EXECUTOR,也就是在當前線程下執行。

如果只是這麼簡單的話我們用個線程池也可以,沒必要搞這麼多,下面我們來看看進階用法,這個call方法會返回生成的Task對象,我們可以繼續對這個對象進行處理

Task.continueWith(new Continuation() {
@Override
public String then(Task task) throws Exception {
return null;
}
})

這個api可謂是簡單易懂,無論這個Task成功或者失敗,這個Continuation都能接受到結果並進行你的處理,最重要的是,會返回一個新的Task,你可以在後面再接一個continueWith();然後實現無限續杯,這比RxJava的使用map來轉換不知道高到哪裡去了。

當然,還要學習一個:

task.onSuccess(new Continuation() {
    @Override
    public Object then(Task task) throws Exception {
        return null;
    }
});

這個onSuccess方法只有Task被成功執行並且沒有報錯的情況下才會被調用,也就是說,Task內部幫我們處理了(其實只是簡單的把報錯信息封裝起來)運行時可能出現的各種錯誤,這樣我們就只會在一切正常的情況下調用我們的代碼,以防出現各種奇怪的錯誤。

還要再學習一個:

task.continueWhile(new Callable() {
    @Override
    public Boolean call() throws Exception {
        return null;
    }
}, new Continuation>() {
    @Override
    public Task then(Task task) throws Exception {
        return null;
    }
});

continueWhile這個方法需要兩個參數,一個是Callable,要求返回Boolean值,表示你的任務是否被成功執行,如果成功執行,會調用接下來的另一個參數Continuation。

接下來我們要搞個大新聞:

task.continueWithTask(new Continuation>() {
    @Override
    public Task then(Task task) throws Exception {
        return null;
    }
});

continueWithTask這個方法用起來就麻煩啦,使用的時候泛型參數一定要返回一個Task對象,否則內部會報錯,至於為什麼我們等下源碼分析再說。

那這個方法干什麼用的呢?你調用continueWithTask 返回的Task_A會在Continuation裡面你自己返回的Task_B完成之後完成,這個方法解決了金字塔嵌套問題。

以上這四個方法都可以選擇線程Task.UI_THREAD_EXECUTOR、Task.BACKGROUND_EXECUTOR,不傳這個參數的話默認為Task.IMMEDIATE_EXECUTOR。

那麼接下來我們來講一下bolts的源代碼

在開始之前要提一下CancellationToken,這個參數,目前來說這個參數並沒有用上,我們也不可以在包外訪問這個類,在bolts內部是傳null進行參數填充的,並且在源碼中也不會被用到,可能會在後面的版本更新中派上用場,以下內容不會對該類再進行解釋,也不會提及指定了該參數的傳參方法。

從Task.Call開始講吧

public static  Task call(final Callable callable) {
  return call(callable, IMMEDIATE_EXECUTOR, null);
}
 
public static  Task call(final Callable callable, Executor executor){
  return call(callable, executor, null);
}
 
public static  Task callInBackground(Callable callable) {
  return call(callable, BACKGROUND_EXECUTOR, null);
}
//上面這三個方法都會調用到下面這個,我們只需要看這個就好了
public static  Task call(final Callable callable, Executor executor,
    final CancellationToken ct) {
//這個TaskCompletionSource是一個包裝類,構造方法內實例化了一個Task,裡面所有//的setXXXX方法都會調用到所持有的Task本身的trySetXXXX方法,這種trySet方法//會返回一個boolean值表示是否執行成功,如果沒有成功,TaskCompletionSource會拋//出一個IllegalStateException異常。
  final bolts.TaskCompletionSource tcs = new bolts.TaskCompletionSource<>();
  try {
    executor.execute(new Runnable() {
      @Override
      public void run() {
//這裡ct 必定為null,不用管
        if (ct != null && ct.isCancellationRequested()) {
          tcs.setCancelled();
          return;
        }

        try {
          tcs.setResult(callable.call());
        } catch (CancellationException e) {
          tcs.setCancelled();
        } catch (Exception e) {
          tcs.setError(e);
        }
      }
    });
  } catch (Exception e) {
    tcs.setError(new ExecutorException(e));
  }
//返回內部task實例
  return tcs.getTask();
}

通過指定的Exeutor在特定線程執行一個Runnable,並調用我們所傳進來的callable的call方法,並返回已經設置了結果的task。

那麼我們來看看設置結果的方法,這三個方法都不能從包外部訪問:

/**
 * Sets the cancelled flag on the Task if the Task hasn't already been completed.
 */
/* package */ boolean trySetCancelled() {
  synchronized (lock) {
    if (complete) {
      return false;
    }
    complete = true;
    cancelled = true;
    lock.notifyAll();
    runContinuations();
    return true;
  }
}

/**
 * Sets the result on the Task if the Task hasn't already been completed.
 */
/* package */ boolean trySetResult(TResult result) {
  synchronized (lock) {
    if (complete) {
      return false;
    }
    complete = true;
    Task.this.result = result;
    lock.notifyAll();
    runContinuations();
    return true;
  }
}

/**
 * Sets the error on the Task if the Task hasn't already been completed.
 */
/* package */ boolean trySetError(Exception error) {
  synchronized (lock) {
    if (complete) {
      return false;
    }
    complete = true;
    Task.this.error = error;
    errorHasBeenObserved = false;
    lock.notifyAll();
    runContinuations();
//這個UnobservedExceptionHandler是我們自己設置的異常處理器,沒設就不用管下面這一句了
    if (!errorHasBeenObserved && getUnobservedExceptionHandler() != null)
      unobservedErrorNotifier = new UnobservedErrorNotifier(this);
    return true;
  }
}

上面這三個方法就是剛剛說過的trySetXXXX系列方法,基本上都是大同小異,首先判斷任務是否已經結束,false就讓TaskCompletionSource拋異常,true則設置complete 狀態,並且解開lock對象鎖,設置結果還是設置異常信息就不解釋了。

我們來看一下這個共同調用的runContinuations()方法

private void runContinuations() {
//對象鎖
  synchronized (lock) {
    for (Continuation continuation : continuations) {
      try {
//這裡傳入task
        continuation.then(this);
      } catch (RuntimeException e) {
        throw e;
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
    continuations = null;
  }
}

上面所遍歷的continuations是一個ArrayList對象,當我們調用continueWith等方法時會往裡面塞Continuation,這個也沒什麼好說的。

我們繼續說下一個

Task.continueWith
public  Task continueWith(
    Continuation continuation) {
  return continueWith(continuation, IMMEDIATE_EXECUTOR, null);
}
 
public  Task continueWith(
    final Continuation continuation, final Executor executor) {
  return continueWith(continuation, executor, null);
}
//上面兩個會調用下面這個
public  Task continueWith(
    final Continuation continuation, final Executor executor,
    final CancellationToken ct) {
  boolean completed;
  final bolts.TaskCompletionSource tcs = new bolts.TaskCompletionSource<>();
//同步鎖
  synchronized (lock) {
    completed = this.isCompleted();
    if (!completed) {
//往列表裡面加東西,當任務完成時遍歷此列表並調用then()方法
      this.continuations.add(new Continuation() {
        @Override
        public Void then(Task task) {
          completeImmediately(tcs, continuation, task, executor, ct);
          return null;
        }
      });
    }
  }
  if (completed) {
    completeImmediately(tcs, continuation, this, executor, ct);
  }
  return tcs.getTask();
}

上面判斷了一下任務是否已經完成,視情況調用completeImmediately()方法

private static  void completeImmediately(
    final bolts.TaskCompletionSource tcs,
    final Continuation continuation, final Task task,
    Executor executor, final CancellationToken ct) {
  try {
    executor.execute(new Runnable() {
      @Override
      public void run() {
//這裡ct 必定為null,不用管
        if (ct != null && ct.isCancellationRequested()) {
          tcs.setCancelled();
          return;
        }

        try {
//這裡跟上面Call()方法中調用callable.call()差不多
          TContinuationResult result = continuation.then(task);
          tcs.setResult(result);
        } catch (CancellationException e) {
          tcs.setCancelled();
        } catch (Exception e) {
          tcs.setError(e);
        }
      }
    });
  } catch (Exception e) {
    tcs.setError(new ExecutorException(e));
  }
}

這個方法裡面給傳進來的tcs設置了一個結果,然後在continueWith()方法的最後取出該tcs的task實例返回給調用者。

接下來這個就有點麻煩了

continueWithTask:

 

public  Task continueWithTask(
    Continuation> continuation) {
  return continueWithTask(continuation, IMMEDIATE_EXECUTOR, null);
}
 
public  Task continueWithTask(
    final Continuation> continuation, final Executor executor) {
  return continueWithTask(continuation, executor, null);
}
 
public  Task continueWithTask(
    final Continuation> continuation, final Executor executor,
    final CancellationToken ct) {
  boolean completed;
  final bolts.TaskCompletionSource tcs = new bolts.TaskCompletionSource<>();
  synchronized (lock) {
    completed = this.isCompleted();
    if (!completed) {
      this.continuations.add(new Continuation() {
        @Override
        public Void then(Task task) {
          completeAfterTask(tcs, continuation, task, executor, ct);
          return null;
        }
      });
    }
  }
  if (completed) {
    completeAfterTask(tcs, continuation, this, executor, ct);
  }
  return tcs.getTask();
}

這個跟上面提到的continueWith結構相同,只是最後調用的complete方法有所差別

我們先來解釋一下這個思路:

我們調用Task.call()獲得一個taskA,然後調用taskA.continueWithTask()獲得返回的taskB,然後再continueWithTask方法中我們會傳進去一個返回結果為Task的taskC對象,taskB會在taskC完成之後再setResult

private static  void completeAfterTask(
    final bolts.TaskCompletionSource tcs,
    final Continuation> continuation,
    final Task task, final Executor executor,
    final CancellationToken ct) {
  try {
    executor.execute(new Runnable() {
      @Override
      public void run() {
//這裡ct 必定為null,不用管
        if (ct != null && ct.isCancellationRequested()) {
          tcs.setCancelled();
          return;
        }

        try {
//這裡這個result就是我們說的taskC,tcs裡面的Task實例就是taskB,並且會返回taskB給調用者
          Task result = continuation.then(task);
          if (result == null) {
            tcs.setResult(null);
          } else {
            result.continueWith(new Continuation() {
              @Override
              public Void then(Task task) {
                if (ct != null && ct.isCancellationRequested()) {
                  tcs.setCancelled();
                  return null;
                }

                if (task.isCancelled()) {
                  tcs.setCancelled();
                } else if (task.isFaulted()) {
                  tcs.setError(task.getError());
                } else {
                  tcs.setResult(task.getResult());
                }
                return null;
              }
            });
          }
        } catch (CancellationException e) {
          tcs.setCancelled();
        } catch (Exception e) {
          tcs.setError(e);
        }
      }
    });
  } catch (Exception e) {
    tcs.setError(new ExecutorException(e));
  }
}

除了上面注釋所說的還有一點要注意的是,taskB會將taskC的結果作為自己的結果,也就是多嵌套了一層而已。

onSuccessTask

 

public  Task onSuccessTask(
    final Continuation> continuation) {
  return onSuccessTask(continuation, IMMEDIATE_EXECUTOR);
}
 
public  Task onSuccessTask(
    final Continuation> continuation, Executor executor) {
  return onSuccessTask(continuation, executor, null);
}
 
public  Task onSuccessTask(
    final Continuation> continuation, Executor executor,
    final CancellationToken ct) {
  return continueWithTask(new Continuation>() {
    @Override
    public Task then(Task task) {
      if (ct != null && ct.isCancellationRequested()) {
        return Task.cancelled();
      }

      if (task.isFaulted()) {
        return Task.forError(task.getError());
      } else if (task.isCancelled()) {
        return Task.cancelled();
      } else {
        return task.continueWithTask(continuation);
      }
    }
  }, executor);
}

我們可以從源代碼看出,taskA調用了continueWithTask傳入一個匿名continuation得到taskB,在taskA正常的、無報錯,即成功的狀態下,taskA會調用continueWithTask(),此時傳入一開始我們傳進來的continuation,然後再執行我們所期望的操作。此時return一個taskC,taskC的結果為我們的continuation返回的taskD的結果。

接下來是continueWhile:

public Task continueWhile(Callable predicate,
    Continuation> continuation) {
  return continueWhile(predicate, continuation, IMMEDIATE_EXECUTOR, null);
}
 
public Task continueWhile(final Callable predicate,
    final Continuation> continuation, final Executor executor) {
  return continueWhile(predicate, continuation, executor, null);
}
//上面兩個調用下面這個
public Task continueWhile(final Callable predicate,
    final Continuation> continuation, final Executor executor,
    final CancellationToken ct) {
  final Capture>> predicateContinuation =
      new Capture<>();
  predicateContinuation.set(new Continuation>() {
    @Override
    public Task then(Task task) throws Exception {
//這裡ct 必定為null,不用管
      if (ct != null && ct.isCancellationRequested()) {
        return Task.cancelled();
      }

      if (predicate.call()) {
        return Task. forResult(null).onSuccessTask(continuation, executor)
            .onSuccessTask(predicateContinuation.get(), executor);
      }
//返回一個一個已經結束且result為null的task
      return Task.forResult(null);
    }
  });
//此時makeVoid()會調用Task.forResult(null)
  return makeVoid().continueWithTask(predicateContinuation.get(), executor);
}

這段代碼中我們可以直接閱讀最後的return語句,這個時候就調用到了我們之前講的continueWithTask,

而Capture是一個簡單的類,可以臨時存儲一個泛型變量,這次的predicateContinuation則存儲了一個返回值類型為Tsak的Continuation對象。

調用continueWhile之後我們獲取了一個taskA,這個taskA會在Continuation返回的taskB結束後結束,並將taskB的結果作為自己的結果,而taskB是第n行中ruturn的。我們把這一行中使用Task. forResult(null)獲取的task稱為taskC,taskC調用onSuccessTask()傳入我們的continuation,返回一個我們處理並獲取結果的taskD,此時taskD調用onSuccessTask(),這樣會形成循環,所以使用的時候一定要注意predicate別直接返回true了,一定要有可觸發的false返回,否則你程序就得跪了。

接下來是onSuccess():

public  Task onSuccess(
    final Continuation continuation) {
  return onSuccess(continuation, IMMEDIATE_EXECUTOR, null);
}
 
public  Task onSuccess(
    final Continuation continuation, Executor executor) {
  return onSuccess(continuation, executor, null);
}
//上面兩個調用下面這個
public  Task onSuccess(
    final Continuation continuation, Executor executor,
    final CancellationToken ct) {
  return continueWithTask(new Continuation>() {
    @Override
    public Task then(Task task) {
      if (ct != null && ct.isCancellationRequested()) {
        return Task.cancelled();
      }

      if (task.isFaulted()) {
        return Task.forError(task.getError());
      } else if (task.isCancelled()) {
        return Task.cancelled();
      } else {
        return task.continueWith(continuation);
      }
    }
  }, executor);
}

這個跟onSuccessTask差不多,成功的時候執行一個continuation而已,沒什麼特別需要解釋的。

到這裡,Task的api和相應的源碼解釋就差不多完成了,下面說一些零散的使用技巧

1、當你需要一個task來調用某些方法時可以使用Tsak.forResult(null)來獲取一個實例,或者直接使用new Task(null)來獲取一個實例。

2、多使用xxxxxTask方法來避免金字塔代碼堆疊

3、有需要可以自己傳一個異常處理器進去處理你可能出現的異常

4、多注意一下傳入的處理線程是否正確,否則是要搞出個大新聞的。

 

照例沒圖

做了一點微小的工作,謝謝

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved