如何在主UI线程之外编写程序

13 浏览
0 Comments

如何在主UI线程之外编写程序

我不知道是否有默认的UI线程,如果没有,我也不知道如何创建它,或者如何确定它的开始和结束时间。我如何确保PacketListener不是主UI线程的一部分?

我一直遇到NetworkOnMainThreadException异常。我知道这意味着我在主UI线程中尝试做一些应该有自己独立线程的事情。然而,我找不到很多关于如何实际做到这一点的信息。

我原以为MainActivity类就是UI线程,因为它有一个UI并且工作正常。然而,我创建了一个实现了Runnable接口的独立类,并在其中放置了网络连接的内容,但仍然遇到异常,所以它仍然是主线程的一部分,对吗?我可以看到MainActivity没有继承Thread,所以也许这是一个愚蠢的假设。如果我添加另一个实现Runnable/继承Thread的类,我没有感觉任何事情会改变。会吗?


MainActivity.java

public class MainActivity extends AppCompatActivity {
    ArrayList listItems;
    ArrayAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listItems = new ArrayList<>();
        adapter = new ArrayAdapter(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 adapter;
    public PacketListener(ArrayAdapter 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();
        }
    }
}

编辑:

我最新的尝试,试图按照这个页面的示例,走了大多数尝试的路线,并完全破坏了应用程序。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。我不再太在乎它是否"脏"。

0
0 Comments

如何在主UI线程之外进行编程

问题的出现原因:

- 代码中的线程没有被启动,需要调用start()方法来启动线程

- 主线程不能执行耗时操作,否则会抛出NetworkOnMainThreadException异常

解决方法:

- 在需要在主UI线程之外执行的代码块中,创建一个新的线程,并在该线程中执行代码

- 在新线程中,通过post()方法将需要在主UI线程中执行的代码封装成一个Runnable对象,并使用listview.post()方法将其提交给主UI线程执行

- 最后,调用start()方法启动新线程

以下是示例代码:

public void sendAnother(View view) {
  new Thread(new Runnable() {
    public void run() {
      listview.post(new Runnable() {
        public void run() {
          adapter.add("inside worker thread");
        }
      });
    }
  }).start();
}

除了以上解决方法外,还需要注意:

- 避免在主UI线程中执行耗时操作,可以使用多线程来处理耗时任务,以避免阻塞主线程导致界面卡顿或无响应的情况发生

- 如果出现其他问题,可以检查代码是否有其他错误,或者尝试创建一个全新的项目来排除可能的问题

希望以上解决方法能够帮助解决问题。如果问题仍然存在,请持续跟踪并解决其他可能的错误或异常。

0
0 Comments

在这段代码中,我们可以看到在MainActivity的onCreate方法中,创建了一个AsyncTask子类的对象UpdateView,并调用了其execute方法。在UpdateView的doInBackground方法中,执行了一些耗时的任务,包括发送和接收数据报文。然后在doInBackground方法中,通过adapter.add方法更新了UI界面。

这段代码的问题在于,耗时的任务是在UI线程中执行的,而不是在主UI线程之外的线程中执行。这可能导致UI界面的卡顿或响应延迟。为了解决这个问题,我们需要将耗时的任务放在主UI线程之外的线程中执行。

解决这个问题的方法是使用Handler或Runnable。下面是一个使用Handler的示例代码:

public class MainActivity extends AppCompatActivity {
    ArrayAdapter<String> adapter;
    private static final int PORT= 8888;
    private static final int TIMEOUT_MS = 500;
    private Handler handler = new Handler();
    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);
        //just to show these parts are in different threads
        String temp = Thread.currentThread().getName();
        adapter.add("onCreate: " + temp);
        new Thread(new UpdateViewRunnable()).start();
    }
    private class UpdateViewRunnable implements Runnable {
        public void run() {
            //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();
            }
            handler.post(new Runnable() {
                public void run() {
                    adapter.notifyDataSetChanged();
                }
            });
        }
    }
}

在这个示例代码中,我们创建了一个Handler对象,并在主UI线程中初始化。然后,在onCreate方法中创建一个新的线程,并在该线程中执行耗时的任务。在耗时的任务执行完毕后,我们使用handler.post方法来将更新UI界面的代码放在主UI线程中执行。

这样,我们就解决了在主UI线程之外执行耗时任务的问题,并避免了UI界面的卡顿或响应延迟。

0
0 Comments

在Android开发中,UI线程是主线程,负责处理用户界面的更新和事件响应。然而,有时候我们需要在应用程序的其他线程中执行一些耗时的操作,以避免阻塞UI线程,提高用户体验和应用程序的响应性。

为了解决这个问题,我们可以使用以下几种方法来在主UI线程之外编程:

1. AsyncTask(异步任务):AsyncTask是Android提供的一种用于在后台执行异步操作的工具类。它允许我们在UI线程之外执行耗时的操作,并在操作完成后更新UI线程。可以通过继承AsyncTask类并实现它的几个方法来使用它。

2. Services(服务):Service是一种在后台运行的组件,没有用户界面。我们可以创建一个Service来执行需要在后台进行的任务,并通过与UI线程进行通信来更新UI。

3. ExecutorService(执行器服务):ExecutorService是Java提供的一个用于管理线程池的接口。通过创建一个ExecutorService对象,并将任务提交给它来执行,我们可以在UI线程之外创建新的线程,并在需要时控制线程的数量。

4. RxJava:RxJava是一个用于异步编程和事件驱动的库。它提供了丰富的操作符和函数式编程的方式来处理异步操作,使得在UI线程之外编程变得更加简单和可读。

选择使用哪种方法取决于你的需求和应用程序的复杂性。你可以通过参考这个链接来获取更多信息:https://stackoverflow.com/a/4722985/6540997

如果你想了解如何在Android中创建一个新的线程,可以尝试实现Runnable接口来创建一个新的线程。然而,这种方式可能不是最佳实践,因为它需要手动管理线程的生命周期和与UI线程的通信。

如果你想深入学习Java和Android中的多线程编程,可以通过谷歌搜索“Multithreading in Java”来找到相关的教程和资料。

希望这些信息对你有所帮助。如果你有其他问题,请随时提问。

0