Problems with AsyncTask/Thread and networkonmainthreadexcept



大家好,
我想为我的Android做一个聊天客户端。但我就是无法获得任何联系。
好吧,也许你可以帮我一点。
在我的主活动中.java我调用:

//connect to the server
SocketTask connection = new SocketTask(this); 
connection.execute();

My SocketTask.java如下所示:

package chat.client;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import android.os.AsyncTask;
public class SocketTask extends AsyncTask<Void, Void, Void>{
    private Socket socket;
    private DataInputStream input;
    protected PrintStream output;
    private MainActivity main;
    private Thread thrd;
    public SocketTask(MainActivity main){
        this.main = main;
    }
    @Override
    protected Void doInBackground(Void... params) {
        try {
            socket = new Socket("192.168.178.23", 1338);
            input = new DataInputStream(socket.getInputStream());
            output = new PrintStream(socket.getOutputStream());
            // submittes the name of the client
            output.println("Mobile");
            output.flush();
            thrd = new Thread(new Runnable() {
                public void run() {
                    while (!Thread.interrupted()) {
                        try {
                            final String data = input.readLine();
                            if (data != null)
                                main.runOnUiThread(new Runnable() {
                                    //new Runnable(){
                                    @Override
                                    public void run() {
                                        if(!data.equals("")){
                                            //main.chatHistory.append(data+"n");
                                            main.addText(data);
                                        }else{
                                            //chatHistory.append("n");
                                            main.addText("");
                                        }
                                    }
                                });
                            //};
                        } catch (IOException e) {
                            //chatHistory.append("Verbindung zum Server abgebrochen!");
                            main.addText("Verbindung zum Server abgebrochen!");
                        }
                    }
                }
            });
            thrd.start();
        } catch (Exception e) {
            //chatHistory.append("Es konnte keine Verbindung zum Server aufgebaut werden!");
            main.addText("Es konnte keine Verbindung zum Server aufgebaut werden!"+e);
        }
        return null;
    }
}

但是当我启动它时,我只会得到:
02-27 16:32:05.875:E/传感器管理器(26146(:线程启动

另外,当我尝试调用"connection.doInBackground(("而不是"connection.execute(("(我知道这根本没有任何意义(时,我得到了一个"networkonmainthreadexception" - 但我认为我已经用AsyncTask解决了这个问题。好吧,我是Android的新手,但我已经用谷歌搜索了很多,不知道我是否那么愚蠢,但现在我放弃了,所以我在这里注册了我。也许你们中的某个人可以告诉我,我做错了什么。

(不确定我是否需要发布我的主活动类。
谢谢!:)

编辑:谢谢大家的所有这些答案,知道我有点过度了,给我一些时间来尝试/理解你的所有提示,谢谢!

在 AsyncTask 的实现上有很多概念错误,甚至很难弄清楚为什么或可能出现什么问题,所以我会在这里写一个关于如何编写 AsyncTask 的食谱和感觉提示,然后你应用它们,如果你仍然收到错误,那么你再问一次:

技巧:

  • 不要在 AsyncTask 中创建新线程,doInBackground(( 已经在后台线程中被调用
  • 不要在 AsyncTask 上调用 runOnUiThread,onPostExecute(( 已经在 UI 线程上调用
  • 如果你的活动暂停(onPause((被调用(,在你的AsyncTask上调用.pause((,否则你可能会有一些NullPointerException
  • 不要按照您的建议直接调用doInBackground()execute()调用将创建一个新线程并为您调用它(这就是 AsyncTask 的原因(
  • 不要保存活动对象或任何其他将上下文保存到 AsyncTask 的对象。只需将 AsyncTask 类声明放在 Activity 本身中,出于组织目的,让 doInbackground(( 调用不同类中的一个方法并进行实际处理。这样,您的onPostExecute可以调用UI来更新它,但您将数据网络共享/处理与活动分开

食谱:

// put this class inside your Activity and
// just call a separate class (for organisation),
// or just put the code all in there (for no organisation)
private class SocketTask extends AsyncTask<Void, Void, String> {
@Override
protected String doInBackground(Void... params) {
    // Whatever you do inside here
    // DO NOT create a new thread!
    return APIConnection.callAPI();
}
@Override
protected void onPostExecute(String result) {
    if(result!=null){
    //Update your UI here
    }else{
    // Some error happen?
    }
}
}

异常表示您需要在后台线程上运行网络操作。直接调用doInBackground((只是使所有内容在调用的同一线程中运行,显然是主线程。所以,你必须用connection.excute()生成新的.但是,您无法从后台线程更新 UI 元素。要在主线程上执行此操作,您需要像这样为 AsyncTask 实现onProgressUpdate()

    @Override
    protected void onProgressUpdate(String... arg) {            
        main.addText(arg[0]);
    }

现在,将doInBackground()中的所有addText()调用替换为 publishProgress("whatever"); 。不要忘记将异步任务声明更改为 AsyncTask<Void, String, Void> 。当你完成上述所有内容时,你不需要在doInBackground()内生成另一个线程,无论如何它都会在后台线程中执行。虽然,您当前的代码也差不多,但这将解决混乱(不再thrd = new Thread(new Runnable() {...main.runOnUiThread...(,并可能解决您的问题。

与其尝试像您那样在主线程上运行某些内容,不如使用 AsynTask ,如果您需要在主线程(即 UI(上运行某些内容,您将从 doInBackground(...) 调用 publishProgess(),这反过来调用 onProgressUpdate(...) 。不要直接拨打doInBackgroundexecute()是启动AsyncTask的正确方法。当doInBackground()返回时,将在主线程上自动调用onPostExecute()

AsyncTask上的Android文档非常好,并且有一个很好的使用示例。

您正在尝试在doInBackground()中使用MainActivity,这需要在UI线程上运行的onPostExecute()方法中,而doInBackground()方法不需要。

异步任务

4个步骤

执行异步任务时,任务将经历 4 个步骤:

onPreExecute((,在执行任务之前在 UI 线程上调用。 此步骤通常用于设置任务,例如通过显示 用户界面中的进度条。

doInBackground(Params...(,在后台线程上调用 在 onPreExecute(( 完成执行后立即执行。使用此步骤 执行可能需要很长时间的后台计算。这 异步任务的参数将传递到此步骤。这 计算结果必须由此步骤返回,并且将是 传回最后一步。此步骤还可以使用 publishProgress(Progress...( 以发布一个或多个进度单元。 这些值发布在 UI 线程的 在进度更新(进度...(步骤上。

onProgressUpdate(Progress...(,在调用后在 UI 线程上调用 以发布进度(进度...(。执行时间是 定义。此方法用于在 后台计算仍在执行时的用户界面。 例如,它可用于动画进度条或显示日志 文本字段。

onPostExecute(Result(,在后台之后的 UI 线程上调用 计算完成。后台计算的结果为 作为参数传递给此步骤。

您是否在清单中添加了所需的权限?

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

最新更新