Android AsyncTask [Невозможно создать обработчик внутри потока, который не вызвал Looper.prepare ()]

Я создал загрузку изображения AsyncTask на основе функции. И после закачки у меня onPostExecute() появляется эта ошибка. Я прочитал несколько ответов StackOverflow на Runnable, но все время получал ошибку снова и снова, несмотря на то, что реализовал другое решение.

Мой код:

class uploadFile extends AsyncTask<String, String, String> {
    private ProgressDialog pDialog;

    /**
     * --------------------------------------------------------------------
     * --------------------------------- Before starting background thread
     * Show Progress Dialog
     */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pDialog = new ProgressDialog(MainActivity.this);
        pDialog.setMessage("Uploading file");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(false);
        pDialog.show();
    }

    /**
     * --------------------------------------------------------------------
     * --------------------------------- getting all recent articles and
     * showing them in listview
     */
    @Override
    protected String doInBackground(String... args) {
        HttpURLConnection conn = null;
        DataOutputStream dos = null;
        DataInputStream inStream = null;
        String existingFileName = Environment.getExternalStorageDirectory()
                .getAbsolutePath() + "/mypic.png";
        String lineEnd = "\r\n";
        String twoHyphens = "--";
        String boundary = "*****";
        int bytesRead, bytesAvailable, bufferSize;
        byte[] buffer;
        int maxBufferSize = 1 * 1024 * 1024;
        String serverResponseMessage = "";
        String urlString = "http://google.info/imgupl/index.php";
        try {
            // ------------------ CLIENT REQUEST
            FileInputStream fileInputStream = new FileInputStream(new File(
                    existingFileName));
            // open a URL connection to the Servlet
            URL url = new URL(urlString);
            // Open a HTTP connection to the URL
            conn = (HttpURLConnection) url.openConnection();
            // Allow Inputs
            conn.setDoInput(true);
            // Allow Outputs
            conn.setDoOutput(true);
            // Don't use a cached copy.
            conn.setUseCaches(false);
            // Use a post method.
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("Content-Type",
                    "multipart/form-data;boundary=" + boundary);
            dos = new DataOutputStream(conn.getOutputStream());
            dos.writeBytes(twoHyphens + boundary + lineEnd);
            dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\""
                    + existingFileName + "\"" + lineEnd);
            dos.writeBytes(lineEnd);
            // create a buffer of maximum size
            bytesAvailable = fileInputStream.available();
            bufferSize = Math.min(bytesAvailable, maxBufferSize);
            buffer = new byte[bufferSize];
            // read file and write it into form...
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);
            while (bytesRead > 0) {
                dos.write(buffer, 0, bufferSize);
                bytesAvailable = fileInputStream.available();
                bufferSize = Math.min(bytesAvailable, maxBufferSize);
                bytesRead = fileInputStream.read(buffer, 0, bufferSize);
            }
            // send multipart form data necesssary after file data...
            dos.writeBytes(lineEnd);
            dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
            // close streams
            Integer serverResponseCode = conn.getResponseCode();
            serverResponseMessage = conn.getResponseMessage();
            Toast.makeText(getApplicationContext(), serverResponseMessage,
                    Toast.LENGTH_SHORT).show();
            Toast.makeText(getApplicationContext(),
                    serverResponseCode.toString(), Toast.LENGTH_SHORT)
                    .show();
            Log.e("Debug", "File is written");
            fileInputStream.close();
            dos.flush();
            dos.close();
        } catch (MalformedURLException ex) {
            Log.e("Debug", "error: " + ex.getMessage(), ex);
        } catch (IOException ioe) {
            Log.e("Debug", "error: " + ioe.getMessage(), ioe);
        }
        // ------------------ read the SERVER RESPONSE
        try {
            inStream = new DataInputStream(conn.getInputStream());

            while ((str = inStream.readLine()) != null) {
                Log.e("Debug", "Server Response " + str);
            }
            inStream.close();

        } catch (IOException ioex) {
            Log.e("Debug", "error: " + ioex.getMessage(), ioex);
        }
        return null;
    }

    /**
     * --------------------------------------------------------------------
     * --------------------------------- After completing background task
     * Dismiss the progress dialog
     **/
    protected void onPostExecute(String args) {
        // dismiss the dialog after getting all products
        pDialog.dismiss();
        MainActivity.this.runOnUiThread(new Runnable() {
            public void run() {
                Toast.makeText(MainActivity.this, "Hello", Toast.LENGTH_SHORT).show();
            }
        });

    }
}

Мой логарифм:

08-13 22:13:32.627: E/AndroidRuntime(9554): FATAL EXCEPTION: AsyncTask #1
08-13 22:13:32.627: E/AndroidRuntime(9554): java.lang.RuntimeException: An error occured while executing doInBackground()
08-13 22:13:32.627: E/AndroidRuntime(9554):     at android.os.AsyncTask$3.done(AsyncTask.java:200)
08-13 22:13:32.627: E/AndroidRuntime(9554):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
08-13 22:13:32.627: E/AndroidRuntime(9554):     at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
08-13 22:13:32.627: E/AndroidRuntime(9554):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
08-13 22:13:32.627: E/AndroidRuntime(9554):     at java.util.concurrent.FutureTask.run(FutureTask.java:138)
08-13 22:13:32.627: E/AndroidRuntime(9554):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
08-13 22:13:32.627: E/AndroidRuntime(9554):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
08-13 22:13:32.627: E/AndroidRuntime(9554):     at java.lang.Thread.run(Thread.java:1019)
08-13 22:13:32.627: E/AndroidRuntime(9554): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
08-13 22:13:32.627: E/AndroidRuntime(9554):     at android.os.Handler.<init>(Handler.java:121)
08-13 22:13:32.627: E/AndroidRuntime(9554):     at android.widget.Toast.<init>(Toast.java:68)
08-13 22:13:32.627: E/AndroidRuntime(9554):     at android.widget.Toast.makeText(Toast.java:231)
08-13 22:13:32.627: E/AndroidRuntime(9554):     at dev.google.imageupload.MainActivity$uploadFile.doInBackground(MainActivity.java:128)
08-13 22:13:32.627: E/AndroidRuntime(9554):     at dev.google.imageupload.MainActivity$uploadFile.doInBackground(MainActivity.java:1)
08-13 22:13:32.627: E/AndroidRuntime(9554):     at android.os.AsyncTask$2.call(AsyncTask.java:185)
08-13 22:13:32.627: E/AndroidRuntime(9554):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
08-13 22:13:32.627: E/AndroidRuntime(9554):     ... 4 more

ИЗМЕНИТЬ после предложения zapl:

08-13 22:38:06.297: E/AndroidRuntime(11511): FATAL EXCEPTION: AsyncTask #1
08-13 22:38:06.297: E/AndroidRuntime(11511): java.lang.RuntimeException: An error occured while executing doInBackground()
08-13 22:38:06.297: E/AndroidRuntime(11511):    at android.os.AsyncTask$3.done(AsyncTask.java:200)
08-13 22:38:06.297: E/AndroidRuntime(11511):    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
08-13 22:38:06.297: E/AndroidRuntime(11511):    at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
08-13 22:38:06.297: E/AndroidRuntime(11511):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
08-13 22:38:06.297: E/AndroidRuntime(11511):    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
08-13 22:38:06.297: E/AndroidRuntime(11511):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
08-13 22:38:06.297: E/AndroidRuntime(11511):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
08-13 22:38:06.297: E/AndroidRuntime(11511):    at java.lang.Thread.run(Thread.java:1019)
08-13 22:38:06.297: E/AndroidRuntime(11511): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
08-13 22:38:06.297: E/AndroidRuntime(11511):    at android.os.Handler.<init>(Handler.java:121)
08-13 22:38:06.297: E/AndroidRuntime(11511):    at android.widget.Toast.<init>(Toast.java:68)
08-13 22:38:06.297: E/AndroidRuntime(11511):    at android.widget.Toast.makeText(Toast.java:231)
08-13 22:38:06.297: E/AndroidRuntime(11511):    at dev.google.imageupload.MainActivity$uploadFile.doInBackground(MainActivity.java:128)
08-13 22:38:06.297: E/AndroidRuntime(11511):    at dev.google.imageupload.MainActivity$uploadFile.doInBackground(MainActivity.java:1)
08-13 22:38:06.297: E/AndroidRuntime(11511):    at android.os.AsyncTask$2.call(AsyncTask.java:185)
08-13 22:38:06.297: E/AndroidRuntime(11511):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
08-13 22:38:06.297: E/AndroidRuntime(11511):    ... 4 more

person MrYanDao    schedule 13.08.2012    source источник
comment
просто создайте Toast прямо в onPostExecute, поскольку он уже выполняется в потоке пользовательского интерфейса. AsyncTasks могут выполняться только из потока пользовательского интерфейса, и эти onSomthing методы будут снова вызываться из потока пользовательского интерфейса.   -  person zapl    schedule 13.08.2012
comment
Удалите runOnUiThread, и это вызвало еще одну проблему :(   -  person MrYanDao    schedule 13.08.2012
comment
Поделитесь новой проблемой: D. А также позвольте мне узнать, что вы хотите делать после того, как ваше фото будет загружено.   -  person Code_Life    schedule 13.08.2012
comment
Я отредактировал свой основной пост. Спасибо ^^ О, я думаю, что смогу завершить остальную часть проекта после этого, потому что я сохраняю ответ сервера в строке, которую я могу использовать позже. Мне просто нужно сначала исправить эту ошибку :(   -  person MrYanDao    schedule 13.08.2012
comment
Создайте класс обработчика и используйте его для перехода в AsyncTask и вызова обработчика ... У вас может быть конструктор в AsyncTask с обработчиком в качестве параметра и из doInBackground вызвать обработчик с постоянным значением, чтобы указать показ тоста, который будет запускать в потоке пользовательского интерфейса - намного чище и проще :)   -  person t0mm13b    schedule 13.08.2012
comment
Это также может произойти, если одна AsyncTask вызывает другую AsyncTask.   -  person Stephen McCormick    schedule 28.11.2018


Ответы (2)


Вы пытаетесь обновить пользовательский интерфейс из фонового потока. Либо переместите тост в onPostExecute, который выполняется в потоке пользовательского интерфейса (рекомендуется), либо вызовите runOnUiThread.

runOnUiThread(new Runnable() {
    public void run() {
        // runs on UI thread
    }
});
person Tyler Treat    schedule 13.08.2012
comment
Правильно (в этом нет необходимости), но у вас также есть два Toast вызова в doInBackground, что вызывает исключение. - person Tyler Treat; 13.08.2012
comment
Так вы хотите сказать, что у меня не может быть Toast в doInBackground? Извините, я здесь нуб :( извините! ИЗМЕНИТЬ, я думаю, я понял. Подождите ... - person MrYanDao; 13.08.2012
comment
Вы можете, но они должны быть в runOnUiThread, чтобы быть в doInBackground. - person Tyler Treat; 13.08.2012
comment
МОЙ БОГ! Большое вам спасибо (': мне удалось решить проблемы. Кстати, я хочу знать, почему у меня не может быть Toast в doInBackground. Я имею в виду, что пока код запущен, почему нельзя использовать Toast? - person MrYanDao; 13.08.2012
comment
Пожалуйста! Toast - это операция пользовательского интерфейса, и пользовательский интерфейс не может быть обновлен непосредственно фоновым потоком, поэтому требуется runOnUiThread. Отметьте это как принятый ответ, если он решил вашу проблему. - person Tyler Treat; 13.08.2012
comment
Большое спасибо! Извините, я только изучаю Java! Спасибо и отметили! - person MrYanDao; 13.08.2012
comment
Большое спасибо. Это решение моей проблемы;) - person Marco Seiz; 16.11.2012

в dev.shaunidiot.imageupload.MainActivity $ uploadFile.doInBackground (MainActivity.java:128)

Вы можете использовать механизм выполнения AsyncTasks для обновления пользовательского интерфейса изнутри doInBackground во время выполнения задачи:

заменять

Toast.makeText(getApplicationContext(), serverResponseMessage,
        Toast.LENGTH_SHORT).show();
Toast.makeText(getApplicationContext(),
        serverResponseCode.toString(), Toast.LENGTH_SHORT)
        .show();

в doInBackground с

publishProgress(serverResponseMessage, serverResponseCode.toString());

и добавьте следующее в свою AsyncTask реализацию

@Override
protected void onProgressUpdate(String... values) {
    if (values != null) {
        for (String value : values) {
            // shows a toast for every value we get
            Toast.makeText(MainActivity.this, value, Toast.LENGTH_SHORT).show();
        }
    }
}

Вы уже установили String в качестве типа прогресса в AsyncTask<Params, Progress, Result>, поэтому, если вы хотите использовать прогресс для чего-то другого, вы можете попробовать использовать runOnUiThread, но я не знаю, сработает ли это.

person zapl    schedule 13.08.2012