【问题标题】:Am I using this Handler and Executor correctly (Android)?我是否正确使用了这个处理程序和执行程序(Android)?
【发布时间】:2018-06-27 08:48:58
【问题描述】:

我有一个执行器,它运行一个 while true 循环,它只是用数据 ping 一个服务器。现在我需要用这些数据更新 UI,所以我使用了一个处理程序。

在我的主要活动中,我有:

private void createGeneralHandler() {
    generalHandler = new Handler(Looper.getMainLooper()){
        @Override


    public void handleMessage(Message msg){

                switch (msg.what){
                    case SERVER_RESPONSE:

                        serverTextView.append("\n"+msg.obj);
                        break;

                    default:
                        super.handleMessage(msg);
                }
            }
        };
    }

这会在名为generalHandler 的主活动中创建一个字段。

现在NetworkTask runnable 需要知道这个处理程序才能将消息发送到正确的位置?

所以我的主要活动中有这个:

networkExecutor = Executors.newSingleThreadExecutor();
networkTask = new NetworkTask(serverIPAddress, serverPort);
networkTask.setRequest("I WANT DATA");
networkTask.setHandler(generalHandler); //IS THIS WRONG ???
networkExecutor.execute(networkTask);  

networkTask 只是一个单独文件中的 Runnable,定义如下:

public class NetworkTask implements Runnable {

    private int port;
    private String ipAddress;
    private int pollInterval;
    private Socket socket = null;
    private PrintWriter out = null;
    private BufferedReader br = null;
    private String request = null;
    private String response = null;
    private static final int SERVER_RESPONSE = 1;
    private Handler handler = null;

    public NetworkTask(String ipAddress, int port){
        this.port = port;
        this.ipAddress = ipAddress;
        this.pollInterval = 50;
    }

    @Override
    public void run() {

        try {
            socket = new Socket(ipAddress, port);
            out = new PrintWriter(socket.getOutputStream(), true);
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            while (!Thread.currentThread().isInterrupted()) {

                Thread.sleep(pollInterval);

                out.println(request);
                try {
                    response = br.readLine();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if(!response.equals("doNothing")){
                    Message message = new Message();
                    message.what = SERVER_RESPONSE;
                    message.obj = response;
                    handler.sendMessage(message);
                }else if(response.equals("Nothing Connected to Server!")){
                    Message message = new Message();
                    message.what = SERVER_RESPONSE;
                    message.obj = response;
                    handler.sendMessage(message);
                }
            }
        } catch (InterruptedException threadE) {
            try {
                br.close();
                out.close();
                socket.close();
            } catch (IOException socketE) {
                socketE.printStackTrace();
            }
            Log.i("NETWORK_TASK_THREAD", "NETWORK TASK closed gracefully!");
        }

    }

    public void setRequest(String request) {
        this.request = request;
    }

    public void setHandler(Handler handler) {
        this.handler = handler;
    }
}

【问题讨论】:

  • 与 Handler 关联的 Looper 用于主线程。这怎么不会导致 NetworkOnMainThreadException?
  • @MichaelKrause 我没有在主线程上进行任何网络操作。我只是得到一个服务器响应并将其显示在 textView 上。我是不是做错了什么?

标签: java android


【解决方案1】:

对您的问题的回答会有点武断。由于实现只是一种设计选择,没有对错之分,而是好与不好。

以下是我想强调的几点:

  • 如果您只是担心networkTask.setHandler(generalHandler);,那么只要您不在主线程上调用任何网络调用或繁重的处理就可以了。
  • 您还需要确保您的 Runnable 在应用程序onStop()onDestroy() 中被适当地中断,以避免潜在的内存泄漏。
  • 您不断尝试 ping 服务器,这不是一个好主意,因为它会消耗资源并耗尽电池。您可以定期执行这些任务或使用 FCM 推送。
  • 对于关闭 InputStreams 或 OutputStreams,它被认为是在 finally {..} 块中进行清理的良好做法,这样可以确保在执行期间发生一些其他异常时进行清理。

另一种方法是实现ViewModelMutableLiveData 并执行操作。这不会因不必要的处理而使您的 Activity 膨胀。

【讨论】:

  • 好的,感谢您的反馈。服务器一直在发送数据,所以我必须不断地 ping 它。你可以看到我有一个 Thread.sleep(pollInterval);定期进行。你有什么建议?
  • @TrtTrt ping 持续时间太短。我会建议使用 JobScheduler/Workmanager,但它的最短持续时间是 15 分钟
  • 所以增加 ping 会有帮助吗?我不确定我应该遵循什么方法。
  • @TrtTrt 如果不需要如此频繁地 ping,则使用 WorkManager 安排定期工作,频率为 15 分钟。即使应用程序未运行,这也将保证执行工作。你可以在这个So查看我的答案
  • 有必要尽可能频繁地 ping,这是我认为的主要问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-23
相关资源
最近更新 更多