我正在尝试编写代码来每秒为服务器提取更新的消息。然后,消息将显示在文本视图中。如果我不更改文本视图中的文本它运行正常。如果我尝试更改线程上的textview,它将崩溃。如果我改变它不在线程上工作正常。
我假设线程无法访问主线程内存?如何在视图中设置刚刚通过互联网加载的文本?
在下面的代码中,我有一个线程,它通过睡眠进行无限循环。它调用一个名为SendMessage的方法。发送消息通过Internet加载文本,最后尝试使用它更新视图。发生这种情况时会引发异常。
代码:
public class cChat extends cBase implements OnClickListener {
/** Called when the activity is first created. */
TextView mUsers;
TextView mComments;
int i=0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat);
mUsers=( TextView) findViewById(R.id.viewusers);;
mComments=( TextView) findViewById(R.id.viewchats);;
Thread thread = new Thread()
{
@Override
public void run() {
try {
int t=0;
while(true)
{
SendMessage();
sleep(1000*5);
t++;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
public void onClick(View v) {
} // end function
// send a uypdate message to chat server
// return reply in string
void SendMessage()
{
try {
URL url = new URL("http://50.63.66.138:1044/update");
System.out.println("make connection");
URLConnection conn = url.openConnection();
// set timeouts to 5 seconds
conn.setConnectTimeout(1000*5);
conn.setReadTimeout(5*1000);
conn.setDoOutput(true);
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
// String line;
String strUsers=new String("");
String strComments=new String("");
String line=new String();
int state=0;
while ((line= rd.readLine() ) != null) {
switch(state){
case 0:
if ( line.contains("START USER"))
state=1;
if ( line.contains("START COMMENTS"))
state=2;
break;
case 1:
if ( line.contains("END USER"))
state=0;
else
{
strUsers+=line;
strUsers+="\n";
}
break;
case 2:
if ( line.contains("END COMMENTS"))
state=0;
else {
strComments+=line;
strComments+="\n";
}
break;
} // end switch
} // end loop
// the next line will cause a exception
mUsers.setText(strUsers);
mComments.setText(strComments);
} catch (Exception e) {
i++; // use this to see if it goes here in debugger
// System.out.println("exception");
// System.out.println(e.getMessage());
}
} // end methed
}
答案 0 :(得分:3)
将runOnUiThread用作
YOUR_CURRENT_ACTIVITY.this.runOnUiThread(new Runnable() {
@Override
public void run() {
// the next line will cause a exception
mUsers.setText(strUsers);
mComments.setText(strComments);
//....YOUR UI ELEMENTS
}
});
编辑: 见doc runOnUiThread
答案 1 :(得分:0)
您无法从不同于创建它的线程(UI线程)触摸UI小部件。但是,如果你有Activity
的引用,你可以这样做:
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
mUsers.setText(strUsers);
mComments.setText(strComments);
}
});
这将要求匿名类可以访问strUsers
。为此你可以做到:
final String finalUseres = strUsers;
并在finalUsers
内使用run()
。
答案 2 :(得分:0)
the Andoid UI toolkit is not thread-safe. So, you
must not manipulate your UI from a worker thread
要解决此问题,Android提供了几种从其他线程访问UI线程的方法。以下列出了可以提供帮助的方法:
您也可以使用AsyncTask。
答案 3 :(得分:0)
您可以使用处理程序将任务(Runnables)发布到UI /主线程:
private Handler handler = new Handler();
//...
Thread thread = new Thread()
{
@Override
public void run() {
try {
int t=0;
while(true)
{
handler.post(new Runnable() {
@Override
public void run() {
SendMessage();
}
});
sleep(1000*5);
t++;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
答案 4 :(得分:0)
尝试使用Service
连续向服务器提取/发送数据。这将减少UI-Thread的负载。