android多线程

线程的基本用法:

android多线程编程其实并不比java多线程特殊,基本都是使用相同的语法,比如说,定义一个线程只需要新建一个类继承自Thread,然后重写父类的run()方法,并在里面编写耗时的逻辑即可,

public class MyThread extends Thread {
    @Override
    public void run() {
        //处理具体的逻辑
        super.run();
    }
}

如何启动这个线程,其实也很简单,只需要new出MyThread的实例,然后调用它的start()方法,这样run()方法中的代码就会在子线程当中运行了。

new MyThread().start();

使用继承的方式耦合性有点高,更多的时候我们都会选择使用Runnable接口的方式定义一个线程

public class MyThread implements Runnable{
    @Override
    public void run() {
        //处理具体的逻辑
    }
}

如果使用了这种写法,启动线程的方法也需要进行相应的改变,

MyThread mythread=new MyThread();
new Thread(mythread).start();

当然如果不想专门再定义一个类去实现runnable接口,也可以使用匿名累的方式,如下所示:

Thread thread= new Thread(new Runnable() {
       @Override
       public void run() {
           //具体处理逻辑
       }
   }).start();

再子线程中更新UI

和许多其他GUI库一样,安卓的UI也是线程不安全的,也就是说,如果想要更新应用程序里的UI元素,则必须在主线程中进行,否则就会出现异常。

下面我们来看一个例子:

  <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/change_text"
        android:text="send request"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/text1"
        android:text="hello world"
        android:textSize="20sp"
            />
public class MainActivity extends Activity  implements View.OnClickListener {
   private  TextView textView;
    private Button changeText;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView=(TextView)findViewById(R.id.text1);
        changeText=(Button)findViewById(R.id.change_text);
        changeText.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.change_text:
            new Thread(new Runnable() {
                @Override
                public void run() {
                    textView.setText("Nice to neet you");
                }
            }).start();
                break;
            default:
                break;


        }

    }

运行的时候会出现如下图所示的情况:

由此正式了安卓确实是不允许自线程中运行UI操作,但是有时候我们必须在子线程里面去执行一些耗时任务,然后根据任务的执行结果来更新相应的UI控件,

安卓提供了一套异步消息处理机制完美的解决了在子线程中运行UI操作。

首先我们先来看一下这个解决的代码

public class MainActivity extends Activity  implements View.OnClickListener {
   private  TextView textView;
    private Button changeText;
    public  static  final  int UPDATE_TEXT=1;
    private  Handler handler=new Handler() {
        @Override
        public void close() {
            
        }

        @Override
        public void flush() {

        }

        @Override
        public void publish(LogRecord record) {

        }
        public  void  handleMessage(Message msg){
            switch (msg.what){
                case  UPDATE_TEXT:
                    textView.setText("Nice to meet you");
                    break;
                default:
                    break;
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView=(TextView)findViewById(R.id.text1);
        changeText=(Button)findViewById(R.id.change_text);
        changeText.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.change_text:
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Message message=new Message();
                    message.what=UPDATE_TEXT;
                    handler.sendMessage(message);
                    
                }
            }).start();
                break;
            default:
                break;


        }

    }

我们来解析异步消息处理机制:

安卓中的异步消息处理主要由四部分组成,Message,Handler,MessageQueue和Looper。

1 Message

Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。

2 Handler

Handler故名思义也就是处理者的意思,它主要是用于发送和处理消息的,发送消息一般是使用Handler的sendmessage()方法,而发出的消息经过一系列地辗转处理后,最终会传递到Handler地handleMessage()方法中,

3MessageQueue

MessageQueue 是消息队列的意思,它主要用于存放所有通过Handler发送的消息,这部分消息会一直存在于消息队列中,等待被处理,每个线程中只会有一个MessageQueue对象。

4 Looper

Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法中,每个线程中也只会只有一个Looper对象。

首先需要在主线成中创建一个Handler对象,并重写handleMessage()方法,然后子线程中需要进行UI操作时,就创建一个Message对象,并通过Handler将这条消息发送出去,之后这条消息会被添加到MessageQueue的队列中等待被处理,而Looper则会一直尝试从MessageQueue中取出待处理消息,最后奋发回Handler的handleMessage()方法中,由于Handle是在主线程中创建的,所以此时handleMessage()方法中的代码也会在主线成中运行,于是我们在这里就可以安心的运行UI操作,整个异步消息处理的核心思想就是这样。

为了更加方便我们在自线程中对UI进行操作,android还提供了另外的一些好用的工具,AsyncTask就是其中之一,借助AsyncTask,即使你对异步消息处理机制完全不了解,也可以十分简单的从子线程切换的主线程,AsyncTask背后的实现原理也是基于异步消息处理机制的。

由于AsyncTask是一个抽象类,所以如果我们想要使用它,就必须创建一个子类去继承它,在继承AsyncTask类指定三个范性参数,这三个参数的用途如下:

1 params

在执行AsyncTask时需要传入参数,用于在后台任务中使用。

2progress

后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的范性作为进度单位。

3 result

当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回类型。

我们还需要自定义一些方法才能完成对任务的定制。

1 onPreExecute()

这个方法会在后台任务开始执行之前调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框

2 doInBackground(Params...)

这个方法中所有代码都会在自线程中运行,我们应该在这里去处理所有的耗时任务,任务一旦完成就可以通过return语句来将任务的执行结果返回,如果AsyncTask的读三个泛型参数指定的是void,就可以不返回任务执行结果,注意,在这个方法中是不可以进行ui操作的,如果要更新UI元素,比如说反馈当前任务的执行进度,可以调用publishProgress(Progress...)方法来完成。

3 onProgressUpdate(Progress...)

  当在后台任务中调用了publishprogress(progress...)方法后,这个方法就会很快被调用,方法中携带的参数就是在后台任务传递过来的,在这个方法中可以对UI进行操作。利用参数中的数值就可以对界面元素进行相应的更新。

4 onPostExecute(Result)

当后台任务执行完毕并通过return语句进行返回时,这个方法就很快会被调用,返回的数据会作为位参数传递到此方法中,可以利用返回的数据来进行一些UI操作,比如说提醒任务执行的结果以及关闭掉进度条对话框。

如果要启动的话只需要调用其execute()方法。

 

posted @ 2016-03-26 03:37  故园的梨花  阅读(224)  评论(0)    收藏  举报