当逐渐深入学习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的理解,由于个人的技术水平有限,某些观点可能有些不当,还希望各位路过的大牛能够批评指正!!!