Я получаю сообщение об ошибке: 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();
}
}
См. Http://developer.android.com/reference/android/os/AsyncTask.html для документированного использования Android, но в основном это сводится к следующей реализации:
Частный подкласс, который расширяет AsyncTask, который реализует следующие методы:
onPreExecute
- onPreExecute
в потоке пользовательского интерфейса перед выполнением задачи и используется для настройки содержимого (например, отображение индикатора выполнения)
doInBackground
- фактическая операция, которую вы хотите выполнить, которая запускается сразу после onPreExecute
onPostExecute
- onPostExecute
в потоке пользовательского интерфейса после завершения doInBackground. Это принимает результат от doInBackground в качестве параметра и затем может использоваться в потоке пользовательского интерфейса.
AsyncTask используется для операций, которые разрешены в потоке пользовательского интерфейса, такие как:
Ваш текущий код сидит в методе, который будет создан в потоке пользовательского интерфейса (который 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();
}
}
});
}
getData(toSubmit);
Вы должны выполнить AsyncTask. doInBackground
задачи может принять ваши String postData
в качестве параметра, и результат этого будет передан onPostExecute
. Оттуда вы можете обновить общедоступную переменную, которая видна внешнему классу (а также вызвать toast
- возможно, с помощью логического значения успеха, обновленного в результате выполнения задачи в doInBackground
)
Activity
. Смотрите эту ссылку для получения дополнительной информации. vogella.com/tutorials/AndroidBackgroundProcessing/article.html