Android - android.os.NetworkOnMainThreadException
У меня есть это исключение, и я читал ветку по этому вопросу, и это казалось странным:
Как исправить android.os.NetworkOnMainThreadException?
Я уже добавил эту строку в мой манифест:
<uses-permission android:name="android.permission.INTERNET" />
На этом обсуждении они говорят о том, что основной поток выполнения приложения не может работать в сети. Что меня интересует, так это как реструктурировать мой код так, чтобы он соответствовал рекомендациям Android.
Вот мой класс Activity для этого:
package com.problemio;
import java.io.InputStream;
import java.util.ArrayList;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class LoginActivity extends Activity
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
// Show form for login_email
final EditText loginEmail = (EditText) findViewById(R.id.login_email);
String name = loginEmail.getText().toString();
// Show field for password
final EditText password = (EditText) findViewById(R.id.password);
String text = password.getText().toString();
// Show button for submit
Button submit = (Button)findViewById(R.id.submit);
// Show options for create-profile and forgot-password
submit.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v)
{
String email = loginEmail.getText().toString();
String pass = password.getText().toString();
sendFeedback(pass, email);
}
});
}
public void sendFeedback(String pass , String email)
{
Log.d( "1" , pass );
Log.d( "1" , email );
// Go to db and check if these r legit
// How do I do that? :)
ArrayList<NameValuePair> postParameters = new ArrayList<NameValuePair>();
postParameters.add(new BasicNameValuePair("username", email ));
postParameters.add(new BasicNameValuePair("password", pass ));
String responseString = null;
try
{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("myUrl");
// no idea what this does :)
httppost.setEntity(new UrlEncodedFormEntity(postParameters));
// This is the line that send the request
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
}
catch (Exception e)
{
Log.e("log_tag", "Error in http connection "+e.toString());
}
}
}
Что я здесь не так делаю и как мне это исправить?:) Спасибо!!
11 ответов
NetworkOnMainThreadException: исключение, которое выдается, когда приложение пытается выполнить сетевую операцию в своем основном потоке.
Вы должны вызвать метод sendfeedback для asynctask, тогда будет работать только приведенный выше код. Поскольку веб-сервер тратит много времени на ответ, основной поток перестает отвечать на запросы. Чтобы избежать этого, вы должны вызывать его в другом потоке. Следовательно, асинктаск лучше.
вот ссылка, которая иллюстрирует, как использовать asynctask
NetworkOnMainThreadException генерируется, когда ваше приложение пытается работать в сети в главном потоке.
Чтобы исправить это, вы можете использовать закрытый внутренний класс в вашем Activity, который расширяет android.os.AsyncTask<Params, Progress, Result>
который будет делать вещи вызова сервера.
Что-то как,
private class SendfeedbackJob extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String[] params) {
// do above Server call here
return "some message";
}
@Override
protected void onPostExecute(String message) {
//process message
}
}
И затем вызвать выше класс из submit.setOnClickListener
как показано ниже,
SendfeedbackJob job = new SendfeedbackJob();
job.execute(pass, email);
Рекомендации
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
try
{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("myUrl");
// no idea what this does :)
httppost.setEntity(new UrlEncodedFormEntity(postParameters));
// This is the line that send the request
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
}
catch (Exception e)
{
Log.e("log_tag", "Error in http connection "+e.toString());
}
Вот твоя проблема. Начиная с api 11, это исключение сообщит вам, что вы выполняете длинные задачи в потоке пользовательского интерфейса (http-связь в вашем классе), и в соответствии с новой политикой StrictGuard это невозможно. Таким образом, у вас есть два разных выбора
- Используйте поток или aynctask для выполнения вашей долгосрочной задачи (лучший способ)
Вы сделали сетевой вызов в главном потоке, что противоречит правилам Android, поэтому вы должны выполнять сетевой вызов в отдельном потоке, например, asynctask или обработчик и т. Д.
Вы можете просто создать класс Async, как показано ниже
class Retrievedata extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
try{
//Your code
}
return null;
}
}
Вы можете просто поместить весь свой код в метод doInBackground
Как указано здесь ,
AsyncTask
устарела, и Google рекомендует использовать
java.util.concurrent
пакет или сопрограммы Kotlin
Вы можете очень легко выполнить свою сетевую задачу в другом потоке, используя
java.util.concurrent.Executors
.
Просто добавьте эти две переменные в свой
LoginActivity
учебный класс:
val executor = Executors.newSingleThreadExecutor()
Затем окружите свой сетевой вызов
executor.execute{}
блокировать:
executor.execute {
/**
* Executes network task in background. You cannot
* access view elements here.
*/
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent()
}
После долгого исследования (продолжавшегося полдня) я нашел решение для моей проблемы, которое похоже на проблему, указанную здесь. Исключением, отображаемым моей Android Studio 2.3.3, было следующее:
android studio android.os.networkonmainthreadexception
Проблема была основана на невозможности установить переменную пользовательского интерфейса в MainActivity. Итак, я увидел следующее видео и решил свою проблему. Я надеюсь, что это также полезно для других:
Посмотрите на эту ссылку: https://developer.android.com/reference/android/os/NetworkOnMainThreadException.html
Исключение, которое выдается, когда приложение пытается выполнить сетевую операцию в своем основном потоке. Приложениям, нацеленным на более ранние версии SDK, разрешено создавать сети в своих основных потоках цикла событий, но это сильно не рекомендуется.
если вы установите minSdkVersion <11, то ваше приложение будет работать, и вы сможете запустить сетевую операцию в главном потоке.
Основной поток является потоком пользовательского интерфейса, и вы не можете выполнить в основном потоке операцию, которая может заблокировать взаимодействие с пользователем. Чтобы избежать этого, создайте простой обработчик и обновите основной поток, если хотите.
Runnable runnable;
Handler newHandler;
newHandler = new Handler();
runnable = new Runnable() {
@Override
public void run() {
try {
//update UI
} catch (Exception e) {
e.printStackTrace();
}
}
};
runnable.run();
чтобы остановить поток использовать
newHandler.removeCallbacks(работоспособный);
Для получения дополнительной информации проверьте это. https://android-developers.googleblog.com/2009/05/painless-threading.html