【Android】HTTP通信での非同期処理の方法

Android 3.0以降、メインスレッドでネットワーク処理を行うとエラーにるみたいです。

メインスレッドにネットワーク処理を書いてしまうと、NetworkOnMainThreadExceptionというエラーがでてしまいます。

メインスレッドでHTTP通信を行う場合は、非同期処理をしないといけないみたいです。

そこで、

AsyncTaskLoader(非同期処理のロード)

LoaderCallback(非同期処理のコールバック)

を使用します。

AsyncTaskLoader


非同期処理(ロード)を行なうために以下ファイル(HttpAsyncTaskLoader.java)を作成します。

public class HttpAsyncTaskLoader extends AsyncTaskLoader<String> {

    /** 引数 */
    private String mArg;

    /** 非同期処理での結果を格納 */
    private String mData;

    public HttpAsyncTaskLoader(Context context, String arg) {
        super(context);
        this.mArg = arg;
    }

    @Override
    public String loadInBackground() {// 非同期処理を記述
        try {
            // 適当に時間がかかる処理
            Thread.sleep(3000);
            mData = "hoge";
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
       
        return mData;
    }

    @Override
    protected void onStartLoading() {// 非同期処理の開始前
        // ActivityまたはFragment復帰時(バックキーで戻る、ホーム画面から戻る等)に再実行されるためここで非同期処理を行うかチェック

        if (mData != null) {// 結果がnullではないは場合は既に実行済みとして非同期処理は不要
            // deliverResultで結果を送信
            deliverResult(mData);
        }

        if (takeContentChanged() || mData == null) {
            // 非同期処理を開始
            forceLoad();
        }
    }

    @Override
    protected void onStopLoading() {// Loader停止時の処理
        // 非同期処理のキャンセル
        cancelLoad();
    }

    @Override
    public void deliverResult(String data) {// 登録してあるリスナー(LoaderCallbacksを実装したクラス)に結果を送信
        if (isReset()) {// Loaderがリセット状態かどうか
            // trueの場合はLoaderがまだ一度も開始していない、resetメソッドが呼ばれている
            return;
        }

        mData = data;

        super.deliverResult(data);
    }

    @Override
    protected void onReset() {
        // reset呼び出し時、Loader破棄時の処理
        super.onReset();

        // Loaderを停止
        onStopLoading();

        // データをクリア
        mData = null;
    }
}

LoaderCallbacks


以下のコードを追加で、非同期処理の結果を受け取ることができます。

public class QuestionsAndAnswersFragment extends Fragment implements LoaderManager.LoaderCallbacks<String> {

    .
    .
    .

    private static final int LOADER_ID = 0;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        // Loaderに渡す引数
        Bundle args = new Bundle();
        args.putString("hoge", "hoge");

        // Loader初期化と開始
        getLoaderManager().initLoader(LOADER_ID, args, this);
    }

    @Override
    public Loader<String> onCreateLoader(int id, Bundle args) {// 非同期処理を行うLoaderを生成
        // getLoaderManager().initLoaderで一回のみ呼び出される

        String data = args.getString("hoge1");
        return new HttpAsyncTaskLoader(getActivity(), data);
    }

    @Override
    public void onLoadFinished(Loader<String> loader, String data) {// 非同期処理完了時
        // ここでView等にデータをセット

        // ログて返ってきた値を確認
        Log.v("tag", data);

        // Loaderを停止・破棄(次回の読み込みでもう一度initLoaderをできるようにするため)
        getLoaderManager().destroyLoader(loader.getId());// loader.getId() == LOADER_ID(initLoaderの第一引数)
    }

    @Override
    public void onLoaderReset(Loader<String> loader) {// Loaderが破棄される時に呼び出し
        // Loaderが参照しているデータを削除する
    }

    .
    .
    .

}

参考サイト:

【Android】AsyncTaskLoaderのサンプル

AsyncTaskLoaderを使ってみる | Developers.IO