android多线程详解之Handler

当逐渐深入学习android的时候,会不可避免接触到网络开发的.

有时我们需要从网络上获取大量数据时,获取完数据后,会及时进行主线程UI的更新,如果把这些耗时的操作放到主UI线程时,可能会造成主线程阻塞以致应用程序关闭,这时我们就需要把这些耗时的操作单独的放到另外的线程中,确保主线程能正常的运行.在android当中,一般能实现这些效果的有两种方法,一种是Handler,另外一种是AsyncTask.

今天我们就主要讲讲Handler的使用方法,就以从我们学校新闻网上获取新闻内容为例,为了方便大家能清晰快速的了解Handler,我就从网上获取少量的数据,闲话少说,我就先给大家看看代码与实现效果:

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
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 TextView data;
    private Button start;
    private Handler handler;
    private ProgressDialog progressDialog = null;

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

        data = (TextView) findViewById(R.id.data);
        start = (Button) findViewById(R.id.start);
        handler = new Handler() {
            public void handleMessage(Message msg) {
                // progressDialog.dismiss();
                Log.i("5", "第三个");
                String content = (String) msg.obj;
                data.setText(content);
                start.setText("结束");
            };

        };

        start.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                Log.i("1", "第一个");
                progressDialog = new ProgressDialog(getApplicationContext());
                progressDialog.setMessage("正在登录...");
                progressDialog.setCancelable(false);
                // progressDialog.show();
                login();

            }
        });

    }

    protected void login() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Log.i("2", "第二");
                    Document doc = Jsoup.connect(
                            "http://www.cnwust.com/index.html").get();
                    List<Map<String, String>> list = new ArrayList<Map<String, String>>();
                    Elements elements = doc.select("#inner_nav a");
                    Log.i("3", elements.toString());
                    for (int i = 1; i < elements.size(); i++) {
                        Map<String, String> map = new HashMap<String, String>();
                        map.put("title", elements.get(i).text());
                        map.put("link", elements.get(i).attr("abs:href"));
                        list.add(map);
                    }

                    Log.i("4", list.toString());
                    handler.obtainMessage(1, list.get(1).get("title"))
                            .sendToTarget();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }

        }).start();
    }

    @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;
    }

}

对应的布局文件代码:

<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" >

    <LinearLayout  android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" >

        <TextView  android:id="@+id/data" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="测试数据" android:textSize="15dp" />

        <Button  android:id="@+id/start" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="10dip" android:text="开始" />
    </LinearLayout>

</RelativeLayout>

实现的效果:

让我们来分析分析这段程序代码是怎么运行的,它首先是在主activity里面申明了一个Handler,然后在主进程创建之后进行实例化,并且在里面写了handlerMessage的方法,对接收到的Message进行处理,并实现对主UI线程的更新,注意在更新主界面UI的操作只能放到这个里面,其余地方可能系统会报错.
我们已经实现了对接受到了的Message的处理,接下来我们来看看我们应该在什么时候选择发送消息呢,由于消息里面一般都会包含我们从网络上获取到的数据,所以当我们新建一个新线程,在里面进行耗时操作完后,我们可以把我们得到的数据,装载到Message里面,并且发送到Handler里面,注意这里面的方法
handler.obtainMessage(1, list.get(1).get(“title”)).sendToTarget().
方法当从的第一个参数”1”,对应的是Message的What,实质就是个int型数据,它的使用,是为了方便我们对接收到的数据进行一个分析,如果我们从网络上获取数据时,我们可以用”0”来表示获取数据失败,用”1”来表示成功,我们再在handlerMessage方法里面写个switch语句处理就行了,由于笔者比较偷懒,就没有在这份代码中写了╯﹏╰,,,,, 而第二个参数list.get(1).get(“title”)它的值其实是个String类型的数据,它对应的是Message的Object,由于String是继承了的Object的,所以系统不会报错,对于这个object的类,我们一般在里面放置从网络获取得到的数据.准备好Message后,我们一定要注意在后面加上一个sendtoTarget()的方法,不然Handler不能得到消息,,,,,而这个Message也遵循一个队列的机制,先进先出,它是逐个逐个发送的,如果读者想要在这方面深究的话,可以了解了解下面这些博客

Android Handler机制

Android消息队列及线程机制详解

完成这些操作后,我们基本上算是对Handler有个大致的了解了,关于实现多线程更新UI的第二个方法,本人会在之后的博客里再给大家介绍.

以上是笔者在实践中对Handler的理解,由于个人的技术水平有限,某些观点可能有些不当,还希望各位路过的大牛能够批评指正!!!

你可能感兴趣的:(多线程,UI,android)