android线程之多线程

本文详细介绍了Android中线程的实现方式,包括继承Thread类和实现Runnable接口两种方法,并结合Handler机制进行UI更新,避免阻塞主线程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相信大家对于什么是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
                    breakcase   2//处理消息
                    breakdefaultbreak;
                }
        }
}

或者可以这样写

Handler mHandler = new Handler(){
        public void handleMessage(Message msg){
                switch(msg.what){
                case   1  :   
                            //处理消息,例如更新UI
                    breakcase   2//处理消息
                    breakdefaultbreak;
                }
        }
}

然后 通过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,其他的由大家来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值