トップ «前の日記(2015-01-04) 最新 次の日記(2015-01-28)» 編集

Cocoa練習帳

iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど

2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|

2015-01-16 [Android]AsyncTaskとUIスレッド

AsyncTaskの仕様をよく読むと気になることが説明されている。UIスレッドで使用するという箇所だ。

Threading rulesでスレッド関連の説明がされているが、クラスのロードはUIスレッド上で。ただし、JELLY_BEANからは自動で対応している。インスタンスはUIスレッドで生成すること。

ソースを確認してみよう。Android SDKが置かれているディレクトリ配下で以下のコマンドを実行。

$ cd /Applications/Development/android-sdk-macosx
$ find . -name AsyncTask.java -print
./samples/android-19/ui/DisplayingBitmaps/DisplayingBitmapsSample/src/main/java/com/example/android/displayingbitmaps/util/AsyncTask.java
./samples/android-21/ui/DisplayingBitmaps/Application/src/main/java/com/example/android/displayingbitmaps/util/AsyncTask.java
./sources/android-19/android/os/AsyncTask.java
./sources/android-21/android/os/AsyncTask.java

Android 5.0 Lollipopのソースを確認してみよう。

public abstract class AsyncTask<Params, Progress, Result> {
        :
    private static final InternalHandler sHandler = new InternalHandler();
        :
    /** @hide Used to force static handler to be created. */
    public static void init() {
        sHandler.getLooper();
    }
        :
}

AsyncTaskのHandlerはクラス変数になっている。そして、HandlerのLooperはクラスメソッドで設定されている。つまり、最初にAsyncTaskのインスタンスを生成する際にHandlerとLooperが保持されることになる。

なぜ、HandlerとLooperが必要か?それは、onCancelledなど、UIスレッドで呼び出すことになっているメソッドがUIスレッドで呼ばれるようにする為だろう。こういうわけだ、AsyncTaskはUIスレッドで生成されることになるので、最初の生成時にUIスレッドのLooperを保持しておいて、別スレッドで処理を終えた後に、このLooperを使って、UIスレッドで結果を返す。

なので、最初のAsyncTaskの生成をUIスレッド以外で行うと、そのスレッドにLooperがない場合は、myLooperがnullの例外が発生することになる。Looperが存在しても、onCencelledなどがUIスレッドとは異なるスレッドで呼ば出されることになってしまう。

気をつけよう。著者はこれでハマった。

_ 関連情報

AsyncTask

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)

トップ «前の日記(2015-01-04) 最新 次の日記(2015-01-28)» 編集