问题
I don't know if a UI thread exists by default, how to create it if not, or how to tell when I'm "in" it where it begins and ends if so. How do I make sure PacketListener
isn't part of the main UI thread?
I keep running into this NetworkOnMainThreadException. I understand that means that I'm trying to do something in the main UI thread that should have its own separate thread. However, I can't find much to tell me HOW to actually do that.
I had thought that the MainActivity class would BE the UI thread, since, well, I had a UI and it worked. However, I've created a seperate class that implements Runnable, and put the network connection stuff in there, and am still getting the exception, so it's still part of the main thread, yes? I can see that MainActivity doesn't extend Thread, so maybe that was a dumb assumption. I don't have the feeling that anything will change if I add another class that implements Runnable/extends Thread. Will it?
MainActivity.java
public class MainActivity extends AppCompatActivity {
ArrayList<String> listItems;
ArrayAdapter<String> adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listItems = new ArrayList<>();
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listItems);
ListView listview = (ListView) findViewById(R.id.listview);
listview.setAdapter(adapter);
(new Thread(new PacketListener(adapter))).run();
}
}
PackageListener.java:
public class PacketListener implements Runnable {
ArrayAdapter<String> adapter;
public PacketListener(ArrayAdapter<String> adapter) {
this.adapter = adapter;
}
public void run() {
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
try {
DatagramSocket socket = new DatagramSocket();
socket.receive(packet);
}
catch(Exception e) {
adapter.add("Exception: " + e.toString() );
e.printStackTrace();
}
catch(Error e) {
adapter.add("Unspecified Error: " + e.toString() );
e.printStackTrace();
}
}
}
EDIT:
My latest attempt, trying to follow this page's example, has gone the route of most of my attempts, and broke the app completely. SendAnother
is a testing method bound to a button:
public void sendAnother(View view) {
adapter.add("button clicked");
new Thread(new Runnable() {
public void run() {
listview.post(new Runnable() {
public void run() {
adapter.add("inside worker thread");
}
});
}
});
}
I think next I'll finally try AsyncTask
. I no longer much care if it's "dirty".
回答1:
ui thread is main thread. you know about current thread by
Thread.currentThread().getName();
sorry i didn't read your whole question but you have to do blocking proccess in another thread than mainThread.
there are many ways to do that : AsyncTask , Services , ExecutorService and RxJava . and which one to pick depends on your need
this link would be helpful :)
回答2:
Your last method is correct, except the thread isn't started yet. So you need to call the start()
:
public void sendAnother(View view) {
//adapter.add("button clicked");
new Thread(new Runnable() {
public void run() {
listview.post(new Runnable() {
public void run() {
adapter.add("inside worker thread");
}
});
}
}).start();
}
回答3:
I'm still not sure I like AsyncTask for this project, so if someone can offer advice or a link to a tutorial to use Handler or Runnable, PLEASE post it!
Strictly speaking though, this at least finally lets me do stuff outside the UI thread, and that was the question. Sooo, for what it's worth to any others having this problem, here's what first worked for me.
public class MainActivity extends AppCompatActivity {
ArrayAdapter<String> adapter;
private static final int PORT= 8888;
private static final int TIMEOUT_MS = 500;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<String> listItems = new ArrayList<>();
ListView listview = (ListView) findViewById(R.id.lvMain);
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, listItems);
listview.setAdapter(adapter);
UpdateView task = new UpdateView();
task.execute();
//just to show these parts are in different threads
String temp = Thread.currentThread().getName();
adapter.add("onCreate: " + temp);
}
private class UpdateView extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
//just to show these parts are in different threads
String temp = Thread.currentThread().getName();
adapter.add("UpdateView: " + temp);
byte[] buf = new byte[256];
byte[] ipAddress = {(byte)192,(byte)168,0,1};
try {
InetAddress address = InetAddress.getByAddress(ipAddress);
String message = "\"xyz\"";
DatagramSocket socket = new DatagramSocket(PORT);
DatagramPacket packet = new DatagramPacket(message.getBytes(), message.length(), address, PORT);
socket.send(packet);
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
}
catch(IOException e) {
adapter.add("IO Exception: " + e.toString() );
e.printStackTrace();
}
adapter.notifyDataSetChanged();
return 0L;
}
}
}
来源:https://stackoverflow.com/questions/46369961/how-to-program-outside-the-main-ui-thread