2012-07-31 99 views
0

我写Android应用连接到蓝牙设备更新,读取从设备发送的数据,把它添加到一个AChartEngine曲线图,在一个TextView显示数据。的Android UI线程停止从其他线程

我的蓝牙代码非常类似于BluetoothChat示例代码(它配备了SDK)的线程实现。我可以看到在LogCat中,ConnectedThread循环正在执行并因此获取新数据,但我的TextView在7行之后停止更新,图表间歇性地暂停(更不用说它只是间歇性地响应交互)。 LogCat中没有显示任何错误。另外,如果我删除图形,TextView的问题仍然存在。

从我的其他线程更新的时候为什么不工作我的UI线程?


以下是我的代码的相关部分。送过来蓝牙每个串在ConnectedThread被接收并被发送到BluetoothController.addToGraph(),然后运行从viewerNewPointsAsyncTask

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; 
     } 
    } 
} 

什么给?如果需要更多代码,请告诉我。

+0

我还没有看到完整的源代码。只是一个想法。可能是错的。你不应该在你的连接线程中使用睡眠? – san 2012-08-01 03:47:22

回答

2

向后我看来......你的AsyncTask正在更新您的TextView和currentseries,但的AsyncTask应该用来为长时间运行的任务,如与其他设备/网络进行通信。你的UI线程应该做的TextView的更新和​​你有它周围的其他方法

doInBackground应该包含代码谈谈您的蓝牙设备

+0

感谢您的回答!您能否请添加一些示例代码来演示如何正确完成此操作? – 2012-08-01 01:28:27

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); 
    } 
} 
0

我正在使用achartengine和AsynkTask编写类似的应用程序。 你应该在doInBackground管理蓝牙,当你收到新的数据呼叫publishProgress对onProgressUpdate方法更新UI(TextView的和Achartengine)。 doInBackground永远不应该更新用户界面,这很奇怪,它实际上有点适合你!如果您正在绘制实时数据,并且可以运行“低”刷新。 如果没有,我会建议实施蓝牙部分作为服务,并将您的数据广播到管理和更新用户界面的活动。如果您收到大量数据,您会发现通过广播发送数据会限制您的吞吐量,因为您必须将数据类Parcelable设置为这样,而且速度非常慢,并且您很快就会受到Android绑定器架构的限制,该绑定器架构在“Localmanager.sendbroadcast ”。我发现与服务交流的最有效方式是通过使用处理程序。

如果你打算做快速实时与achartengine作图应先检查我的问题就在这里的问题,你会发现后面一个:Is achartengine ready for realtime graphing?