質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.37%

  • Android

    6988questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

【Android】非同期処理後にページ遷移をしたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 4,731

GH_usami13

score 16

【10月6日質問編集】

おこなっていることは、
dialogfragmentでonClickをすると非同期処理をおこない、 
非同期処理が終了したら
Activityの遷移をおこなっております。

しかし、fragmentで非同期処理をおこなうと、
Activityとの接続が切れて
新たなActivityを呼ぼうとした時に
getActivityがnullになってしまい、
遷移できずにエラーになってしまいます。 

dialogfragmentで処理しているコードが下記になります。
public class AnnotationDialogFragment extends DialogFragment {

    public String name;
    public String snippet;
    Context context;

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        int index = snippet.indexOf(":");
        final String id = snippet.substring(0, index);
        snippet = snippet.substring(index + 1);

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle(name);
        builder.setMessage(snippet);
        builder.setPositiveButton(R.string.detail, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(final DialogInterface dialog, int which) {
                AsyncDetail asyncDetail = new AsyncDetail(new AsyncTaskCallback() {
                    @Override
                    public void postExecute(String result) {     //この時点でgetActivityはnull
                        Intent intent = new Intent(getActivity() , DetailActivity.class);
                        intent.setClassName("パッケージ名", "パッケージ名.DetailActivity");
                        intent.putExtra("result", result);
                        startActivity(intent);
                    }
                } );
                asyncDetail.execute("URL", id);
            }
        });
        builder.setNegativeButton(R.string.close, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub
            }
        });
        return builder.create();
    }

非同期処理をおこなうAsyncTaskを継承したクラスが下記になります。
public class AsyncDetail extends AsyncTask<String, Integer, String> {

    public AsyncTaskCallback callback = null;

    public AsyncDetail(AsyncTaskCallback _callback) {
        this.callback = _callback;
    }

    private HttpClient hClient = new DefaultHttpClient();

    // バックグラウンドで処理
    @Override
    protected String doInBackground(String... params) {
        String uri = params[0];
        int id = Integer.parseInt( params[1] );
        return PostLocations(uri, id);
    }

    // バックグラウンド処理が終了した後にメインスレッドに渡す処理
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        this.callback.postExecute(result);
    }

    // 位置情報(JSON)をダウンロード
    private String PostLocations(String uri, int id) {
        try {
            HttpPost post = new HttpPost(uri);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", id);
            StringEntity se = new StringEntity(jsonObject.toString(), "UTF-8");
            post.setHeader("Accept", "application/json");
            post.setHeader("Content-Type", "application/json");
            post.setEntity(se);
            HttpResponse resp = hClient.execute(post);

            if (resp.getStatusLine().getStatusCode() < 400) {
                String str = EntityUtils.toString(resp.getEntity(), HTTP.UTF_8);
                return str;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}

コールバックインターフェースを下記に記します。
public interface AsyncTaskCallback {
    void postExecute(String result);
}

非同期処理をさせてもActivityを保持させていられるやり方か、
新たにActivityを生成させるやり方を知りたいです。

また、これらの書き方はよくないということでありましたら、
どんな方法が良いのかお教えいただけますと幸いです。

皆様のお力添えのほど、よろしくお願い致します。
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

遷移後のアクティビティを呼び出せていないから起こる
コードを見るに、遷移先のアクティビティは関係ないと思います。

例外が発生しているのはAsyncDetailの以下の部分です。
protected void onPreExecute() {
    super.onPreExecute();
    this.callback.preExecute();    // ココ
}
エラー内容は、このcallbacknullだったため、preExecuteを実行できなかった、という意味です。

理由は上記の通りですが、何故nullなのかは
public void onClick(DialogInterface dialog, int which) {
    AsyncDetail asyncTask = new AsyncDetail(this);
    asyncTask.execute("URL", id);
    getActivity().finish();
}
public AsyncDetail(android.content.DialogInterface.OnClickListener onClickListener) {
    // TODO Auto-generated constructor stub
    hClient = new DefaultHttpClient();
}
この2つの部分に原因があると思われます。

上の部分で、new AsyncDetail(this);と記述していますが、このthisAsyncTaskCallbackを実装していますか?
恐らく実装していないのではないでしょうか?
しかし、下の部分のコンストラクタがあるためコンパイルエラーにはならず、結果、ビルドはできる状態になったのだと思います。


そもそも、
ダイアログでonClickすることで非同期処理をおこない、  
非同期処理が終了したら、 
新たなアクティビティで処理後の内容を出力したいです。 
この目的とコードがチグハグです。
質問文のコードでは、遷移前と遷移後、どちらでも非同期処理を行おうとしています。

遷移前に、非同期処理を行い、非同期処理が終了したら遷移。
@Override
public void onClick(DialogInterface dialog, int which) {
    AsyncDetail asyncTask = new AsyncDetail(new AsyncTaskCallback() {
        public void postExecute(String result) {
            Intent intent = new Intent(getApplicationContext(), DetailActivity.class);
            intent.putExtra("RESULT", result);
            startActivity(intent);
        }
        // 他 略
    });
    asyncTask.execute("URL", id);
    getActivity().finish();
}
遷移後にデータを表示。
public class DetailActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);

        Intent intent = getIntent();
        String result = intent.getStringExtra("RESULT");
        // 出力処理など
    }
}
目的にそうとしたら、大まかなコードですが、こんな感じになるのではないでしょうか。


