什么是进程
一个进程是一个独立(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提供的一套异步消息处理机制了。