如何在主UI线程之外编程

时间:2017-09-22 17:14:22

标签: android multithreading udp networkonmainthread

我不知道默认情况下是否存在UI线程,如果不是,如何创建它,或者如何告诉我在" m""它它开始和结束的地方,如果是这样的话。如何确保PacketListener不是主要UI线程的一部分?

我一直在遇到 NetworkOnMainThreadException 。我理解这意味着我试图在主UI线程中做一些应该有自己独立线程的东西。但是,我无法告诉我如何实际做到这一点。

我原以为MainActivity类会成为UI线程,因为我有一个UI而且它有效。但是,我创建了一个单独的类来实现Runnable,并将网络连接的内容放在那里,我仍然得到异常,所以它仍然是主线程的一部分,是吗?我可以看到MainActivity并没有扩展Thread,所以这可能是一个愚蠢的假设。如果我添加另一个实现Runnable / extends Thread的类,我感觉不会有任何改变。会吗?

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();
        }
    }
}

编辑:

我最近的尝试,尝试按照this page's示例,已经走了大部分尝试的路线,并完全打破了应用程序。 SendAnother是绑定到按钮的测试方法:

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");
                }
            });
        }
    });
}

我想下一步我终于会尝试AsyncTask。我不再在乎它是否肮脏&#34;。

3 个答案:

答案 0 :(得分:1)

ui线程是主线程。

你知道当前的线程
Thread.currentThread().getName();
抱歉,我没有阅读你的整个问题但你必须在另一个线程中阻止proccess而不是mainThread。

有很多方法可以做到这一点:AsyncTask,Services,ExecutorService和RxJava。 哪一个选择取决于你的需要

this link会有所帮助:)

答案 1 :(得分:0)

您的上一个方法是正确的,但线程尚未启动。所以你需要调用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();
}

答案 2 :(得分:0)

我仍然不确定我喜欢这个项目的AsyncTask,所以如果有人可以提供建议或教程链接以使用Handler或Runnable,请发布它!

严格来说,这至少最终让我在UI线程之外做了一些事情,这就是问题所在。 Sooo,对于任何有这个问题的人来说,它的价值在哪里,这是我最初的工作。

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;
        }
    }
}