2014年4月5日土曜日

[Android] なぜJava標準Threadクラスを基本的にAndroidで使用しないほうがいいのか? Loader、AsyncTaskLoader徹底解剖 番外編 Part1


おそらくそもそもLoader、AsyncTaskLoaderとは?から来た人が多いと思うので説明は不要でしょうが、
この記事はLoader、AsyncTaskLoaderについての記事の番外編です。


なぜJava標準Threadクラスを基本的にAndroidで使用しないほうがいいのか?


さて、Androidで非同期処理をする方法の1つに
Java標準のThreadクラスを使用する
というものがありますが、なぜ使用しないほうがいいのでしょう?
この方法には以下の欠点があります。
  1. AndroidにはViewを操作したい場合はUIスレッドからしか行えないという制限がある
  2. Threadクラスにはデフォルトで安全にキャンセルする方法がない
  3. Threadクラスにはデフォルトでプールがない
詳しく説明していきましょう。


AndroidにはViewを操作したい場合はUIスレッドからしか行えないという制限がある


まず、1.ですが、これはAndroid自体の制限で、Viewを操作するにはUIスレッドからしか行えない。
というルールがあります。
故に自分でスレッドを生成し、処理結果を元に自分で生成したスレッド内でViewを操作しようとすると
下記のようなエラーになります。

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

しかし、この問題に関して言えばHanderというものを使えばその問題を解決できます。

new Handler(Looper.getMainLooper()).post(new Runnable()
{
    @Override
    public void run()
    {
        //View操作のコード
    }
});

というコードを自分で生成したスレッド内に書けば
そのスレッドからUIスレッドに「こういう処理をしてね」とお願いすることができます。
ただ、2.や3.に関しては自前で頑張るしかありません。


Threadクラスにはデフォルトで安全にキャンセルする方法がない


さて、2.のキャンセルに関してですが、
Threadクラスにはぱっと見stopやsuspend、resumeというメソッドがあるので、一見できそうです。
・・・がこれらのメソッドは非推奨になっています。
これに関しては正式にわざわざアナウンスされております。

Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated?

スレッドを止める方法がないとActivityなどが破棄されスレッドの結果を受け取る先がなくなった際に、
すでに結果を返却する場所がないのに処理を続けてしまうという事になったりします。


Threadクラスにはデフォルトでプールがない


また、3.に関しては何度も何度も短いスパンで非同期処理を行うときの話ですが、
非同期処理のたびに「スレッドを生成し、処理が終了すると破棄する」という動作をさせると、
スレッドの生成や破棄のコスト(時間的にもCPUやメモリのリソース)もなかなか高くなります。
それが短い時間で何度も行われるとかなりの負荷になり得ます。
そこでうまくスレッドを再利用して無駄を減らすという仕組みをプールといいますが、
これを自前で作って管理するのもなかなか大変です。


まとめ


上記などの理由によってAndroidではThreadで非同期処理はしないほうがいいと思います。
場合によってはThreadクラスを使った方がいいケースも存在しますが、
ある程度Androidやスレッドに深い理解がないと
誤った使い方や非効率な使い方をする可能性が高いため、
基本的にはThreadクラスの使用は避けたほうが無難でしょう。

0 件のコメント:

コメントを投稿