Androidにおける通信処理の整理

Androidにおいて,通信処理はUIスレッドとは別のスレッドで
非同期に実行する必要があるので,
必然的にandroid.os.AsyncTaskを使うことになると思う.

リファレンスは下記のとおり.
AsyncTask | Android Developers

実装サンプルは下記のような感じ.
自作アプリの該当クラスから余計な要素を削除したんだけど,
そのせいで動作しなくなっているかもしれない.

package jp.nk5.sampleapp;

import java.net.HttpURLConnection;
import java.net.URL;
import android.os.AsyncTask;

public class TestAsyncTask extends AsyncTask<Void, Void, Boolean> {

  private ConnectCallbackListener listener;

  /*
   * コンストラクタ.リスナーの実装クラスのインスタンスを格納する.
   */
  public TestAsyncTask(ConnectCallbackListener listener)
  {
    this.listener = listener; //(3)
  }

  /*
   * バックグラウンド処理.インターネットにアクセスして
   * その成否を返す.
   */
  @Override
  protected Boolean doInBackground(Void... params) //(5)
  {
    return internetAccess();
  }

  /*
   * 終了処理.リスナーの実装クラスに格納されている
   * updateUIメソッドを実行する.
   */
  @Override
  protected void onPostExecute(Boolean result) //(6)
  {
    if (listener != null)
    {
      listener.updateUI(result); //(7)
    }
  }

  /*
   * ただインターネットにアクセスするだけの処理.
   */
  private boolean internetAccess()
  {
    HttpURLConnection connection = null;
    // 接続の確立
    try
    {
      URL url = new URL("http://hogehoge/");
			             
      // 接続用HttpURLConnectionオブジェクト作成
      connection = (HttpURLConnection)url.openConnection();
      connection.setRequestMethod("GET");
      // 接続
      connection.connect();
    }
    catch (Exception e)
    {
      return false;
    }
    return true;
  }
}

コンストラクタや事後処理で登場しているConnectCallbackListenerは,
下記のようなインターフェース.

package jp.nk5.sampleapp;

public interface ConnectCallbackListener {
    /*
     * 非同期タスクの事後に実行される描画処理.
     */
    public void updateUI(boolean result);
}

実装クラスは,AsyncTaskを呼び出すActivityとなる.
つまり,以下のような感じ.

package jp.nk5.sampleapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class AccessActivity extends Activity implements ConnectCallbackListener {

  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_access);
  }

  /*
   * ボタンビュー押下時のイベント.通信処理を非同期で実施する.
   * ビューとの紐づけはlayoutのXMLに記述している(今回は略).
   */
  public void onClickConnectButton(View view) //(1)
  {
    //非同期処理として通信処理を実行.
    new TestAsyncTask(this).execute(); //(2)(4)
  }

  /*
   * 非同期通信処理の事後処理.結果を画面に通知する.
   */
  @Override
  public void updateUI(boolean result) //(7)
  {
    if (result == true)
    {
      Toast.makeText(this, "成功!", Toast.LENGTH_SHORT).show();
    }
    else
    {
      Toast.makeText(this, "失敗", Toast.LENGTH_SHORT).show();
    }
  }
}

処理の流れとしては複雑だけど以下.

(1) AccessActivityのonClickConnectButton()が実行される.
(2) 非同期タスクのTestAsyncTaskのインスタンスが作成される.
(3) そのときに引数としてAcessActivityへの参照が渡される.
(4) execute()で非同期タスクが実行される.
  ※ここでonClickConnectButton()としての処理は終了する.
(5) 裏側でTestAsyncTaskのdoInBackground()処理が実行される.
(6) 裏側でonPostExecute()処理が実行される.
(7) 手順(3)でAccessActivityへの参照が渡されているので,
AccessActivityに実装したupdateUI()処理が実行される.


「描画処理はActivity」「通信処理はAsyncTask」と,
役割分担を明確にするために,今回はインターフェースを用意しているけれど,
トースト表示処理くらいなら,AsyncTaskに直書きでも良いと思う.

ちなみにこれ,ボタンを連打することで
非同期タスクが終了する前に新たな非同期タスクが生成可能なので,
実装としてはよろしくなかったりする.
非同期タスク実行中は,ボタンを非活性にするなど,
細かな制御を行うことを忘れずに.