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);

AsyncTask

Рекомендации

AsyncTask doc

Пример AsyncTask для Android

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 это невозможно. Таким образом, у вас есть два разных выбора

  1. Используйте поток или 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. Итак, я увидел следующее видео и решил свою проблему. Я надеюсь, что это также полезно для других:

Как избежать Android OS NetworkOnMainThreadException

Посмотрите на эту ссылку: 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

Другие вопросы по тегам