android.os.NetworkOnMainThreadException: рефакторинг кода для использования AsyncTask?

1

Я получаю сообщение об ошибке: android.os.NetworkOnMainThreadException, я знаю, что исправление заключается в том, чтобы запустить мой код в AsnycTask.

Я не знаю, как реорганизовать следующий код для использования AsnycTask? Могу ли я сделать все это в одном activity?

public class MainActivity extends AppCompatActivity {

    @Bind(R.id.tvTitle)
    TextView title;
    @Bind(R.id.etName)
    EditText name;
    @Bind(R.id.etEmail)
    EditText email;
    @Bind(R.id.etIdea)
    EditText idea;
    @Bind(R.id.btnSubmit)
    Button submit;

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

        submit.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                //get input from editText boxes to send to php file on server
                String  toSubmit = name.getText().toString() + " " + email.getText().toString() + " " + idea.getText().toString();

                try{
                    getData(toSubmit);
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        });
    }

    public static InputStream toInputStream(String input, String encoding) throws IOException {
        byte[] bytes = encoding != null ? input.getBytes(encoding) : input.getBytes();
        return new ByteArrayInputStream(bytes);
    }

    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;

    public static long copyLarge(InputStream input, OutputStream output)
            throws IOException {
        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
        long count = 0;
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
            count += n;
        }
        return count;
    }

    public static int copy(InputStream input, OutputStream output) throws IOException {
        long count = copyLarge(input, output);
        if (count > Integer.MAX_VALUE) {
            return -1;
        }
        return (int) count;
    }

    String getData(String postData) throws IOException {
        StringBuilder respData = new StringBuilder();
        URL url = new URL("MY_URL");
        URLConnection conn = url.openConnection();
        HttpURLConnection httpUrlConnection = (HttpURLConnection) conn;

        httpUrlConnection.setUseCaches(false);
        httpUrlConnection.setRequestProperty("User-Agent", "YourApp"); 
        httpUrlConnection.setConnectTimeout(30000);
        httpUrlConnection.setReadTimeout(30000);

        httpUrlConnection.setRequestMethod("POST");
        httpUrlConnection.setDoOutput(true);

        OutputStream os = httpUrlConnection.getOutputStream();
        InputStream postStream = toInputStream(postData, "UTF-8");
        try {
            copy(postStream, os);
        } finally {
            postStream.close();
            os.flush();
            os.close();
        }

        httpUrlConnection.connect();

        int responseCode = httpUrlConnection.getResponseCode();

        if (200 == responseCode) {
            InputStream is = httpUrlConnection.getInputStream();
            InputStreamReader isr = null;
            try {
                isr = new InputStreamReader(is);
                char[] buffer = new char[1024];
                int len;
                while ((len = isr.read(buffer)) != -1) {
                    respData.append(buffer, 0, len);
                }
            } finally {
                if (isr != null)
                    isr.close();
                Toast toast = Toast.makeText(getApplicationContext(), "Success", Toast.LENGTH_SHORT);
            }
            is.close();
        }
        else {
            // use below to get error stream
            // inputStream = httpUrlConnection.getErrorStream();
        }
        return respData.toString();
    }

}
  • 0
    да можно написать AsyncTask в том же Activity . Смотрите эту ссылку для получения дополнительной информации. vogella.com/tutorials/AndroidBackgroundProcessing/article.html
  • 0
    Должен ли я просто вставить код тяги в нем? Спасибо
Показать ещё 1 комментарий
Теги:
android-asynctask

1 ответ

1
Лучший ответ

См. Http://developer.android.com/reference/android/os/AsyncTask.html для документированного использования Android, но в основном это сводится к следующей реализации:

