Android 应用因 NetworkOnMainThreadException 而崩溃

Android app crashes due to NetworkOnMainThreadException

我想开发一个应用程序,允许我从 android 应用程序的形式将数据作为文本文件上传到服务器 这是主要活动 class

    package com.example.incrediblemachine.sendtest;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
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 java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends Activity {

    EditText msgTextField;
    Button sendButton;

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

        //make message text field object
        msgTextField = (EditText) findViewById(R.id.msgTextField);
        //make button object
        sendButton = (Button) findViewById(R.id.sendButton);
    }

    public void send(View v)
    {
        //get message from message box
        String  msg = msgTextField.getText().toString();

        //check whether the msg empty or not
        if(msg.length()>0) {
            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httppost = new HttpPost("http://ramsproject.16mb.com/sendorder.php");

            try {
                List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
                nameValuePairs.add(new BasicNameValuePair("id", "01"));
                nameValuePairs.add(new BasicNameValuePair("message", msg));
                httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                httpclient.execute(httppost);
                msgTextField.setText(""); //reset the message text field
                Toast.makeText(getBaseContext(),"Sent",Toast.LENGTH_SHORT).show();
            }catch (IllegalStateException e)
            {
                e.printStackTrace();
            }
            catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            //display message if text field is empty
            Toast.makeText(getBaseContext(),"All fields are required",Toast.LENGTH_SHORT).show();
        }
    }

}

它在第 53 行出现异常 httpclient.execute(httppost);

异常显示 android.app.NetworkOnMainThreadException 我该如何解决这个问题

只需使用一个线程。

Thread thread = new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
});

thread.start(); 

在此线程中调用 httpClient。

您不能在 MainThread 中进行网络调用。您应该为网络操作使用异步任务。您可以从下面的 link 中找到有关它的更多信息:

https://developer.android.com/reference/android/os/AsyncTask.html

我还建议您使用网络库来处理您的网络操作。您可以从下面的 link 中为您的网络操作找到一个好的库:

http://square.github.io/retrofit/

当应用程序试图在其主线程上执行网络操作时抛出的异常。 允许以 Honeycomb SDK 或更高版本为目标的应用程序在其主事件循环线程上进行联网,以避免在与网络相关的无响应情况下出现迟缓。你可以参考Documentation.

要解决此问题,您可以选择以下选项: 1.Using 异步任务 2.线程 3.处理程序

我想在这里为您提供一个解决方案。为此,我想在您了解解决方案之前指出几点。

    在 UI 线程或主线程,进一步阅读以了解这一点。

  1. 每个 Android 应用程序 运行 在其自己的进程中并具有唯一的用户 ID。每当安装 android 应用程序时,它都会获得一个唯一的用户 ID。每当应用程序 运行 时,它都会获得一个单独的内存 space 和程序执行路径。这个进程由它自己的称为堆的内存组成。进程就像一个单独的环境给你的应用程序运行代码或进程代码。

  2. 另一方面,线程是子进程或轻量级进程。它在进程内部产生。每当创建一个线程时,它都会获得一部分内存(堆栈)。一个进程可以产生许多线程。

  3. 一个线程不能访问另一个线程的内存(栈),它是特定线程私有的。但是他们可以访问进程内存(堆内存)。将堆内存视为全局内存。

  4. 每当为您的应用程序创建一个进程时,都会创建一个线程,这是强制性的。该线程称为主线程。在 android 中它也可能被称为 UI 线程。因为此线程处理您看到的所有 UI 组件(如 activity、片段和服务(即使服务在后台 运行,它在 UI线程)等)。

  5. Android 框架的创建方式是他们希望处理主线程上的所有 UI 操作,使其具有高优先级来处理 UI组件。因为 UI 是显示给用户的,如果应用程序在未处理 UI.

  6. 的情况下被冻结,用户将不会喜欢该应用程序
  7. 这就是您得到 "NetworkOnMainThread" 异常的原因。因为 Android 限制 运行ning 长 运行ning 操作,如网络访问、文件访问、数据库访问以及 运行 在 UI 线程上的那些处理。因为限制 UI 响应需要花费很多时间,因为它没有给 UI 组件处理机会。

我希望你明白为什么你现在会得到这样的异常。长 运行ning 操作不应限制 UI 线程操作。所以它应该从 UI 线程移动到另一个新线程(移动你创建 HttpClient 的代码,直到你收到它的响应)。 Android 还为此提供了另一种选择。您可以创建一个 AsyncTask,它会为您处理线程创建过程。您可以只编写代码并将结果传递给 UI 线程。了解更多。

注意:所有线程都访问进程内存。但是一个进程不能访问另一个进程的内存,除非它有相同的 USER ID。意味着除非它来自您的应用程序之一。这可以使用 AIDL 接口完成。

我希望这个解决方案能帮助您理解您遇到的异常并解决它们。