【问题标题】:“android.os.NetworkOnMainThreadException” when receiving socket data despite using AsyncTask [duplicate]尽管使用 AsyncTask,但在接收套接字数据时出现“android.os.NetworkOnMainThreadException” [重复]
【发布时间】:2015-07-25 21:16:48
【问题描述】:

关于重复:请注意,我已经确认了其他问答(线程 UI),但我的情况不同,因为我尝试使用该解决方案,但它在所有情况下都不起作用(因为它适用于写作,但不适用于不是为了阅读。

更新:我确切地知道出了什么问题,请阅读粗体的我的问题部分 我正在尝试制作一个通过 WiFi 连接到 Java 服务器的 Android Socket 客户端。最终客户端将发送和接收命令和日志,因为将有一个文本框,用户可以在其中编写 SQL 命令并通过点击按钮命令将从应用程序发送到桌面服务器并在另一个文本框中显示日志。

到目前为止,我一直在尝试使用另一个问题中的This Answer 来制作该客户端,并在 TCP 客户端中添加以下行。

Scanner  in = new Scanner(socket.getInputStream());//in doInBackground
//also changed send method a little
public String send(String command)
{
    if ( connected ){
        out.println(command);
        out.flush();

        String back = in.nextLine().toString();
        return back;

    }
    return "not Connected";
}

连接成功,send 方法确实在服务器接收到命令时发送命令。但是服务器写回的字符串在标题中抛出提到的异常,尽管我正在使用 AsyncTask。

我的问题

为什么 Scanner 会在 PrintWriter 正常工作时抛出此异常?

主要活动

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {


EditText serverIP, servMsg;
String ip, serverOut;
Button connectBtn;
TcpClient tcpClient;

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

    serverIP = (EditText) findViewById(R.id.serverIP);
    connectBtn = (Button) findViewById(R.id.connectBtn);
    servMsg = (EditText) findViewById(R.id.servMsg);

}

public void onConnectBtn(View view){

    try{

        ip = serverIP.getText().toString();
        tcpClient = new TcpClient();
        tcpClient.connect(getApplicationContext(), ip, 8082);
        serverOut = tcpClient.send("HELLO FROM cat:123");
        servMsg.setText(serverOut);

        tcpClient.disconnect(getApplicationContext());

    }
    catch (Exception e){

        Toast.makeText(getApplicationContext(),
                "Exception on runnning thread: " + e.getMessage().toString(), Toast.LENGTH_LONG).show();

    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
  }
}

TCP 客户端

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;

public class TcpClient {

private static final String TAG = TcpClient.class.getSimpleName();

private Socket socket;
private PrintWriter out;
private Scanner in;
private boolean connected;

public TcpClient() {
    socket = null;
    out = null;
    connected = false;
}


public void connect(Context context, String host, int port) {
    new ConnectTask(context).execute(host, String.valueOf(port));
}

private class ConnectTask extends AsyncTask<String, Void, Void> {

    private Context context;

    public ConnectTask(Context context) {
        this.context = context;
    }

    @Override
    protected void onPreExecute() {
        showToast(context, "Connecting..");
        super.onPreExecute();
    }

    @Override
    protected void onPostExecute(Void result) {
        if (connected) {
            showToast(context, "Connection successful");
        }
        super.onPostExecute(result);
    }

    private String host;
    private int port;

    @Override
    protected Void doInBackground(String... params) {
        try {
            String host = params[0];
            int port = Integer.parseInt(params[1]);
            socket = new Socket(host, port);
            out = new PrintWriter(socket.getOutputStream(), true);
            in = new Scanner(socket.getInputStream());
        } catch (UnknownHostException e) {
            showToast(context, "Don't know about host: " + host + ":" + port);
            Log.e(TAG, e.getMessage());
        } catch (IOException e) {
            showToast(context, "Couldn't get I/O for the connection to: " + host + ":" + port);
            Log.e(TAG, e.getMessage());
        }
        connected = true;
        return null;
    }


}

public void disconnect(Context context) {
    if (connected) {
        try {
            out.close();
            socket.close();
            connected = false;
        } catch (IOException e) {
            showToast(context, "Couldn't get I/O for the connection");
            Log.e(TAG, e.getMessage());
        }
    }
}


/**
 * Send command to a Pure Data audio engine.
 */
 public String send(String command)
{
    if ( connected ){
        out.println(command);
        out.flush();

        String back = in.nextLine().toString();
        return back;

    }
    return "not Connected";
}
private void showToast(final Context context, final String message) {
    new Handler(context.getMainLooper()).post(new Runnable() {

        @Override
        public void run() {
            Toast.makeText(context, message, Toast.LENGTH_LONG).show();
        }
    });
  }
}

Layout 现在还包含两个 TextEdits,其中一个用户键入计算机的 IP(我用正确的 IP 检查),第二个将显示服务器响应。

【问题讨论】:

  • “但我的情况不同,因为我尝试使用该解决方案但它不起作用” - 这可能是因为您不了解解决方案并且您申请了它不正确。回复:您认为输出有效的理论,您向我们展示了支持这一点的零证据。 (提示:堆栈跟踪...)
  • @StephenC 我不明白你的意思。这不是我的理论。正如我所说,我已经运行并调试了程序。它运行 write 方法,并且也在运行(不是理论上但实际上)的服务器接收消息。但在此之后,将执行 readline 方法,该方法会引发异常

标签: java android sockets android-asynctask


【解决方案1】:

我相信您不是“刷新”,这实际上是在强制缓冲区清空其内容。请看一下这个使用 TCP/IP 的工作聊天服务器/客户端代码。附带说明一下,我建议不要扩展 ActionBarActivity,因为它已被弃用(谷歌表示他们将远离它并且不会很快支持它)。请参阅第三个链接。

ChatServer.java

ChatClient.java

ActionBar Activity deprecation

【讨论】:

  • 我认为这不是问题,因为我已经将 PrintWriter 用于我提到的常用 Java 套接字客户端,并且不需要刷新。也感谢您注意到已弃用的类,它来自空白活动模板
猜你喜欢
  • 2015-08-03
  • 2018-09-09
  • 1970-01-01
  • 2013-04-22
  • 2013-06-18
  • 1970-01-01
  • 2020-01-12
  • 2020-01-18
  • 1970-01-01
相关资源
最近更新 更多