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的理解,由于个人的技术水平有限,某些观点可能有些不当,还希望各位路过的大牛能够批评指正!!!
更多相关文章
- 一句话锁定MySQL数据占用元凶
- [置顶] Android之路——第一个上线 APP项目总结
- Python+PyQT5的子线程更新UI界面
- 微信授权APP第三方登陆(Android)
- android 数据库处理及操作
- Android高性能编码 - 第二篇 数据库操作
- 一切为了更贴近系统―Android中的线程模型
- Android(安卓)程序应该考虑的问题
- Android与PHP交互,Android传递JSON数据,PHP接受并保存数据