什么是进程
一个进程是一个独立(self contained)的运行环境,它可以看作一个程序或者一个应用。
什么是线程
而线程是进程中执行的一个任务,Java运行环境是一个包含了不同累和程序的单一进程。线程可以被称为轻量级进程。线程需要较少的资源来创建和驻留在进程中,并且可以共享进程中的资源。
Android线程
Android的线程,实际上和Java的多线程编程并没有什么本质上的不同。当我们需要执行一些耗时操作,比如说发起一条网络请求时,考虑到网速等其他原因,服务器未必会立刻响应我们的请求,如果不将这类操作放在子线程中运行,就会导致主线程被阻塞住,从而影响用户对软件的正常使用。
线程的基本用法
Android多线程编程其实并不比Java多线程特殊,基本都是使用相同的语法。有两种创建线程的方法:
一是新建一个继承自Thread的类,然后重写父类的run()方法,并在里面编辑耗时逻辑即可,如:
1 public class MyThread extends Thread{
2 @Override
3 public void run(){
4 //具体处理的逻辑
5 }
6 }
启动这个线程的方法也很简单,只需要new出MyThread的实例,然后调用它的start方法,这样run()方法中的代码就会在子线程中运行,如
new MyThread().start();
然而,使用继承的耦合性比较高,更多的时候使用实现Runnable接口是一个不错的选择,如:
1 public class MyThread implements Runnable{
2 @Override
3 public void run(){
4 //具体处理的逻辑
5 }
6 }
如果使用了这种写法,启动线程的方法也需要进行相应的改变,如:
MyThread myThread = new MyThread();
new Thread(myThread).start();
可以看到,Thread的构造函数接收一个Runnable参数,而new出的MyThread正是一个实现了Runnable接口的对象,所以可以将它直接传入到Thread的构造函数里。接着调用Thread的start()方法,run()方法中的代码就会在子线程中运行。
Android中的多线程
和许多其他的GUI库一样,Android的UI也是线程不安全的。也就是说,如果想要更新应用中的UI元素,则必须在主线程中进行,否则就会出现异常。
举个例子,新建一个AndroidThreadTest的项目,然后修改activity中的代码
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:id="@+id/change_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Change text"/>
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello world"
android:textSize="20sp"/>
</RelativeLayout>
布局文件中定义了两个控件,TextView用于在屏幕正中间显示一个Hello World字符串,Button用于改变TextView中显示的内容。我们希望在点击Button后可以把TextView中显示的字符串改成Nice to meey you.
接下来修改MainActivity中的代码:
1 public class MainActivity extends Activity implements OnClickListener{
2
3 private Button changeText;
4 private TextView text;
5
6 @Override
7 protected void onCreate(Bundle savedInstanceState) {
8 super.onCreate(savedInstanceState);
9 setContentView(R.layout.activity_main);
10 text = (TextView)findViewById(R.id.text);
11 changeText = (Button)findViewById(R.id.change_text);
12 changeText.setOnClickListener(this);
13 }
14
15 @Override
16 public boolean onCreateOptionsMenu(Menu menu) {
17 // Inflate the menu; this adds items to the action bar if it is present.
18 getMenuInflater().inflate(R.menu.main, menu);
19 return true;
20 }
21
22 @Override
23 public void onClick(View v) {
24 // TODO Auto-generated method stub
25 switch (v.getId()) {
26 case R.id.change_text:
27 new Thread(new Runnable() {
28
29 @Override
30 public void run() {
31 // TODO Auto-generated method stub
32 text.setText("Nice to meet you");
33 }
34 }).start();
35 break;
36
37 default:
38 break;
39 }
40 }
41
42 }
可以看到,在change text按钮的点击事件中开启了一个子线程,然后在子线程中调用TextView的setText()方法去改变字符串,代码的逻辑非常简单,但是就是按下按钮然后更新文本,然后运行一下程序,可以发现程序不出所料的将会崩溃。
程序崩溃的原因是因为在子线程中更新UI所导致的,由此可以看到Android不允许在子线程进行UI操作。但有些时候我们必须在子进程中去执行一些耗时任务,然后根据任务的执行结果来更新相应的UI控件,对于这种情况,就需要使用Android提供的一套异步消息处理机制了。