AsyncTask / Thread和networkonmainthreadexception的问题

时间:2013-02-27 15:54:23

标签: android sockets android-asynctask

你好,伙计们,
我想为我的Android制作聊天客户端。但我无法得到任何联系 好吧,也许你可以帮我一点..
在我的MainActivity.java中,我调用:

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

我的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 / SensorManager(26146):线程启动

此外,当我尝试调用“connection.doInBackground()”而不是“connection.execute()”时(我知道这根本没有任何意义),我得到一个“networkonmainthreadexception” - 但我以为我已经用AsyncTask解决了这个问题。嗯,我是Android的新手,但我已经搜索了很多,不知道我是不是那么傻但现在我放弃了,所以我在这里注册了我。也许有人可以告诉我,我做错了什么..

(不确定我是否需要发布我的MainActivity类......)
谢谢! :)

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

5 个答案:

答案 0 :(得分:1)

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

<强>提示:

  • 不在AsyncTask中创建新线程,doInBackground()已在后台线程中调用
  • 不要在AsyncTask上调用runOnUiThread,已在UI线程上调用onPostExecute()
  • 如果您的活动暂停(调用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?
    }
}
}

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

您正试图使用​​MainActivity doInBackground()中的onPostExecute(),这需要位于UI线程和doInBackground()线程上运行的{{1}}方法中}方法没有。

AsyncTask

  

4个步骤

     

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

     

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

     

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

     

onProgressUpdate(Progress ...),在调用后在UI线程上调用   发布进度(进度......)。执行的时间是   未定义。此方法用于显示任何形式的进度   后台计算仍在执行时的用户界面。   例如,它可用于为进度条设置动画或显示登录   文本字段。

     

onPostExecute(Result),在后台后的UI线程上调用   计算结束。背景计算的结果是   作为参数传递给此步骤。

答案 3 :(得分:0)

如果您需要在主线程(即UI)上运行某些内容,而不是尝试使用AsynTask在主线程上运行某些内容,则可以从publishProgess()调用doInBackground(...) onProgressUpdate(...),后者又调用doInBackground。不要直接致电execute()AsyncTask是启动doInBackground()的正确方法。返回onPostExecute()后,将在主线程上自动调用{{1}}。

Android docs on AsyncTask非常好,并有一个很好的用法示例。

答案 4 :(得分:0)

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

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

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