AndroidはUIのthread上でネットワーク通信を行おうとすると、エラーが発生してしまいます.その他、時間のかかる処理もUI threadで実行すべきではありません.
これらの場合の実装方法を紹介します.
UI threadとは、ActivityやFragmentの処理を実行しているthreadです.
基本的にこのthread上で処理を行っていくのですが、ネットワーク通信をはじめとする重い処理はこのthread上で実行できません.
これは、その処理中画面が固まってしまい、ユーザビリティが低下するためです.
別threadで処理を実行する簡単な方法は以下のようになります.
1 2 3 4 5 6 7 |
new Thread(new Runnable() { @Override public void run() { //重い処理の実行 } }) {}.start(); |
普通のJavaと同じですね.
別Thread単体で処理が完結する場合はこの実装でいいのですが、大抵は処理結果を画面に表示したいかと思います.
このような場合に、単純にCallback用のクラスを作成してrunの中で実行してもうまくいきません.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public static class Callback { public void call() { //画面に結果を返す処理 } } public void asyncProcess(Callback callback) { new Thread(new Runnable() { @Override public void run() { //重い処理の実行 callback.call(); //ここで実行しても正常に機能しない } }) {}.start(); |
このように非同期処理(別Threadで行う処理)結果を画面に戻したい場合は、
AsyncTaskを利用します.
AsyncTackはGenericsを用いて1.処理を行う時に呼び出し元から渡す引数の型、2.処理の進捗を表す型、3.処理結果の型を定義します.
具体的な実装は以下のようになります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
private class TestTask extends AsyncTask<String, Integer, Long> { protected Long doInBackground(String... strings) { //引数は同じ型であれば、複数渡すことが可能. //配列になっているので、strings[0]のように取得する //非同期で行いたい処理はここで } protected void onProgressUpdate(Integer... progress) { //進捗率を表示したい場合はここで } protected void onPostExecute(Long result) { //処理結果を画面で利用したい場合はここで } } // 画面側は以下のように処理を実装する private void executeAsyncTask() { AsyncTask<String, Integer, Long> testTask = new TestTask(); String inputParam = "foo"; testTask.executes(inputParam); } |
注意点としては、一度実行したAsyncTaskインスタンスを再実行することはできないので、都度newする必要があります.
ちなみに、android.os.Handlerを用いれば、通常のThreadでもUIに結果を戻すことができます.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Handler handler = new Handler(); Thread t = new Thread() { @Override public void run() { // 非同期で行いたい処理をここに記載 handler.post(new Runnable() { @Override public void run() { // ここで画面に戻す処理を記載 } }); } }; t.start(); |