【问题标题】:Bluetooth thread / Handler doesn't update the UI蓝牙线程/处理程序不更新 UI
【发布时间】:2016-02-25 12:46:06
【问题描述】:

我有一个从蓝牙设备接收值的安卓应用。我第一次打开Activity 时,一切都很顺利。 Bluetooth 中的值显示在 TextView 中。

该应用由两个活动组成 --> MainDetails(详细信息包括一些片段)。

Main 活动中,用户输入一个 ID 并按下确定按钮。然后我启动蓝牙线程并使用 MAC 地址直接连接到蓝牙设备。然后我打开Details 活动。

Details 活动中,我创建了一个Handler 类,它将蓝牙设备中的值放到文本视图中。然后用户有是和否按钮来保存数据库中的值(或不保存),当按下时,他被重定向回Main活动。

第一次发生这种情况时,一切正常。但是第二次打开Details 活动时,句柄不会更新UI。我不明白为什么,如果我尝试调试,我可以看到它正常工作 -> 处理程序获取值并更新文本视图,但由于某种原因,我在 UI 中看不到它们。

有人知道问题可能是什么吗?

Handle 看起来像这样:

static class MyHandler extends Handler {
    private final WeakReference<DetailsFragment> mFragment;

    public MyHandler(DetailsFragment fragment) {
        mFragment = new WeakReference<>(fragment);
    }

    @Override
    public void handleMessage(Message msg) {
        DetailsFragment fragment = mFragment.get();
        if (fragment != null) {
            String tempValue = (String) msg.obj;
            if (tempValue != null && !tempValue.equals("")) {                   
                fragment.updateTextViewValue(tempValue.trim());
            }
        }
    }
}

这是Details活动中的取消按钮点击:

public void cancelButtonClick() {
    Intent intent = new Intent(getActivity(), MainActivity.class);
    startActivity(intent);
    getActivity().finish();
}

这是蓝牙ConnectedThread

public class ConnectedThread extends Thread {

    private final int INCOMMING = 1;

    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;

    private final Handler mHandler;

    public ConnectedThread(BluetoothSocket socket, Handler handler) {
        mmSocket = socket;
        mHandler = handler;

        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        // Get the input and output streams using temp objects, because
        // member streams are final
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {
            //log exception
        }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    public void run() {
        byte[] buffer = new byte[1024]; // buffer store for the streams
        int bytes = 0; // bytes returned from read()

        // Keep listening to the InputStream until an exception occurs
        while (true) {
            try {
                // Read from the InputStream
                buffer[bytes] = (byte) mmInStream.read();
                if ((buffer[bytes] == '\n') || (buffer[bytes] == '\r')) {
                    String value = new String(buffer, 0, bytes);
                    // Send the obtained bytes to the UI activity
                    mHandler.obtainMessage(INCOMMING, value).sendToTarget();
                    bytes = 0;
                } else
                    bytes++;
            } catch (IOException ex) {
                //log the exception
                break;
            }
        }
    }

    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {
            // log the exception
        }
    }
}

我想知道当我第二次打开Details 活动时,ConnectedThreadHandler 是否正在更新旧的TextView,但这可能吗,因为我使用的是WeakReference

【问题讨论】:

    标签: android bluetooth android-handler


    【解决方案1】:

    您的描述让我认为您可能有泄漏的活动,然后您的线程将更新不再显示的片段。 您可以尝试启动以下命令行:

    adb shell dumpsys meminfo <your.app.package>
    

    您会找到对结果here 的很好解释。 您可以在“对象”部分找到您感兴趣的内容,您可以在其中找到“活动”编号。

    你可以去你的细节活动,回到主要活动,再次进入细节,等等...... 活动数量应保持稳定。如果它增加,您的活动可能会泄漏。

    从那里,您应该寻找保留的视图/片段(我可以看到您的处理程序中有一个 WeakReference,所以您知道如何修复它)

    在这里,Memory MonitorAllocation Tracker 等分析工具肯定会有所帮助,但需要一些时间才能理解。

    【讨论】:

    • 您对泄露的活动可能是正确的,但我无法查明。我尝试运行上述命令,但不知道要查找什么。
    • 如果那是对的,你正处于一场史诗般的战斗的边缘。我会更新我的答案给你更多的弹药...
    • “你正处于史诗般的战斗边缘”——我的人生故事...感谢您的帮助!
    • 没问题,我经历过很多次,我知道这很艰难。
    • 我认为你对泄露的活动是正确的,我可以看到每次我再次启动它时返回到 Details 活动都会增加数量。
    【解决方案2】:

    假设您实际上没有更新ConnectedThreadHandler,那么问题不是“为什么不更新 UI?”而是“如何 UI 更新?”

    您需要更新帖子的mHandler 成员:

    public void setHandler( MyHandler newHandler ) {
        mHandler = newHandler;
    }
    

    然后添加

    connectedThread.setHandler( new MyHandler( this ) );
    

    到您的片段的onActivityCreated() 事件。

    根据您遇到的流量,事件总线可能是更好的实施方式。

    【讨论】:

    • 我试过了,但不幸的是它没有改变任何东西。问题是我第一次启动活动时,UI 会更新。第二次不是。应用程序没有崩溃或任何事情,代码正在运行,如果我调试,我可以看到处理程序正在获取正确的消息,但 UI 没有更新。
    【解决方案3】:

    好的,我想我没看错,当我重定向回MainActivity 时,我只需要取消ConnectThreadConnectedThread。这解决了我的问题。尴尬,但我还是个初学者。

    但是,我想我仍然对泄露的活动有疑问。但这是我将继续讨论的另一个话题。

    【讨论】:

      猜你喜欢
      • 2013-08-02
      • 2012-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多