我NetworkOnMainThreadException
android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1303)
ObjectOutputStream.writeObject()
ObjectOutputStream
ObjectOutputStream
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)
并尝试在几个不同的地方创建套接字和new_items = [ j for j in JSON['Items'] if j.get('Type') == 'Address' ]
JSON = {'Items' : new_items }
,我认为这些不在主线程上,但似乎没有帮助。
我看到了一个改变线程策略here的建议,但我宁愿不这样做,特别是如果事实证明这是一个我不知道的小事。我没有正确创建线程吗?
new_items = [ j.get('heighlight') for j in JSON['Items'] if j.get('Type') == 'Address' ]
错误,在Address Type
:
[highlight for highlight in respose['Items'] if highlight['Type'] == 'Address']
编辑:我忘了提,这个类用于客户端和服务器。通过调用connectToServer()调用startServer()和客户端来启动服务器。套接字通信在从客户端发送时有效,但在尝试从服务器发送时会因上述错误而崩溃。
答案 0 :(得分:0)
问题是,默认情况下Service在主线程上运行。因此,当您使用该服务的Binder调用send()时,仍然会从主线程调用它。您应该在ClientThread中调用此方法。为了实现尝试使用ExecutorService框架 - 它有待处理任务的并发队列(因为wifi在发送时可能比你想要的工作慢)。 如果线程和作业的主机名相同,则可以在ExecutorService中为每个连接创建线程并接受任务。
答案 1 :(得分:0)
警告:服务在其托管进程的主线程中运行;该 service不会创建自己的线程,也不会单独运行 除非另有说明,否则请遵循如果您的服务是 执行任何CPU密集型工作或阻止操作,如MP3 播放或联网,你应该在里面创建一个新的线程 服务完成这项工作。通过使用单独的线程,您可以 降低应用程序无响应(ANR)错误的风险,以及 应用程序的主线程可以保持专用于用户交互 与您的活动。
您可以从谷歌Android开发者页面阅读有关服务的完整信息 https://developer.android.com/guide/components/services.html