AsyncDetailにも怪しいコードがありますが、質問内容とは離れるため、ひとまずはノータッチです。すいません。



2015/10/4 追記
例外のスタックトレースが無いので、推測になってしまいますが、原因は以下の部分かもしれません。
public void onClick(DialogInterface dialog, int which) {
    AsyncDetail asyncDetail = new AsyncDetail(new AsyncTaskCallback() {
        @Override
        public void postExecute(String result) {
            Intent intent = new Intent(getActivity(), DetailActivity.class);    // ココ
            intent.putExtra("result", result);
            startActivity(intent);
        }
    });
    getActivity().finish();        // ココ
    asyncDetail.execute("URL", id);
}

非同期処理開始前に、Activityをfinishしているのに、非同期処理完了時に、getActivity()でActivityを取得しようとしています。
getActivity().finish();を非同期処理完了時に実行するか、別の方法でContextを取得してみてください。




Fragmentのコードを確認したところ、Fragment#startActivity(Intent)はFragment自身が設置されているActivityのActivity#startActivity()を呼ぶような処理をしています。
なので、Fragment#startActivity(Intent)を呼ぶ前に、設置されているActivityのAcitivity#finish()呼んでしまった場合、Activity#startActivity()が呼び出せなくなるのだと思います。
実際のソースコードでは呼ぶ前にnullチェックをしており、nullの場合に件の例外を投げるようになっていました。

ですので、上に書いたように、getActivity().finish();を非同期処理完了時に実行するのがいいと思います。



getActivity().finish();postExecute内に移してみてください。