Частный подкласс, который расширяет AsyncTask, который реализует следующие методы:

  1. onPreExecute - onPreExecute в потоке пользовательского интерфейса перед выполнением задачи и используется для настройки содержимого (например, отображение индикатора выполнения)

  2. doInBackground - фактическая операция, которую вы хотите выполнить, которая запускается сразу после onPreExecute

  3. onPostExecute - onPostExecute в потоке пользовательского интерфейса после завершения doInBackground. Это принимает результат от doInBackground в качестве параметра и затем может использоваться в потоке пользовательского интерфейса.

AsyncTask используется для операций, которые разрешены в потоке пользовательского интерфейса, такие как:

  • Открытие соединения сокета
  • HTTP-запросы (такие как HTTPClient и HTTPURLConnection)
  • Попытка подключения к удаленной базе данных MySQL
  • Загрузка файла

Ваш текущий код сидит в методе, который будет создан в потоке пользовательского интерфейса (который NetworkOnMainThreadException, поэтому вам нужно переместить свой код в поток, который выполняется на worker потоке.

Перемещение вашего кода в AsyncTask

По внешнему виду, только ваш метод getData() должен быть перестроен. Все, что касается получения данных, может идти в бит doInBackground задачи, и все обновления компонентов пользовательского интерфейса (например, ваш toast) необходимо перенести в onPostExecute.

Он должен выглядеть примерно следующим образом (обратите внимание, что некоторые вещи, возможно, потребуется изменить). Это было записано от компилятора):

private class MyTask extends AsyncTask<Void, Void, Value> 
{
    boolean success = false;

    @Override
    protected String doInBackground(String toSubmit) 
    {
        StringBuilder respData = new StringBuilder();
        URL url = new URL("MY_URL");
        URLConnection conn = url.openConnection();
        HttpURLConnection httpUrlConnection = (HttpURLConnection) conn;

        httpUrlConnection.setUseCaches(false);
        httpUrlConnection.setRequestProperty("User-Agent", "YourApp"); 
        httpUrlConnection.setConnectTimeout(30000);
        httpUrlConnection.setReadTimeout(30000);

        httpUrlConnection.setRequestMethod("POST");
        httpUrlConnection.setDoOutput(true);

        OutputStream os = httpUrlConnection.getOutputStream();
        InputStream postStream = toInputStream(toSubmit, "UTF-8");
        try {
            copy(postStream, os);
        } finally {
            postStream.close();
            os.flush();
            os.close();
        }

        httpUrlConnection.connect();

        int responseCode = httpUrlConnection.getResponseCode();

        if (200 == responseCode) {
            InputStream is = httpUrlConnection.getInputStream();
            InputStreamReader isr = null;
            try {
                isr = new InputStreamReader(is);
                char[] buffer = new char[1024];
                int len;
                while ((len = isr.read(buffer)) != -1) {
                    respData.append(buffer, 0, len);
                }
            } finally {
                if (isr != null)
                {
                    isr.close();
                    success = true;
                }
            }
            is.close();
        }
        else {
            // use below to get error stream
            // inputStream = httpUrlConnection.getErrorStream();
        }
        return respData.toString();
    }

    @Override
    protected void onPostExecute(String result) 
    {
        Toast toast = Toast.makeText(getApplicationContext(), "Success", Toast.LENGTH_SHORT);
        processValue(result);
    }
}

private void processValue(String theResult) 
{
   //handle value
}

String toSubmit = "";

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

    submit.setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            //get input from editText boxes to send to php file on server
            toSubmit = name.getText().toString() + " " + email.getText().toString() + " " + idea.getText().toString();

            try{
                new MyTask().execute();
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    });
}
  • 0
    Хорошо, спасибо, getData входит в doInBackground? Я очень смущен этим
  • 0
    Довольно много. Где вы изначально вызываете getData(toSubmit); Вы должны выполнить AsyncTask. doInBackground задачи может принять ваши String postData в качестве параметра, и результат этого будет передан onPostExecute . Оттуда вы можете обновить общедоступную переменную, которая видна внешнему классу (а также вызвать toast - возможно, с помощью логического значения успеха, обновленного в результате выполнения задачи в doInBackground )
Показать ещё 7 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню