相信大家对于什么是android进程和线程的理论应该都有所了解了,不清楚的可以查看这篇文章
android进程和线程
下面进一步学习,如何实现线程和多线程
什么是单线程,什么是多线程?先看这张图
多线程:它是一组指令的集合,在控制流程语句当中,每一个线程就是一条控制语句,线程与线程之间是可以实现数据共享的,所谓多线程,在某一个时间片段同时有多个任务在一起执行。
线程运行过程中的生命周期
这里不细讲过程
下面才是重点,线程实现的方法,我们先看看java里的线程
java实现线程有两种方式:
■继承Thread类
步骤如下:
1、定义一个普通类去继承Thread类,则表明此类是一个线程类。
语法结构:
public class 类名 extends Thread{}
2、重写父类中的run方法
语法结构:
public void run() {
//线程的执行体
}
3、使用线程
调用start方法来执行线程
语法结构:
线程对象名.start();
■实现Runnable接口
步骤如下
1、定义普通类去实现Runnable接口
语法结构:
public class 类名 implements Runnable{}
2、重写run方法
3、启动线程
-定义自己的线程对象
MyThread myThread = new MyThread();
-定义系统的线程对象,把自己的线程对象作为参数传递到系统的线程对象
Thread thread = new Thread(myThread);
-调用start方法执行:thread.start()
当然这两个方式是有区别和优缺点的
采用继承Thread类方式:
(1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。
(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。
采用实现Runnable接口方式:
(1)优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。
我们再来看看android的线程
Android和Java一样,它支持使用Java里面的Thread类来进行一步任务处理。所以可以轻松地像上面Java的例子一样来使用Android上的线程,
但是在
android进程和线程
文章里说过
Android UI工具包不是线程安全的。所以,你不能从一个工作线程中操作你的用户界面,你必须从用户界面中对用户界面做所有的操作。因此,有简单的规则,以Android的单线程模型:
•不要阻塞用户界面线程
•不访问用户界面线程以外的安卓用户界面工具包
所以android的线程实现方式跟java一样有两种,但是处理方法有区别
下面我们来看看
说到线程不得说Handler,它是线程间通信的桥梁,Handler的细节在这里
android的消息处理机制
我们直接上程序
Handler消息处理机制
public class MyHandler extends Handler{
public void handleMessage(Message msg){
switch(msg.what){
case 1 :
//处理消息,例如更新UI
break;
case 2 :
//处理消息
break;
default : break;
}
}
}
或者可以这样写
Handler mHandler = new Handler(){
public void handleMessage(Message msg){
switch(msg.what){
case 1 :
//处理消息,例如更新UI
break;
case 2 :
//处理消息
break;
default : break;
}
}
}
然后 通过new得到一个对象实例
MyHandler mHandler = new MyHandler();
向消息队列发送消息可以使用下列方法发送
mHandler.sendMessage(message);
mHandler.postDelayed(Runnable r, long delayMillis);
mHandler.sendEmptyMessage(int what);
mHandler.sendMessage(Message msg);
mHandler.sendEmptyMessageAtTime(int what, long uptimeMillis);
然后开始创建线程
方式一:继承Thread类
步骤和java创建差不多,直接上程序
public class MyThread extends Thread{
public void run(){
//消息执行体,创建消息并发送到消息队列就在这里发送,如:
Message message =new Message();//得到一个消息对象
message.what=1;//给消息做标记,当handler获取消息时就知道是那个
message.obj=msg;//需要发送的数据
mHandler.sendMessage(message);//向消息队列里加入消息
}
}
开启线程的方法
MyThread myThread = new MyThread();//new一个线程对象
myThread.start();//使用start()方法启动线程
注意:不一定run()方法里的message都是用上面的方法创建,看情况而定
方式二:实现Runnable接口
直接上程序
public MyRunnable implements Runnable{
public void run(){
//消息执行体,创建消息并发送到消息队列就在这里发送,如:
Message message =new Message();//得到一个消息对象
message.what=1;//给消息做标记,当handler获取消息时就知道是那个
message.obj=msg;//需要发送的数据
mHandler.sendMessage(message);//向消息队列里加入消息
}
}
注意:有时根据需要可以通过写构造函数传入参数
启动线程方法
MyRunnable myRunable = new MyRunnable();//得到一个Runnable对象
Thread thread = new Thread(myRunnable);//new一个thread并传入runnable对象
thread.start();//使用start()方法启动线程
有时候为了看起来紧凑可以这样写
new Thread(new Runnable(){
public void run(){
//消息执行体,创建消息并发送到消息队列就在这里发送,如:
Message message =new Message();//得到一个消息对象
message.what=1;//给消息做标记,当handler获取消息时就知道是那个
message.obj=msg;//需要发送的数据
mHandler.sendMessage(message);//向消息队列里加入消息
}
}).start();
Runnable 并不一定是新开一个线程,比如下面的调用方法就是运行在UI主线程中的:
Handler mHandler=new Handler();
mHandler.post(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
}
});
Runnable是一个接口,不是一个线程,一般线程会实现Runnable。 所以如果我们使用匿名内部类是运行在UI主线程的,如果我们使用实现这个Runnable接口的线程类,则是运行在对应线程的。
这种情况下,由于不是在新的线程中使用,所以千万别做复杂的计算逻辑。
下面给出简单例子(经典的在UI中实现计时操作)
XML布局
<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" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<LinearLayout
android:id="@+id/my_lay"
android:layout_below="@id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView1"
android:layout_centerHorizontal="true"
android:layout_marginTop="116dp"
android:text="button" />
</LinearLayout>
</RelativeLayout>
主程序
先做个简单的描述:
在这个例子里使用了上面的两种方式来创建线程,一个线程实现计时,一线程往TextView写入信息,Button按键按下计时停止
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
private final int MESSAGE_WHAT_1 = 1;//消息标记
private final int MESSAGE_WHAT_2 = 2;
private final int MESSAGE_WHAT_3 = 3;
public Button btn1 = null;
private TextView tv = null;
private TextView tv1 = null;
private boolean isRunning = true;//计时
private int timer = 0;
public Handler mHandler = null;
private Thread mThread = null;
private Thread mThread1 = null;
private MyRunnable mRunnable = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv=(TextView)findViewById(R.id.textView1);
tv1=(TextView)findViewById(R.id.textView2);
btn1=(Button)findViewById(R.id.button1);
btn1.setOnClickListener(new bt1Listener());
mHandler = new MyHandler();
//线程1
mRunnable = new MyRunnable();
mThread = new Thread(mRunnable);
mThread.start();
//线程2
mThread1 = new MyThread();
mThread1.start();
}
public class MyHandler extends Handler{
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_WHAT_2:
//通过继承Thread类实现的线程更新UI
String str1=msg.getData().getString("text1");
String str2=msg.getData().getString("text2");
tv.setText(str1 + " " + str2);
case MESSAGE_WHAT_1:
//通过实现Runnable来更新UI
tv1.setText("逝去了:" + msg.obj);//经典的更新UI例子。在UI中计时
break;
default: break;
}
}
}
//方法一:继承Thread类
public class MyThread extends Thread{
//private String data = "";
public MyThread(){//通过构造函数来传入数据
super();
}
public void run(){
Message message=new Message();//new一个Message对象
message.what = MESSAGE_WHAT_2;//给消息做标记
Bundle bundle = new Bundle();
bundle.putString("text1","这个继承Thread类"); //往Bundle中存放数据
bundle.putString("text2","来更新UI"); //往Bundle中put数据
message.setData(bundle);//mes利用Bundle传递数据
mHandler.sendMessage(message);//Handler将消息放入消息队列
}
}
//方法二:实现implements接口
public class MyRunnable implements Runnable{
@SuppressWarnings("static-access")
public void run(){
try {
while(isRunning){
Thread.currentThread().sleep(1000);
timer++;//加1计时
Message message = new Message();//new一个message对象
message.obj = timer;//将timer封装到消息里
message.what = MESSAGE_WHAT_1;//做标记
mHandler.sendMessage(message);//加入消息队列
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
class bt1Listener implements OnClickListener{
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
isRunning = false;
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
效果图:
点击Button
其实android实现多线程的方法可采用runOnUiThread,post,handle,AsyncTask技术实现。
这里讲解的是使用handler,其他的由大家来。