我正在编写一个连接蓝牙设备的Android应用,读取设备发送的数据,将其添加到AChartEngine图表,并在TextView中显示数据。
我的蓝牙代码非常类似于BluetoothChat示例代码中的线程实现(它随SDK一起提供)。我可以在LogCat中看到ConnectedThread
循环正在执行并因此获取新数据,但我的TextView在7行之后停止更新而图表间歇性停止(不是提到它只是间歇性地响应交互)。 LogCat中没有显示任何错误。此外,如果我删除图表,TextView的问题仍然存在。
为什么我的UI线程在从其他线程更新时无效?
以下是我的代码的相关部分。通过蓝牙发送的每个字符串都会在ConnectedThread
中收到并发送给BluetoothController.addToGraph()
,NewPoints
会从AsyncTask
类运行viewer
private class ConnectedThread extends Thread {
public ConnectedThread(BluetoothSocket socket, String socketType) { ... } // Initialize input and output streams here
public void run() {
while (true) {
Log.i(TAG, "READ mConnectedThread");
// Read from the InputStream
byte[] buffer = new byte[1024];
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(BluetoothController.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
Log.i(TAG, "LOOPEND mConnectedThread");
}
}
}
public class BluetoothController extends Activity {
private viewer plotter;
public static final int MESSAGE_READ = 2;
// The Handler that gets information back from the BluetoothClass
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
addToGraph(readMessage);
break;
}
}
};
protected void addToGraph(String result) {
// process the string, create doubles x and y that correspond to a point (x,y)
plotter.new NewPoints().execute(x, y);
}
}
public class viewer extends Activity {
// initialize graph, etc.
@Override
protected void onResume() {
// Create handlers for textview
textHandler = new Handler();
// Set scrolling for textview
myTextView.setMovementMethod(new ScrollingMovementMethod());
protected class NewPoints extends AsyncTask<Double, Void, Void> {
@Override
protected Void doInBackground(Double... values) {
mCurrentSeries.add(values[0], values[1]); // x, y
if (mChartView != null) {
mChartView.repaint();
}
final Double[] messages = values;
textHandler.post(new Runnable() {
@Override
public void run() {
myTextView.append("(" + messages[0].toString() + ", " + messages[1].toString() + ") \n");
}
});
return null;
}
}
}
。
{{1}}
是什么给出的?如果需要更多代码,请告诉我。
答案 0 :(得分:2)
似乎向后退了......你的AsyncTask正在更新你的textview和currentseries,但是AsyncTask应该用于长时间运行的任务,比如与其他设备/网络通信。您的UI线程应该正在更新textview,而你已经反过来了
doInBackground应包含与BlueTooth设备通信的代码
答案 1 :(得分:1)
当然,这是来自Dropbox api的一个,并展示了如何实现 当您的任务在后台进行通信工作时,进度条。 你必须为了你自己的邪恶目的修改它,但这是一个很好的例子 后台任务。
/**
* Here we show uploading a file in a background thread, trying to show
* typical exception handling and flow of control for an app that uploads a
* file
*/
public class UploadFile extends AsyncTask<Void, Long, Boolean> {
private DropboxAPI<?> mApi;
private File mFile;
private long mFileLen;
private UploadRequest mRequest;
private Context mContext;
private final ProgressDialog mDialog;
private String mErrorMsg;
public UploadFile(Context context, DropboxAPI<?> api, File file) {
// We set the context this way so we don't accidentally leak activities
mContext = context.getApplicationContext();
mFileLen = file.length();
mApi = api;
mFile = file;
mDialog = new ProgressDialog(context);
mDialog.setMax(100);
mDialog.setMessage("Uploading " + file.getName());
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setProgress(0);
mDialog.setButton(Dialog.BUTTON_POSITIVE ,(CharSequence) "Cancel", new Dialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// This will cancel the putFile operation
mRequest.abort();
}
});
mDialog.show();
}
@Override
protected Boolean doInBackground(Void... params) {
try {
// By creating a request, we get a handle to the putFile operation,
// so we can cancel it later if we want to
FileInputStream fis = new FileInputStream(mFile);
String path = mFile.getName();
mRequest = mApi.putFileOverwriteRequest(path, fis, mFile.length(),
new ProgressListener() {
@Override
public long progressInterval() {
// Update the progress bar every half-second or so
return 500;
}
@Override
public void onProgress(long bytes, long total) {
publishProgress(bytes);
}
});
if (mRequest != null) {
mRequest.upload();
return true;
}
} catch (DropboxUnlinkedException e) {
// This session wasn't authenticated properly or user unlinked
mErrorMsg = "This app wasn't authenticated properly.";
} catch (DropboxFileSizeException e) {
// File size too big to upload via the API
mErrorMsg = "This file is too big to upload";
} catch (DropboxPartialFileException e) {
// We canceled the operation
mErrorMsg = "Upload canceled";
} catch (DropboxServerException e) {
// Server-side exception. These are examples of what could happen,
// but we don't do anything special with them here.
if (e.error == DropboxServerException._401_UNAUTHORIZED) {
// Unauthorized, so we should unlink them. You may want to
// automatically log the user out in this case.
} else if (e.error == DropboxServerException._403_FORBIDDEN) {
// Not allowed to access this
} else if (e.error == DropboxServerException._404_NOT_FOUND) {
// path not found (or if it was the thumbnail, can't be
// thumbnailed)
} else if (e.error == DropboxServerException._507_INSUFFICIENT_STORAGE) {
// user is over quota
} else {
// Something else
}
// This gets the Dropbox error, translated into the user's language
mErrorMsg = e.body.userError;
if (mErrorMsg == null) {
mErrorMsg = e.body.error;
}
} catch (DropboxIOException e) {
// Happens all the time, probably want to retry automatically.
mErrorMsg = "Network error. Try again.";
} catch (DropboxParseException e) {
// Probably due to Dropbox server restarting, should retry
mErrorMsg = "Dropbox error. Try again.";
} catch (DropboxException e) {
// Unknown error
mErrorMsg = "Unknown error. Try again.";
} catch (FileNotFoundException e) {
}
return false;
}
@Override
protected void onProgressUpdate(Long... progress) {
int percent = (int)(100.0*(double)progress[0]/mFileLen + 0.5);
mDialog.setProgress(percent);
}
@Override
protected void onPostExecute(Boolean result) {
mDialog.dismiss();
if (result) {
showToast("File successfully uploaded");
} else {
showToast(mErrorMsg);
}
}
答案 2 :(得分:0)
我正在使用achartengine和AsynkTask编写类似的应用程序。 您应该在doInBackground中管理蓝牙,并在接收新数据时调用publishProgress来更新onProgressUpdate方法上的UI(TextView和Achartengine)。 doInBackground永远不应该更新UI,它真的很适合你!如果您使用“低”刷新来绘制实时数据,那将是有效的。 如果不是,我建议将蓝牙部分作为服务实施,并将您的数据广播到管理和更新UI的活动。如果您收到大量数据,您会发现通过广播发送数据会限制您的吞吐量,因为您必须使您的数据类Parcelable并且速度非常慢,并且您很快就会在“Localmanager.sendbroadcast”上使用Android的binder arquitecture达到极限”。我发现与服务通信的最有效方式是使用处理程序。
如果您打算使用achartengine进行快速实时图表制作,请先在此处查看我的一个问题,了解您稍后会发现的问题:Is achartengine ready for realtime graphing?