我已将一个传感器与Android Phone
连接。传感器测量响应并在应用程序上显示相应的结果。我试图使用Java Timer
,但现在计划移动到Thread
。
在连续模式下,应用程序将完全禁用,不需要任何用户吸引。用户需要设置一些预采集设置,然后按下开始按钮。启动该按钮后,main GUI
会不断更新,但在操作过程中,用户无法与应用程序交互。用户需要再次按下"开始"按钮来停止应用程序。此时启动按钮将充当停止按钮。
我是Android的新手,所以我在网上学习,发现Asyntask
是更好的选择,而不是thread
。然后有人还提到Service
也可以更好地运行长进程或Concurrent
。我希望我的应用程序运行很长一段时间没有停止或内存泄漏。
你认为我的情况怎样比较好?在此期间,我尝试使用AsyncTask
.
这是我使用AsynTask
的代码。我希望这段代码连续运行并更新UI线程。UI
有一个图表,它将与来自后台的数据更新。
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button button = (Button) findViewById(R.id.button1); //This button will start and stop the app.
button.setOnClickListener(addOnButtonClick(button));
}
//从main按钮被按下,然后从按钮信号,Aysnctask将被调用。我刚刚实现了doInBackground
函数。
View.OnClickListener addOnButtonClick(final Button button){
return new View.OnClickListener()
{
public void onClick(View v)
{
new AsyncTaskActivity().doInBackground();
//Here i want to add one flag, which will be activated as 'true`when the
//button will be pressed once and `fasle` when the button will be pressed //second time.
//True-> activity run, false ->activity stop.
}
};
}
public class AsyncTaskActivity extends AsyncTask<Void , Void, Void>{
@Override
protected Void doInBackground(Void... params){
nativeData = getDatafromsensor(); //Data from native.
DataPoint[] data = new DataPoint[Size];
for (int i=0; i<Size; i++) {
double x = i;
double y = nativeData[i];
DataPoint v = new DataPoint(x, y);
data[i] = v;
}
}
series.resetData(data);
}
return null;
}
我认为Service
可能是长期发展的方式,但以下是AsyncTask
的发展方式。
你应该非常仔细地阅读AsyncTask文档的"用法"部分,这样你就能理解UI线程方法和后台线程方法之间的交互。在您的onClick()
方法中,您直接调用doInBackground()
,这是一个禁忌。你调用execute()
,结果doInBackground()
在另一个线程上被调用。
AsyncTask
有一个更新进度的方法。它意味着用于更新(例如)进度条(必须从UI线程完成),而后台线程仍在运行。你可以用它来实现你的目标。
创建AsyncTask
的子类来运行数据捕获线程:
public class SensorTask extends AsyncTask<Void, List<Double>, Void> {
protected void onPreExecute() {
// runs on the UI thread
// TODO set up your UI for data acquisition
}
protected Void doInBackground(Void... params) {
// TODO initialize sensor for acquisition
while (! isCancelled()) {
nativeData = getDatafromsensor(); //Data from native.
List<Double> sensorData = new ArrayList<Double>();
for (int i = 0; i < nativeData.length; i++) {
sensorData.add(new Double(nativeData[i]);
}
publishProgress(sensorData); // this invokes onProgressUpdate on UI thread
Thread.sleep(DELAY_TIME); // if you need to
}
// TODO sensor cleanup
}
protected void onProgressUpdate(List<Double>... values) {
// runs on the UI thread
// TODO update your UI with the sensor data
}
protected void onCancelled(Void result) {
// runs on the UI thread
// TODO update UI for acquisition complete
}
}
你可以这样启动它:
public void onClick(View v) {
// you need to keep a reference to the task so you can cancel it later
if (mSensorTask != null) {
// task already exists -- if running, stop it
mSensorTask.cancel(false);
mSensorTask = null;
} else {
// task doesn't exist -- make a new task and start it
mSensorTask = new SensorTask();
mSensorTask.execute();
// this will make doInBackground() run on background thread
}
};
这是很重要的:确保你在活动的onPause()
方法中取消任务,所以线程只在活动当前时运行。
编辑:使用全局数组的优点是消除了额外的对象分配。只要确保同步访问数据数组即可。下面是为使用全局数组编写AsyncTask
代码的另一种方法:
public class SensorTask extends AsyncTask<Void, Void, Void> {
protected void onPreExecute() {
// runs on the UI thread
// TODO set up your UI for data acquisition
}
protected Void doInBackground(Void... params) {
// TODO initialize sensor for acquisition
while (! isCancelled()) {
synchronized (nativeData) {
nativeData = getDatafromsensor(); // Data from native.
}
publishProgress(null); // this invokes onProgressUpdate on UI thread
Thread.sleep(DELAY_TIME); // if you need to
}
// TODO sensor cleanup
}
protected void onProgressUpdate(Void... values) {
// runs on the UI thread
synchronized (nativeData) {
// TODO update your UI with the sensor data
}
}
protected void onCancelled(Void result) {
// runs on the UI thread
// TODO update UI for acquisition complete
}
}
我使用了您的技术,并在pre
中设置了图形索引并初始化了条件。在background
的事情中,我调用本机函数并从传感器获得数据。在publish
中,我以图形形式显示该数据,为此我使用了GraphView
库。下面是代码
public class AsyncTaskActivity extends AsyncTask<Void, Double, Void> {
protected void onPreExecute() {
viewport.setMinY(0);
viewport.setMaxY(8000);
viewport.setMinX(0);
viewport.setMaxX(330);
staticLabelsFormatter = new StaticLabelsFormatter(graph);
staticLabelsFormatter.setHorizontalLabels(new String[]{"400", "500", "600", "730"});
graph.getGridLabelRenderer().setLabelFormatter(staticLabelsFormatter);
}
protected Void doInBackground(Void... params) {
while (!isCancelled()) {
synchronized (nativeData) {
nativeData = getDatafromsensor(); // Data from native.
}
publishProgress(null); // this invokes onProgressUpdate on UI thread
}
}
protected void onProgressUpdate(Void... values) {
///This one here
series.setBackgroundColor(Color.rgb((int) spec_data[WeightSize], (int) spec_data[WeightSize+1], (int) spec_data[WeightSize+2]));
series.resetData(data);
}
protected void onCancelled(Void result) {
Log.d("Updates", "I am In Cancelled");
if (mSensorTask != null)
mSensorTask.cancel(true);
}
}
问题:
问题是,在ProgressUpdate
,当我设置背景颜色。它经常闪烁。就像有时它不会显示超过30秒,即使图形完全变化。我需要睡觉吗?但"为什么"的图表正在瞬间改变?