您的位置:首页 > 移动开发 > Android开发

android中Handler的初步认识(三)

2014-03-31 19:57 519 查看
        在上一个例子中,最终我们发现,其实用到的线程只有一个,那就是程序的主线程(UI线程)。那么怎么把那个例子改成用新建的线程来实现呢,今天我尝试了一下,写了下面这个小程序。

        当然,首先要声明一下,今天的这个例子并不是推荐的写法,而是我为了学习多线程而写的例子(貌似更常用的是AsyncTask,而不是Thread和Handler去更新UI)。

        在今天的这个例子中,我用到了Looper,先说说Looper是什么

在API中是这么解释Lopper的:Class used to run a message loop for a thread。我的理解是Looper是用来控制message queue的类

Looper常用的几个用法有:

Looper.prepare()                安卓的主线程中会默认调用这个方法来创建消息队列。但是,如果我们自己新建的线程,如果需要消息队列,则需要手动调用这个方法。

Looper.loop()                     这个方法用在prepare()方法之后,调用该方法之后,进入消息循环。

Looper.getMainLooper()  我在代码中用到了这个方法,这个方法的作用是获得主线程的Looper实例

Looper.myLooper()            这个方法用到获取当前线程的Looper实例

今天这个例子和第二篇中实现的功能一下,我只不过改了一个写法而已,下面是代码:

package com.example.handler2;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;

public class MainActivity extends Activity {

Button startButton = null;
Button stopButton = null;
ProgressBar progressbar = null;
Thread counter = null;

//获取主线程的looper
Looper looper = Looper.getMainLooper();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

startButton = (Button) findViewById(R.id.startButton);
stopButton = (Button) findViewById(R.id.stopButton);
progressbar = (ProgressBar) findViewById(R.id.progressBar);

//为button绑定onclicklistener
startButton.setOnClickListener(new ButtonOnclickListener());
stopButton.setOnClickListener(new stopOnclickListener());
}

class ButtonOnclickListener implements OnClickListener{
public void onClick(View v) {
progressbar.setVisibility(View.VISIBLE);
counter = new Thread(){
int i = 1;
@Override
public void run() {
// TODO Auto-generated method stub
i += 10;
Message msg = handler.obtainMessage();
msg.arg1 = i;

//让线程延迟一秒
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
Log.i("run", "run "+i+"%");
Log.i("run", Thread.currentThread().getName());
msg.sendToTarget();

}
};
counter.start();
}
}

class stopOnclickListener implements OnClickListener{
public void onClick(View v) {
//从message queue 中去掉run
handler.removeCallbacks(counter);
//让progressbar置成隐藏
progressbar.setVisibility(View.GONE);
}
}

//将handler与主线程关联
Handler handler = new Handler(looper){
public void handleMessage(android.os.Message msg) {

int i =msg.arg1;
//根据message中传来的参数控制进度条
progressbar.setProgress(i);

Log.i("run", Thread.currentThread().getName());

if(i<100){
handler.post(counter);
}else{
handler.removeCallbacks(counter);
progressbar.setVisibility(View.GONE);
}
};
};
}

       

         这段代码,和第二篇中最大的差别就是,当我点击启动按钮后,调用的不是主线程的run,而是我新建的线程。
        但是因为安卓不允许我们在主线程之外的线程中对UI进行修改,所以我在新建的线程中只是进行计数,然后将计数的结果通过message传递到主线程中,在主线程中更新进度条。

         

遗留问题:

         本来这个例子到这里就结束了,但是,我为了深入了解一下就在我新建的线程的run中和主线程Handler的handlerMessage方法中打印了当前线程的名称:

结果如下:


        

        按照我最初的理解,在日志中应该是主线程和我的线程交替写入日志,但是实际的情况是在第一次是counter线程,后面打印的都是主线程

        请问各位,有谁知道这是为什么吗?

        我看到在API中Handler的post方法是这么说明的:Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached.

         难道是,我使用了post方法,就相当于把counter线程的run中的代码拷贝中主线程中去执行了吗?如果有谁知道麻烦为我解答一下,不甚感激!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息