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

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

ただいまの
回答率

88.05%

AsyncTaskスレッドからfindViewByIdを呼ぶと例外エラーになります

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,887

score 36

AndroidでJSONデータを取得し、それをListViewに表示するプログラムを組もうとしています。

AsyncTaskを使ってJSONデータの取得まではうまくいったのですが、それをメインスレッドのListViewに渡そうとすると「FATAL EXCEPTION」のエラーが出ます。ブレイクポイントで確認したところ、findViewByIdでエラーが出ているようです。

ちょっと長くなりますが、ソースは以下の通りです。

MainActivity.java

package com.example.kuma.testtabasync;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TabHost;

import java.util.ArrayList;

import static com.example.kuma.testtabasync.R.id.list01;

public class MainActivity extends AppCompatActivity {
    // バックグラウンド用
    NetworkTask task;

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

        // バックグラウンドを実行
        task = new NetworkTask(this);
        task.execute("http://nanaco.sub.jp/sample/board.json");

        // タブホストを取得
        TabHost host = (TabHost) findViewById(R.id.tabHost);
        host.setup();

        // タブ1を定義
        TabHost.TabSpec tab01 = host.newTabSpec("tag01");
        tab01.setIndicator("掲示板");
        tab01.setContent(R.id.tab01);
        host.addTab(tab01);

        // タブ2を定義
        TabHost.TabSpec tab02 = host.newTabSpec("tag02");
        tab02.setIndicator("オフ会");
        tab02.setContent(R.id.tab02);
        host.addTab(tab02);

        // タブ3を定義
        TabHost.TabSpec tab03 = host.newTabSpec("tag03");
        tab03.setIndicator("ギャラリー");
        tab03.setContent(R.id.tab03);
        host.addTab(tab03);

        // アクティブタブ
        host.setCurrentTab(0);

        /*
        // デバッグ用
        ArrayList<String> data = new ArrayList<>();
        data.add("あああ");
        data.add("いいい");
        data.add("ううう");
        getList(data);
        */
    }

    // リスト表示
    public void getList(ArrayList<String> result){
//        System.out.println(result.get(1));
        ListView list = (ListView) findViewById(list01);
        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, result);
        list.setAdapter(adapter);
    }

}


NetworkTask.java(AsyncTask)

package com.example.kuma.testtabasync;

import android.content.Context;
import android.os.AsyncTask;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;

public class NetworkTask extends AsyncTask<String, Integer, ArrayList> {

    // メインへアクセス
    MainActivity main = new MainActivity();

    // コンストラクタ
    public NetworkTask(Context context) {
        super();
    }

    // 通信用のバックグラウンドメソッド
    @Override
    protected ArrayList doInBackground(String... params) {
        // サイズ可変の変数
        StringBuilder data = new StringBuilder();
        ArrayList<String> list = new ArrayList<>();
        try {
            // 取得先のURL
            URL url = new URL(params[0]);
            // 通信オブジェクトを生成
            HttpURLConnection con = (HttpURLConnection)url.openConnection();
            // 通信メソッドを指定
            con.setRequestMethod("GET");
            // 通信オブジェクトからストリーム受信
            BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream(), "Shift-JIS"));
            String line;
            while ((line = reader.readLine()) != null){
                data.append(line);
            }
            try {
                // JSONオブジェクトを生成
                JSONArray json = new JSONArray(data.toString());
                for (int i = 0; i < json.length(); i++) {
                    JSONObject item = json.getJSONObject(i);
                    JSONObject temp = item.getJSONObject("Board");
                    String topic = temp.getString("topic");
                    list.add(topic.toString());
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    // 通信後の表示用(doInBackgroundの結果がここへ)
    @Override
    protected void onPostExecute(ArrayList result) {
        main.getList(result);
    }
}


activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tabHost"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
        </TabWidget>

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <LinearLayout
                android:id="@+id/tab01"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <ListView
                    android:id="@+id/list01"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"></ListView>

            </LinearLayout>

            <LinearLayout
                android:id="@+id/tab02"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <ListView
                    android:id="@+id/list02"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"></ListView>

            </LinearLayout>

            <LinearLayout
                android:id="@+id/tab03"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <ListView
                    android:id="@+id/list03"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"></ListView>

            </LinearLayout>
        </FrameLayout>
    </LinearLayout>
</TabHost>


MainActivityのgetList(AsyncTaskからの戻り値を表示させるメソッド)で「System.out.println(result.get(n));」とやると表示されるので、おそらくデータは来ているのだと思います。また、その上のコメントアウトしている「デバッグ用」の箇所をコメントインすると、デバッグ用の文字列が表示されます。

ちょっと調べたところ、スレッドをまたいでのUI操作は例外エラーを誘発するとのことで、とはいえどうすればいいのかわからず、困っています。

またまた基本的なところで恐縮ですが、ご教示いただけますと幸いです。
よろしくお願いいたします。

  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+2

MainActivity.javaでは、NetworkTaskのコンストラクタにMainActivityを渡しているので、そちらを使うと良いでしょう。

public class NetworkTask extends AsyncTask<String, Integer, ArrayList> {

    // メインへアクセス
    MainActivity main;

    // コンストラクタ
    public NetworkTask(MainActivity context) {
        super();
        main = context;
    }

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/09/01 18:03 編集

    ご回答、ありがとうございます。そういえば、コンストラクタ経由でMainActivityが渡されてましたね…

    ということで、以下のように修正してみました。

    // メインへアクセス
    MainActivity main;

    // コンストラクタ
    public NetworkTask(MainActivity context) {
     super();
     main = context;
    }
    (中略)
    @Override
    protected void onPostExecute(ArrayList result) {
     ListView list = (ListView) main.findViewById(list01);
     ArrayAdapter<String> adapter = new ArrayAdapter<>(
        main, android.R.layout.simple_list_item_1, result);
     list.setAdapter(adapter);
    }

    正常に動作しました!!!!!
    わかりやすいソースのご提示、本当にありがとうございます。

    まだまだ知識や理解が足らず、本当に恥ずかしい限りですが、先輩方々のアドバイスをもとにもっともっと勉強してまいりたいと思います。

    今後とも、よろしくお願いいたします!!!

    キャンセル

+2

スレッドがどうかいう問題ではありません。

Activityを継承したクラスはプログラマーがインスタンス化するものではありません。
また、インスタンス化できたとしても、そのインスタンスはAsyncTaskを起動したActivityのインスタンスとは別の物です。

コールバックの仕組みを実装して、AsyncTaskの処理の終了をActivityに通知してするようにしましょう。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/09/01 16:41

    早々のご回答、ありがとうございます。スレッドの問題じゃないんですね…
    また、インスタンス化でどうこうできるものではないとのこと、勉強になりました。Androidの基本的な仕組みや作法について理解が十分でないので、もっともっと勉強したいと思います。

    キャンセル

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

  • ただいまの回答率 88.05%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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