【发布时间】:2017-11-28 08:43:19
【问题描述】:
我不断在android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1303) 上获得NetworkOnMainThreadException ObjectOutputStream.writeObject() 调用,即使它是在与主线程不同的线程上完成的。我从一个套接字创建了ObjectOutputStream,并尝试在几个不同的地方创建套接字和ObjectOutputStream,我认为这些地方不在主线程上,但这似乎没有帮助。
我看到了更改线程策略 here 的建议,但我宁愿不这样做,特别是如果它证明是我刚刚遗漏的一些小东西。我没有正确创建线程吗?
public class WifiService extends Service {
private ArrayList<ClientThread> clientThreads=new ArrayList<>();
private ServerThread serverThread;
private int localPort;
public WifiService() {
}
public void send(String info){
for (ClientThread c: clientThreads) {
c.send(info);
}
}
public void startServer(String hostName){
if(serverThread==null) {
serverThread = new ServerThread(hostName);
new Thread(serverThread).start();
}
}
public void connectToServer(InetAddress address, int port){
ClientThread clientThread=new ClientThread(address,port);
clientThread.start();
clientThreads.add(clientThread);
}
@Override
public IBinder onBind(Intent intent) {
return mybinder;
}
public final IBinder mybinder = new LocalBinder();
public class LocalBinder extends Binder {
public WifiService getService(){
return WifiService.this;
}
}
@Override
public int onStartCommand(Intent intent,int flags, int startId){ //called when service first started. Starts service in background forever unless stopself() called.
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
private class ServerThread extends Thread{
private ServerSocket serverSocket;
private String hostName;
public ServerThread(String hostName){
this.hostName=hostName;
}
public void tearDown(){
stopSelf();
}
@Override
public void run(){
try {
serverSocket=new ServerSocket(0);
localPort=serverSocket.getLocalPort();
startBroadcasting(hostName);
} catch (IOException e) {
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()){
Socket clientSocket = null;
try {
clientSocket = serverSocket.accept();
ClientThread clientThread=new ClientThread(clientSocket);
clientThread.start();
clientThreads.add(clientThread);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private class ClientThread extends Thread{
protected Socket socket=null;
private ObjectInputStream input;
private ObjectOutputStream output;
private InetAddress address;
private int port;
public ClientThread(Socket socket){
this.socket=socket;
this.address=socket.getInetAddress();
this.port=socket.getLocalPort();
}
public ClientThread(InetAddress address, int port){
this.address=address;
this.port=port;
}
public void tearDown(){
stopSelf();
}
@Override
public void run(){
Log.d("ClientThread", "port: "+port);
if(socket==null){
try {
socket=new Socket(address, port);
} catch (IOException e) {
e.printStackTrace();
return;
}
}
try {
output=new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
input=new ObjectInputStream(socket.getInputStream());
while (!Thread.currentThread().isInterrupted()) {
try {
CommunicationTemplate received_CT=(CommunicationTemplate)input.readObject();
MessageMainActivity(received_CT);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
input.close();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void send(String info){
CommunicationTemplate ct=new CommunicationTemplate(1,"fromPlayer","toPlayer", 100L, info);
try {
output.writeObject(ct);
output.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void MessageMainActivity(CommunicationTemplate communicationTemplate){ //sends bundle to MainActivity to interact with UI
Bundle messageBundle = new Bundle();
messageBundle.putSerializable("msg",communicationTemplate);
Intent intent=new Intent();
intent.setAction("message");
intent.putExtra("message",messageBundle);
sendBroadcast(intent);
}
private void commMainActivity(HostInfo hostInfo){ //sends bundle to MainActivity to interact with UI
Bundle messageBundle = new Bundle();
messageBundle.putParcelable("host",hostInfo);
Intent intent=new Intent();
intent.setAction("host");
intent.putExtra("host",messageBundle);
Log.d("commMainActivity", "sending hostInfo to MainActivity...");
sendBroadcast(intent);
}
}
还有错误,ClientThread > send() > output.writeObject():
06-25 01:22:29.864 15175-15175/com.example.admin.bluetoothcomms E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.admin.bluetoothcomms, PID: 15175
android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1303)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
at java.net.SocketOutputStream.write(SocketOutputStream.java:157)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at java.io.ObjectOutputStream$BlockDataOutputStream.flush(ObjectOutputStream.java:1889)
at java.io.ObjectOutputStream.flush(ObjectOutputStream.java:731)
at com.example.admin.bluetoothcomms.WifiService$ClientThread.send(WifiService.java:151)
at com.example.admin.bluetoothcomms.WifiService.send(WifiService.java:33)
at com.example.admin.bluetoothcomms.MainActivity.send(MainActivity.java:178)
at com.example.admin.bluetoothcomms.MainActivity.onClick(MainActivity.java:126)
at android.view.View.performClick(View.java:6207)
at android.widget.TextView.performClick(TextView.java:11094)
at android.view.View$PerformClick.run(View.java:23639)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6688)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
编辑:我忘了提,这个类用于客户端和服务器。服务器通过调用 startServer() 启动,客户端通过调用 connectToServer() 启动。 Socket 通信在从客户端发送时有效,但在尝试从服务器发送时因上述错误而崩溃。
【问题讨论】:
-
@ReazMurshed 这是一个最不恰当的要求。这里提出的问题本身就是完整的,并且出于正当理由,OP 可能无法,可能无法提供他的整个代码,
-
我理解并删除了评论。
标签: java android multithreading sockets networkonmainthread