【Android】Bundleの使い方

Bundleとは


AndroidにはActivityのライフサイクルがあります。

別のActivityが前面に来るなどにして、メモリが不足した場合にActivityが破棄されることがあります。

このとき、メモリ上にだけ展開されていたインスタンス変数などの値も破棄されてしまいます。

再度呼び出されるときは、もう一度Activityを生成しなおすため、前回の状態は失われています。

そこで、前回と同じ状態に復元できるようにするために、状態を保存、復元するクラスとしてAndroidが準備してくれているのがBundleです。

簡単に言うとBundleはOSの判断で強制的に停止、終了する時に一時的にデータを格納するクラスです。

Bundleの使い方


Bundleの作成

Bundle 変数 = new Bundle();

変数.putString("キー1", "値1");
変数.putString("キー2", "値2");

値を受け取る場合

String 変数 = args.getString("キー1");
String 変数 = args.getString("キー2");

Bundleの使用例

画面遷移などでも使用できるのですが、今回は同じクラス内の異なるpublic ... { }同士で値を受け渡す処理を書きます。

public clas ... extends ... {

    @Override
    public ... {
        .
        .
        .

        Bundle args = new Bundle();// Bundleの作成

        args.putString("key1", "value1");// 渡す値をセット
        args.putString("key2", "value2");// 渡す値をセット
    }

    @Override
    public ... {
        .
        .
        .

        String getValue1 = args.getString("key1");//値の受け取り
        String getValue2 = args.getString("key2");//値の受け取り
    }

}

参考サイト:

Android - Bundle - Qiita

Thinking megane: 振る舞いのよいAndroidアプリのために。BundleSaver。

【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