问题:
初学者在使用联网操作时,如果基础没打好,可能出以下差错:
在子线程中更新类变量,然后使用该变量来更新控件属性,第一次控件是没反应的,第二次控件的属性才被更新。
请看示例代码:
示例里面有个类变量data
,整个demo的逻辑就是点击Button后开启子线程发起post请求,将数据赋值给data
,然后在子线程操作完后把类变量里面的东西更新给Textview
public class MainActivity extends AppCompatActivity {
Button send;
TextView textView;
String data;
void initView(){
send = (Button) findViewById(R.id.send);
textView = (TextView) findViewById(R.id.text_view);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
try{
// Post request example:
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.build();
Request request = new Request.Builder()
.url("https://www.baidu.com")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
data = response.body().string();
System.out.println(data);
} catch (Exception e){
e.printStackTrace();
}
}
}).start();
textView.setText(data);
}
});
}
}
如何解决:
当数据取得后,随后回到主线程,直接把取得的数据赋值更新给控件。
public class MainActivity extends AppCompatActivity {
Button send;
TextView textView;
//String data;
void initView(){
send = (Button) findViewById(R.id.send);
textView = (TextView) findViewById(R.id.text_view);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
try{
// Post request example:
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.build();
Request request = new Request.Builder()
.url("https://www.baidu.com")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
String data = response.body().string();
switchThread(data);
System.out.println(data);
} catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
});
}
private void switchThread(final String content){
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText(content);
}
});
}
}
原因:
第一次更新失败是因为某ui控件尚未被赋值,类变量仍然为空;第二次更新成功是因为连续开启了两个子线程(第二次点击开启了第二个子线程),当第二个子线程开启时候第一个子线程便被终止,子线程内的成员变量赋值给类变量,ui控件获得值后便被更新成功
总结:
对于初学者而言,Handler
、runOnUiThread()
、Thread
等是其永远绕不开的东西,因此不要想着偷来用巧方法,否则会弄巧成拙。