Java 已在另一个线程上运行,但仍引发android.os.NetworkOnMainThreadException?

Java 已在另一个线程上运行,但仍引发android.os.NetworkOnMainThreadException?,java,android,multithreading,sockets,networkonmainthread,Java,Android,Multithreading,Sockets,Networkonmainthread,我编写了一个简单的服务器-客户端TCP套接字连接,并一直在尝试在主机和客户端之间进行连接。虽然我已经在另一个线程(不是主线程)上运行了网络操作,但当我尝试从客户端向服务器发送字符串时,它会抛出 public class Client extends AppCompatActivity { public static final String TAG = Client.class.getSimpleName(); public static final int ServerPORT = 300

我编写了一个简单的服务器-客户端TCP套接字连接,并一直在尝试在主机和客户端之间进行连接。虽然我已经在另一个线程(不是主线程)上运行了网络操作,但当我尝试从客户端向服务器发送字符串时,它会抛出

public class Client extends AppCompatActivity  {

public static final String TAG = Client.class.getSimpleName();
public static final int ServerPORT = 3000;
public static final String ServerIP = "10.146.166.86";
EditText message;
TextView mainView;
ClientThread clientThread;
Thread thread;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_client);
    message = (EditText)findViewById(R.id.message);
    mainView = (TextView)findViewById(R.id.mainView);
}

public void updateMessage(final String message) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mainView.append(message + "\n");
        }
    });
}

public void onClick(View view) {

    if (view.getId() == R.id.connectServer) {
        mainView.setText("");
        clientThread = new ClientThread();
        thread = new Thread(clientThread);
        thread.start();
        return;
    }

    if (view.getId() == R.id.sendMessage) {
        Log.i(TAG, "Message sent from client");
        clientThread.sendMessage(message.getText().toString());
    }
}

class ClientThread implements Runnable {

    private Socket socket;
    private BufferedReader input;

    @Override
    public void run() {
        try {
            InetAddress serverAdd = InetAddress.getByName(ServerIP);
            socket = new Socket(serverAdd, ServerPORT);
            while (!Thread.currentThread().isInterrupted()) {
                this.input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String message = input.readLine();
                if (null == message || "Disconnect".contentEquals(message)) {
                    Thread.interrupted();
                    message = "Server Disconnected.";
                    updateMessage(getTime() + " | Server : " + message);
                    break;
                }

                updateMessage(getTime() + " | Server : " + message);
            }
        } catch (UnknownHostException e1) {
            e1.printStackTrace();
        } catch (IOException e2) {
            e2.printStackTrace();
        }
    }

