介绍
当我们需要执行一些耗时操作时,比如发起一条网络请求,考虑到网速等因素的影响,服务器未必会立即响应我们的请求,如果不将这类操作放到子线程中去运行,会导致主线程被阻塞,从而影响用户对软件的正常使用。
线程的基本用法
Android的多线程编程基本是和Java多线程编程使用相同的语法。
继承方式
定义一个线程,只需要新建一个类继承自Thread,然后重写父类的run()方法,并在里面编写耗时逻辑即可。
class MyThread extends Thread {
@Override
public void run(){
//处理具体的逻辑
}
}
该如何启动这个线程呢?
只需要new出MyThread的实例,然后调用它的start()方法,这样run()方法中的代码就会在子线程中运行了。
new MyThread().start();
接口方式
很多时候,使用继承的方式耦合性比较高,更多的时候可以使用实现Runnable接口的方式来定义一个线程,如下所示:
class MyThread implements Runnable {
@Override
public void run(){
//处理具体的逻辑
}
}
相应的,启动方式变成如下:
MyThread myThread = new MyThead();
new Thread(myThread).start();
Thread 的构造函数接收一个 Runnable 参数,而我们 new 出的 MyThread 正是一个实现了 Runnable 接口的对象,所以可以直接将它传入到 Thread 的构造函数里,接着调用 Thread 的 start()方法,run()方法中的代码就会在子线程当中运行了。
匿名类方式
可以使用匿名类的方式来定义一个线程。
new Thread(new Runnable() {
@Override
public void run() {
// 处理具体的逻辑
}
}).start();
在子线程中更新UI
Android的UI是线程不安全的,如果想要更新应用程序中的UI元素,必须在主线程中进行,否则会出现异常。
下面用一个例子来说明:
activity_main.xml 中的代码:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/change_text"
android:text="Change Text"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/text"
android:layout_centerInParent="true"
android:text="Hello World"/>
</RelativeLayout>
MainActivity.java中的代码:
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity implements View.OnClickListener {
private TextView text;
private Button changeText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
changeText = (Button) findViewById(R.id.change_text);
changeText.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.change_text:
new Thread(new Runnable() {
@Override
public void run() {
text.setText("Nice to meet you");
}
}).start();
break;
default:
break;
}
}
}
运行之后,点击Change Text按钮,报如下错误:
那么,我们在Change Text按钮的点击事件中开启了一个子线程,在子线程中调用TextView中的setText方法,在子线程中更新了UI,结果果然出现了上面的报错。
由此也证实了Android中不允许在子线程中进行UI操作。