我有一个Android应用程序,它从线程A中的BLE设备接收ASCII字符串(因此字符串中的每个字符恰好对应一个字节)。
这些字符串有最大长度的块。例如,假设最大长度为4,我们收到以下字符串:
" ABCD" (4)," EFGH" (4)," I \ r \ n" (3)
另一方面,我有另一个线程B需要读取这些字符串,但作为一个完整的行。在该示例中,在接收到所有三个数据包之后,该线程应该读取一行:
" ABCDEFGHI"
我的第一个赌注是使用公共底层BlockingQueue实现自定义InputStream和OutputStream。然后使用OutputStreamWriter写入线程A中的传入字符串和包装在BufferedStream中的InputStreamReader,以使用线程B中的readLine()函数,但它不起作用。
我可以看到在线程A上使用自定义OutputStream时,字节(块)被添加到队列中但是当我从线程B调用readLine()时,它会阻塞并且永远不会返回字符串,即使我知道整行已经已添加到基础队列。
我非常确定我在这里重新发明轮子,而且我一直无法在网上找到明确的答案。必须有更好的方法在Java / Android中执行此操作。这听起来像是一种非常常见的模式。
我主要在C#做事,所以可能会有一些我缺少的课程。我也看了看ByteBuffer,但似乎这样做迫使我实现自己的readLine()函数,因为BufferedReader等没有使用的InputStream。
答案 0 :(得分:0)
您可以使用 Greenrobot's EventBus 轻松地在线程之间发送数据。
Greenrobot的EventBus是一个允许组件(活动,片段,服务和背景线程)之间进行通信的库。
的build.gradle
dependencies {
compile 'org.greenrobot:eventbus:3.0.0'
}
<强> 1。听众(主题A)
public class BleListener{
private static Context _context;
private static BleListener _instance;
private static ListenerThread _listenerThread;
private static boolean _isListenerThreadEnable = false;
private BleListener(Context context){
_context = context;
// set ble config and open ble port in here
// ....
// enable listener thread
if (!_isListenerThreadEnable) {
_listenerThread = new ListenerThread();
_listenerThread.start();
_isListenerThreadEnable = true;
}
}
// call this function from outer class
public static BleListener getInstance(Context context) {
if (_instance == null) {
_instance = new BleListener(Context context);
}
return _instance;
}
private class ListenerThread extends Thread {
ListenerThread() {
// setting your receive buffer, thread priority in here
}
@Override
public void run() {
while (_isListenerThreadEnable) {
synchronized (_bleDevice) {
int _receivedCount = _bleDevice.getQueueStatus();
while (_receivedCount > 0) {
// append your received data in here with ByteBuffer or StringBuffer
// ..
// parsing data for get valid data
// ..
// send valid data out when receive special character (end of message flag) or when timeout received with EventBus
EventBus.getDefault().post( ValidModal);
}
}
Thread.Yield();
}
}
}
}
<强> 2。 MAIN(线程B - 从线程A读取数据)
订户还需要在总线上注册和注销。只有在订阅者注册时,他们才会收到活动。在Android中,在活动和片段中,您通常应该根据其生命周期进行注册。对于大多数情况,onStart / onStop工作正常:
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
订阅者实现在发布事件时将调用的事件处理方法(也称为“订阅者方法”)。这些是使用@Subscribe注释定义的。
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(ValidModal) {
// You will get valid data from thread A here.
//..
}
答案 1 :(得分:0)
根据Ted Hopp的推荐,我最终使用了 PipedInputStream 和 PipedOutputStream (包含在OutputStreamWriter和BufferedReader中)。
它像魅力一样,完全符合我的需要。谢谢!