    void sendMessage(String message) {
        try {
            if (null != socket) {
                PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
                out.println(message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

String getTime() {
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
    return sdf.format(new Date());
}
@Override
protected void onDestroy() {
    super.onDestroy();
    if (null != clientThread) {
        clientThread.sendMessage("Disconnect");
        clientThread = null;
    }
}
}
这对我来说似乎更奇怪,因为当我尝试切换主机和客户端设备时,现在我可以从客户端发送到服务器,但不能从服务器发送到客户端。然后,我得出结论,这应该是由于我的一个设备。一个运行安卓8,一个运行安卓6,问题似乎属于运行安卓8的人。虽然我通过添加以下内容成功地解决了此问题:

android.os.NetworkOnMainThreadException. 
这对我来说真的很奇怪,因为它发生的方式。它实际上取决于设备吗

编辑:完整错误消息。这很奇怪,因为它只发生在我的一台设备上。当我在设备之间切换角色时,它成功地完成了它的工作

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy); 

sendMessage
中的代码没有在另一个线程上运行,因为您将它放在另一个名为“thread”的类中。调用
execute()
时,只有runnable的
run()
方法在另一个线程上运行。因此,您必须在
new Thread()
中调用sendMessage,或者将其放入某种线程安全变量或队列中,然后在
run()
方法中检查循环,然后发送出去。

您在
sendMessage
中的代码没有在另一个线程上运行,只是因为您将它放在另一个名为“Thread”的类中。调用
execute()
时,只有runnable的
run()
方法在另一个线程上运行。因此,您必须在
new Thread()
中调用sendMessage,或者将其放入某种线程安全变量或队列中,然后在
run()中检查循环
方法,然后发送。

是否可以编辑问题并发布与崩溃相关的整个Java堆栈跟踪?添加了崩溃原因。是否可以编辑问题并发布与崩溃相关的整个Java堆栈跟踪?添加了崩溃原因。您的意思是OP正在与
套接字进行交互
socket.getOutputStream()
-从
sendMessage
方法内的主线程?我实际上不明白你的意思,因为在我的onClick方法中,它调用:clientThread.sendMessage(message.getText().toString())和clientThread extensed Runnable(我相信clientThread中的run()会被执行),@buzzerbeater27-
socket.getOutputStream()
是一个I/O操作,它位于从主线程调用的
sendMessage
内部。您正在对实例变量调用方法,但这并不意味着它切换了线程。只有
run()
内部发生的事情发生在另一个
线程上
@buzzerbeater27:在
线程上调用
start()
只能在后台线程上运行
run()
方法。它不会神奇地导致在该类上实现的所有其他方法在后台线程上被调用。但是,“线程安全变量或队列”是什么意思?你能写一些具体的例子吗?你的意思是OP正在与
Socket
-
Socket.getOutputStream()
-从
sendMessage
方法内的主线程进行交互吗?我实际上不明白你的意思,因为在我的onClick方法中,它调用:clientThread.sendMessage(message.getText().toString()),clientThread扩展了Runnable(我相信clientThread中的run()会被执行),@buzzerbeater27-
socket.getOutputStream()
是一个I/O操作,它位于从主线程调用的
sendMessage
中。您正在对实例变量调用方法,但这并不意味着它切换了线程。只有
run()
内部发生的事情发生在另一个
线程上
@buzzerbeater27:在
线程上调用
start()
只能在后台线程上运行
run()
方法。它不会神奇地导致在该类上实现的所有其他方法在后台线程上被调用。但是,“线程安全变量或队列”是什么意思?你能写一些具体的例子吗?
02-10 16:42:17.719 827-827/com.dev.kvuong2711.clienttcp I/Client: Message sent from client
02-10 16:42:17.720 827-827/com.dev.kvuong2711.clienttcp W/System.err: android.os.NetworkOnMainThreadException
02-10 16:42:17.721 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1448)
02-10 16:42:17.721 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:108)
02-10 16:42:17.721 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
02-10 16:42:17.721 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
02-10 16:42:17.721 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
02-10 16:42:17.721 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:295)
02-10 16:42:17.721 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141)
02-10 16:42:17.721 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229)
02-10 16:42:17.722 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at java.io.BufferedWriter.flush(BufferedWriter.java:254)
02-10 16:42:17.722 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at java.io.PrintWriter.newLine(PrintWriter.java:482)
02-10 16:42:17.722 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at com.dev.kvuong2711.clienttcp.Client$ClientThread.sendMessage(Client.java:105)
02-10 16:42:17.722 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at com.dev.kvuong2711.clienttcp.Client.onClick(Client.java:68)
02-10 16:42:17.722 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
02-10 16:42:17.722 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
02-10 16:42:17.722 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at android.view.View.performClick(View.java:6256)
02-10 16:42:17.722 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at android.view.View$PerformClick.run(View.java:24779)
02-10 16:42:17.722 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at android.os.Handler.handleCallback(Handler.java:789)
02-10 16:42:17.722 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:98)
02-10 16:42:17.723 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at android.os.Looper.loop(Looper.java:180)
02-10 16:42:17.723 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6950)
02-10 16:42:17.723 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
02-10 16:42:17.723 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
02-10 16:42:17.723 827-827/com.dev.kvuong2711.clienttcp W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:835)