24365
お世話になっております。  
[前回](https://ja.stackoverflow.com/questions/24293/twitter4j%E3%81%A7%E8%A4%87%E6%95%B0%E7%94%BB%E5%83%8F%E3%82%92%E6%8A%95%E7%A8%BF%E3%81%97%E3%81%9F%E3%81%84%E3%81%AE%E3%81%A7%E3%81%99%E3%81%8C-%E4%B8%80%E5%BA%A6%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E5%8F%96%E5%BE%97%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%81%AB%E3%82%82%E3%81%8B%E3%81%8B%E3%82%8F%E3%82%89%E3%81%9A%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%8C%E3%81%AA%E3%81%84%E3%81%A8%E8%A8%80%E3%82%8F%E3%82%8C%E3%81%BE%E3%81%99%E3%81%A9%E3%81%AE%E3%82%88%E3%81%86%E3%81%AB%E3%81%97%E3%81%9F%E3%82%89%E3%82%88%E3%82%8D%E3%81%97%E3%81%84%E3%81%A7%E3%81%97%E3%82%87%E3%81%86%E3%81%8B)の質問では回答有難うございました。  
無事、複数枚画像の投稿にすることが成功しました。  
今回はその続きで、投稿はできているものの、`Caused by: java.lang.RuntimeException: Can't create
handler inside thread that has not called
Looper.prepare()`がログキャトに出力されておりアプリが強制終了します。  
ツイート自体は成功しているのですが、アプリが落ちてしまい困り果てました。  
何かいい解決策はないでしょうか？ご教示願います。

```

    public class TweetActivity extends Activity {
    
    private EditText mInputText;
    private Twitter mTwitter;
    private Button mGazou;
    private ImageView imageView,imageView2,imageView3,imageView4;
    private Boolean gazou=false;
    UploadedMedia media1=null;
    UploadedMedia media2=null;
    UploadedMedia media3=null;
    UploadedMedia media4=null;
    int k =0;
    Uri[] multi_uri=null;
    Uri uri = null;
    InputStream in;
    long[]mediaIds = null;
    long media_id =0;
    
    private static final int RESULT_PICK_IMAGEFILE = 1001;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.new_tweet);
    
        mTwitter = TwitterUtils.getTwitterInstance(this);
        //Twitter文字入力
        mInputText = (EditText) findViewById(R.id.input_text);
        //Twitter画像選択（ギャラリーから）
        mGazou = (Button)findViewById(R.id.button1);
        mGazou.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
    
                Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
                intent.addCategory(Intent.CATEGORY_OPENABLE);
                intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
                intent.setType("image/*");
    
                startActivityForResult(intent, RESULT_PICK_IMAGEFILE);
            }
        });
    
        findViewById(R.id.action_tweet).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //tweet();
            }
        });
    }
    
    @Override
    public void onActivityResult(int requestCode, int resultCode,final Intent resultData) {
    
        if (requestCode != RESULT_PICK_IMAGEFILE || resultCode != RESULT_OK) {
            return;
        }
    
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                try {
                    //mTwitterはOAuth認可済みであるとする
                    String message = "画像テストじゃおりゃぁぁぁぁぁぁぁぁ！！！！！！！！";
                    ClipData clipData = resultData.getClipData();
    
    
                    if(clipData!=null){
                        mediaIds = new long[clipData.getItemCount()];
                        for (int i = 0, length = clipData.getItemCount(); i < length; i++) {
                             ClipData.Item item = clipData.getItemAt(i);
                             mediaIds[i] = (mTwitter.uploadMedia(String.format("[filename_%d]", i + 1), getContentResolver().openInputStream(item.getUri())).getMediaId());
                        }
    
                    }else{
                           Log.i("flag", "１枚通過");
                                uri = resultData.getData();
                                Log.i("flag", uri.toString());
                                mediaIds = new long[1];
                                mediaIds[0] =(mTwitter.uploadMedia(String.format("[filename_%d]",1), getContentResolver().openInputStream(uri)).getMediaId());
                                Log.i("flag", String.valueOf(mediaIds[0]));
                    }
                             StatusUpdate update = new StatusUpdate(message);
                             update.setMediaIds(mediaIds);
                             mTwitter.updateStatus(update);
                             showToast("投稿できました！");
    
    
    
    
                } catch (TwitterException e) {
                    e.printStackTrace();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }.execute();
     }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.new_tweet_menu, menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        switch (item.getItemId()) {
            case R.id.menu_not:
                Intent intent = new Intent(this, MainActivity.class);
                startActivity(intent);
                finish();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }
    
    
    
    
    
    /* private void tweet() {
            AsyncTask<String, Void, Boolean> task = new AsyncTask<String, Void, Boolean>() {
                @Override
                protected Boolean doInBackground(String... params) {
    
                    try {
    
                        //画像アップロード
                        if(gazou==true){
    
                            if(k>0){
                                mediaIds = new long[k];
                            }else if(k==0){
                                mediaIds=new long[1];
                            }
    
                            StatusUpdate update = new StatusUpdate(params[0]);
                            switch(k){
                                case 0:
                                    try {
                                        media1 = mTwitter.uploadMedia(new File(getPath(TweetActivity.this,uri)));
                                        mediaIds[0]=media1.getMediaId();
    
    
                                    } catch (TwitterException e) {
                                        // TODO 自動生成された catch ブロック
                                        e.printStackTrace();
                                    }
                                    break;
    
                                case 2:
                                    try {
                                        media1 = mTwitter.uploadMedia(new File(getPath(TweetActivity.this,multi_uri[0])));
                                        media2 = mTwitter.uploadMedia(new File(getPath(TweetActivity.this,multi_uri[1])));
                                        mediaIds[0]=media1.getMediaId();
                                        mediaIds[1]=media2.getMediaId();
                                    } catch (TwitterException e) {
                                        // TODO 自動生成された catch ブロック
                                        e.printStackTrace();
                                    }
                                    break;
                                case 3:
                                    try {
                                        media1 = mTwitter.uploadMedia(new File(getPath(TweetActivity.this,multi_uri[0])));
                                        media2 = mTwitter.uploadMedia(new File(getPath(TweetActivity.this,multi_uri[1])));
                                        media3 = mTwitter.uploadMedia(new File(getPath(TweetActivity.this,multi_uri[2])));
                                        mediaIds[0]=media1.getMediaId();
                                        mediaIds[1]=media2.getMediaId();
                                        mediaIds[2]=media3.getMediaId();
                                    } catch (TwitterException e) {
                                        // TODO 自動生成された catch ブロック
                                        e.printStackTrace();
                                    }
                                    break;
                                case 4:
    
                                    try {
                                        media1 = mTwitter.uploadMedia(new File(getPath(TweetActivity.this,multi_uri[0])));
                                        media2 = mTwitter.uploadMedia(new File(getPath(TweetActivity.this,multi_uri[1])));
                                        media3 = mTwitter.uploadMedia(new File(getPath(TweetActivity.this,multi_uri[2])));
                                        media4 = mTwitter.uploadMedia(new File(getPath(TweetActivity.this,multi_uri[3])));
                                        mediaIds[0]=media1.getMediaId();
                                        mediaIds[1]=media2.getMediaId();
                                        mediaIds[2]=media3.getMediaId();
                                        mediaIds[3]=media4.getMediaId();
                                    } catch (TwitterException e) {
                                        // TODO 自動生成された catch ブロック
                                        e.printStackTrace();
    
                                    }
                                    break;
                            }
                            Log.i("ImageCount", "画像選択枚数："+String.valueOf(k));
                            Log.i("ImageTAG", mediaIds.toString());
                            update.setMediaIds(mediaIds);
                            mTwitter.updateStatus(update);
                        }else{
                            mTwitter.updateStatus(params[0]);
                        }
    
                        return true;
                    } catch (TwitterException e) {
                        e.printStackTrace();
                        return false;
                    }
                }
    
                @Override
                protected void onPostExecute(Boolean result) {
                    if (result) {
                        showToast("ツイートが完了しました！");
                        showToast("×ボタンを押して元の画面に戻ってね");
                        mInputText.setText("");
    
                    } else {
                        showToast("ツイートに失敗しました。。。");
                    }
                }
            };
            task.execute(mInputText.getText().toString());
        }*/
    
        private void showToast(String text) {
            Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
        }
    
    }
    
```

# ログキャット

```

    04-26 07:44:57.408: E/AndroidRuntime(4995): FATAL EXCEPTION: AsyncTask #4
    04-26 07:44:57.408: E/AndroidRuntime(4995): Process: android.example.shutwitter, PID: 4995
    04-26 07:44:57.408: E/AndroidRuntime(4995): java.lang.RuntimeException: An error occured while executing doInBackground()
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at android.os.AsyncTask$3.done(AsyncTask.java:300)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at java.util.concurrent.FutureTask.run(FutureTask.java:242)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at java.lang.Thread.run(Thread.java:818)
    04-26 07:44:57.408: E/AndroidRuntime(4995): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at android.os.Handler.<init>(Handler.java:200)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at android.os.Handler.<init>(Handler.java:114)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at android.widget.Toast$TN.<init>(Toast.java:336)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at android.widget.Toast.<init>(Toast.java:100)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at android.widget.Toast.makeText(Toast.java:250)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at android.example.shutwitter.TweetActivity.showToast(TweetActivity.java:253)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at android.example.shutwitter.TweetActivity.access$1(TweetActivity.java:252)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at android.example.shutwitter.TweetActivity$3.doInBackground(TweetActivity.java:111)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at android.example.shutwitter.TweetActivity$3.doInBackground(TweetActivity.java:1)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at android.os.AsyncTask$2.call(AsyncTask.java:288)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    04-26 07:44:57.408: E/AndroidRuntime(4995):     ... 4 more
    
```
CC BY-SA 3.0
2016-04-26T12:10:30.613
24363
2016-04-26T16:37:05.587
2017-04-13T12:52:39.113
-1
15276
question
android twitter twitter4j
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()の原因は？
`Toast`を含めたUIの処理は、UIスレッド（メインスレッドとも呼ばれます）で行われています。

対して、[`AsyncTask`](http://developer.android.com/intl/ja/reference/android/os/AsyncTask.html)は非同期処理を行うクラスのため、別のスレッドにて動作しています。このエラーは`doInBackground()`内から、直接`Toast`の表示（＝UIスレッドへの操作）はできないということを意味しています。

より厳密に説明するならば、バックグラウンドスレッドからUIスレッドへ、`Handler`クラスを用いてスレッド間の通信を行おうとしているのですが、バックグラウンドスレッドのイベントループが回っていない（[`Looper#prepare()`](http://developer.android.com/intl/ja/reference/android/os/Looper.html)がコールされていない）ので、メッセージが送れないため、この例外が発生します。

解決策としては、`AsyncTask`にはUIスレッドへ処理の進捗や結果を表示するための、コールバックメソッドが用意されていますので、そちらを利用すると良いと思います。

例えば、ツイートが成功した、という情報が必要であれば、`AsyncTask`の型パラメータ（`<Void, Void,
Void>`の部分）のうち、最後の型パラメータを`Boolean`にして、`doInBackground()`で結果の成否を返すようにします。

`doInBackground()`の返り値で`onPostExecute()`が呼び出されます。このコールバックメソッド内ではUIスレッドにアクセスできますので、成否に応じて`Toast`を表示することができます。

```

    new AsyncTask<Void, Void, Boolean>() {
        @Override
        protected Boolean doInBackground(Void... params) {
            try {
               // 省略
               mTwitter.updateStatus(update);
    
            } catch (TwitterException e) {
                return false;
            } catch (FileNotFoundException e) {
                return false;
            }
            return true;
        }
    
        @Override
        protected void onPostExecute(Boolean result) {
            if(result) {
                showToast("投稿に成功しました");
            } else {
                showToast("投稿に失敗しました");
            }
        }
    }.execute();
    
```
CC BY-SA 3.0
2016-04-26T13:36:58.620
24365
2016-04-26T13:36:58.620
5337
24363
answer