public void onClick(DialogInterface dialog, int which) {
    AsyncDetail asyncDetail = new AsyncDetail(new AsyncTaskCallback() {
        @Override
        public void postExecute(String result) {
            Intent intent = new Intent(getActivity(), DetailActivity.class);
            intent.putExtra("result", result);
            startActivity(intent);
            getActivity().finish();    // ここに移す
        }
    });
    // getActivity().finish();
    asyncDetail.execute("URL", id);
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/04 18:43

    ご回答有り難うございます。

    half_sleepingさんのおっしゃられるように
    認識がだいぶおかしかったようです。

    改めて、コードを改変して色々と実行してみたのですが、
    違ったエラーで苦戦してしまいました。

    よろしければご教授のほど、
    よろしくお願いいたします。

    キャンセル

  • 2015/10/04 21:30 編集

    追加の回答ありがとうございます。
    もうしわけございません。
    元のコードに少々誤りがございました。
    Intentのインスタンスを生成するときに
    contextを第一引数としていましたが、
    Contextの生成のコードを載せておりませんでした。

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

    builder.setPositiveButton(R.string.detail, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
    AsyncDetail asyncDetail = new AsyncDetail(new AsyncTaskCallback() {

    @Override
    public void postExecute(String result) {
    Intent intent = new Intent(context , DetailActivity.class);
    intent.putExtra("result", result);
    startActivity(intent);
    }
    });
    getActivity().finish();
    asyncDetail.execute("URL", id);
    }
    })
    return builder.create();
    }

    //ここを書き忘れておりました
    @Override
    public void onAttach(Activity activity){
    super.onAttach(activity);
    context = activity;
    }

    また、スタックトレースは以下のようになっております。

    java.lang.IllegalStateException: Fragment AnnotationDialogFragment{206bef1d} not attached to Activity
    W/System.err﹕ at android.app.Fragment.startActivity(Fragment.java:1068)
    W/System.err﹕ at android.app.Fragment.startActivity(Fragment.java:1054)
    W/System.err﹕ at パッケージ名.AnnotationDialogFragment$2$1.postExecute(AnnotationDialogFragment.java:41) //startActivity(intent)
    W/System.err﹕ at パッケージ名.AsyncDetail.onPostExecute(AsyncDetail.java:36)
    W/System.err﹕ at パッケージ名.AsyncDetail.onPostExecute(AsyncDetail.java:15)
    W/System.err﹕ at android.os.AsyncTask.finish(AsyncTask.java:636)
    W/System.err﹕ at android.os.AsyncTask.access$500(AsyncTask.java:177)
    W/System.err﹕ at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:653)
    W/System.err﹕ at android.os.Handler.dispatchMessage(Handler.java:102)
    10-04 21:17:23.422 2701-2701/com.example.mac_gusami.pr_sample0917 W/System.err﹕ at android.os.Looper.loop(Looper.java:135)
    W/System.err﹕ at android.app.ActivityThread.main(ActivityThread.java:5254)
    W/System.err﹕ at java.lang.reflect.Method.invoke(Native Method)
    W/System.err﹕ at java.lang.reflect.Method.invoke(Method.java:372)
    W/System.err﹕ at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
    W/System.err﹕ at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

    デバッグをしてみても、
    contextにMapsActivityが格納されており、
    MapsActivityからDetailActivityに遷移するという認識です。

    よろしくお願いいたします。

    キャンセル

  • 2015/10/07 02:51

    ご丁寧に解説していただきありがとうございます。
    非同期処理をおこなった瞬間、FragmantとActivityとの接続が切れてしまって、
    非同期処理後にActivityを呼ぼうと思っても、
    getActivity()がnullになってしまい、
    前回のコメントで記載したようなエラーになってしまうようですね。

    どうにかActivityを保持させて非同期処理後にそのActivityから新しいActivity(DetailActivity)へ遷移できないものかと調べてはいるのですが、
    half_sleepingさんがおっしゃられるように、
    非同期処理後にgetActivity().finish();おこなう方法がわかりませんでした。

    大変ご迷惑おかけしますが、
    もう少し具体的にお教えいただくことは可能でしょうか?

    また、他の方法をとった方がよろしいのでしょうか?
    (例)AsyncTaskLoader

    何卒よろしくお願いいたします。

    キャンセル

  • 2015/10/07 16:36

    コメントありがとうございます。

    getActivity().finish();
    をそちらに記載しても変わらず、startActivity(intent)でエラーになってしまいます。

    非同期処理を開始した時点でActivityとFragmentが破棄されてしまい、
    postExecute()に返ってきた時には
    どことも接続がされていない状態のようです。

    非同期前にActivityを保持させて、
    非同期処理後に保持させてあるActivityを呼び出して
    という処理を
    http://www.garunimo.com/program/p17.xhtml
    等でおこなったのですが、
    同じ結果となってしまいました。

    キャンセル

  • 2015/10/07 18:00

    今回は、setPositiveButtonのclick時には
    画面遷移の処理はおこなわず、
    非同期処理だけおこない、
    元のActivity側で画面遷移の処理をおこなったら
    期待した処理ができました。

    この度は、長々とお付き合いいただきありがとうございました。

    キャンセル

同じタグがついた質問を見る

  • Android

    6988questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。