我不确定我的提示是否正确,因为我没有得到预期的输出。我有一个类,我在其中调用一个应该启动一个线程的方法。
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
beginListenForData()
}
beginListenForData函数用于启动一个线程并检查数据是否有数据供读取。如果是这种情况,它会读取并更新UI变量:
void beginListenForData()
{
Thread workerThread = new Thread(new Runnable() {
@Override
public void run()
{
int bytesAvailable = 3;
while(!Thread.currentThread().isInterrupted())
{
try
{
bytesAvailable = mmInStream.available();
if(bytesAvailable > 0)
{
byte[] packetBytes = new byte[bytesAvailable];
mmInStream.read(packetBytes);
bytesAvailable = mmInStream.available();
String s = new String(packetBytes);
text.setText(s);
}
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
workerThread.start();
}
}
我没有得到所需的输出。该线程应该读取数据或检查数据是否可用。如果可用,则读取它并将UI变量设置为读取的值。
我正确地执行了吗?我的代码中有什么问题吗?
答案 0 :(得分:4)
正常Thread
should not access the UI thread。我建议使用AsyncTask
而不是在Android中使用标准线程或Runnables。 AsyncTask
可用于同时远离UI线程,然后对其进行更改。 doInBackground()
方法中调用的所有内容都远离主UI线程,而onPreExecute()
和onPostExecute()
方法中调用的所有内容都可以与您的UI进行良好的交互。
当您从UI线程上运行的某个东西调用新线程时,建议使用AsyncTask
(如Activity
,就像在您的实例中一样)。以下示例;
public class YourAsyncTask extends AsyncTask{
@Override
protected Object doInBackground(Object... arg0) {
// Work to be done in the background.
return null;
}
@Override
protected void onPostExecute(String result) {
// Changes to be made to UI
}
@Override
protected void onPreExecute() {
// Changes to be made to UI
}
}
然后你可以像这样从你的活动中运行AysncTask
;
new YourAsyncTask().execute("");
要处理Activity
,您可能需要为AysncTask
创建自定义构造函数,并通过构造函数将活动实例传递给它,以存储在实例变量中。我希望这会有所帮助。
更多信息;
答案 1 :(得分:2)
text.setText(s);
您无法从工作线程中触摸UI。它应该是执行text.setText(s);
答案 2 :(得分:2)
线程无法更新GUI
您可以使用runOnUiThread()
方法或使用Handler
编辑:处理程序示例: How to use an Android Handler to update a TextView in the UI Thread?
答案 3 :(得分:0)
所以这就是我将如何做到这一点
创建活动的成员变量:
private BackgroundWorkerThread m_bgThread = null;
protected Handler m_bgHandler = null;
请参阅下面的BackgroundWorkerThread类,然后在onCreate()中初始化主活动中的线程和处理程序:
// Notice we pass the Handler Constructor this because we are implementing the interface
// in our activity
m_bgHandler = new Handler(this)
m_bgThread = new BackgroudnWorkerThread();
m_bgThread.start();
确保您拥有活动implements Handler.Callback
界面,该界面会将此方法添加到您的活动中:
@Override public boolean handleMessage(Message msg)
{
switch(msg.what){
case 0:
// Will update the UI on the Main Thread
updateUI(msg.obj);
break;
case 1:
// rejoin the Thread with the main Thread
try {
m_bgThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
return true;
}
在每个case语句中,您将消息传递给后台线程。
例如在您的活动中的某个地方调用sendFirstMessage():
public void sendFirstMessage(){
// Passes the 0 to the background Handler handleMessage
m_bgThread.workerHandler.obtainMessage(0).sendToTarget();
}
然后在Activity的处理程序handleMessage()覆盖
case 0:
updateUI(msg.obj);
break;
然后
public void updateUI(Object obj){
text.setText(obj.toString());
// Call to tell Background Thread to shut down looper
m_bgThread.workerHandler.obtainMessage(1).sendToTarget();
// Call to tell the Main Thread no more updates needed
m_bgHandler.obtainMessage(1).sendToTarget();
}
然后将您的后台线程类创建为您的活动的子类:
private class BackgroundWorkerThread extends Thread implements Handler.Callback{
private Looper workerLooper;
protected Handler workerHandler;
@Override public void run()
{
// Set up the Handler and Looper
Looper.prepare();
workerLooper = Looper.myLooper();
workerHandler = new Handler(workerLooper, this);
Looper.loop();
}
@Override public boolean handleMessage(Message msg)
{
switch(msg.what){
case 0:
// now this function is being called to run on the background Thread
beginListenForData();
break;
case 1:
workerLooper.quit();
break;
}
return true;
}
}
// This method is now being execute in the background
public void beginListenForData()
{
int bytesAvailable = 3;
while(!Thread.currentThread().isInterrupted())
{
try{
bytesAvailable = mmInStream.available();
if(bytesAvailable > 0)
{
byte[] packetBytes = new byte[bytesAvailable];
mmInStream.read(packetBytes);
bytesAvailable = mmInStream.available();
String s = new String(packetBytes);
// Instead of trying to set the text view here, send a message back to
// the Activity to update the UI on the Main thread
// text.setText(s);
// Passes 0, and the String Object to the Activity Handler
m_bgHandler.obtainMessage(0, s).sendToTarget();
}
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
这有点困难,但这就是它的完成方式,手动创建一个线程,使用looper在后台检查消息,然后将消息从后台线程传递给活动以更新UI。
祝你好运!任何问题随时都可以问。或者您可以从http://android-developers.blogspot.com/2009/05/painless-threading.html
采取最简单的路线可能的意识形态 public void beginListenForData()
{
String s = null;
new Thread(new Runnable(){
public void run(){
int bytesAvailable = 3;
while(!Thread.currentThread().isInterrupted())
{
try{
bytesAvailable = mmInStream.available();
if(bytesAvailable > 0)
{
byte[] packetBytes = new byte[bytesAvailable];
mmInStream.read(packetBytes);
bytesAvailable = mmInStream.available();
s = new String(packetBytes);
// Takes Care of updating the UI
text.post(new Runnable(){
public void run(){
text.setText(s);
}
});
}
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
答案 4 :(得分:-1)
您先致电super.onCreate(savedInstanceState);
吗?
然后你必须致电setContentView(R.layout.yourlayout);
。
为什么bytesAvailable
设置为3而不是0?
为什么bytesAvailable = mmInStream.available();
被调用两次?只有一个就足够了!
然后mmInStream
和text
(!important!text = (TextView) findViewById(R.id.thetextviewid);
)在某处初始化了吗?
如果所有这些都完成了,一切都应该没问题。
编辑:最后您 致电text.postInvalidate();