Android程序开发之异步加载机制 之 Handler 笔记
来源:互联网 发布:北京日报新闻网络热线 编辑:程序博客网 时间:2024/06/07 13:15
1.Handler是Android中引入的一种让开发者参与处理线程中消息循环的机制。Handler的内部实现主要涉及到如下几个类: Thread、MessageQueue和Looper。
Thread是最基础的,Looper和MessageQueue都构建在Thread之上,Handler又构建在Looper和MessageQueue之上,我们通过Handler间接地与下面这几个相对底层一点的类打交道。
2.
MessageQueue
Looper
消息队列MessageQueue只是存储Message的地方,真正让消息队列循环起来的是Looper,这就好比消息队列MessageQueue是个水车,那么Looper就是让水车转动起来的河水,如果没有河水,那么水车就是个静止的摆设,没有任何用处,Looper让MessageQueue动了起来,有了活力。
Looper是用来使线程中的消息循环起来的。默认情况下当我们创建一个新的线程的时候,这个线程里面是没有消息队列MessageQueue的。为了能够让线程能够绑定一个消息队列,我们需要借助于Looper:首先我们要调用Looper的prepare方法,然后调用Looper的Loop方法。
需要注意的是Looper.prepare()和Looper.loop()都是在新线程的run方法内调用的,这两个方法都是静态方法。我们知道线程Thread和Looper是一对一绑定的,也就是一个线程中最多只有一个Looper对象
4.
Handler
Handler是暴露给开发者最顶层的一个类,其构建在Thread、Looper与MessageQueue之上。Handler具有多个构造函数,签名分别如下所示:
1. publicHandler()
2. publicHandler(Callbackcallback)
3. publicHandler(Looperlooper)
4. publicHandler(Looperlooper, Callbackcallback)
第1个和第2个构造函数都没有传递Looper,这两个构造函数都将通过调用Looper.myLooper()获取当前线程绑定的Looper对象,然后将该Looper对象保存到名为mLooper的成员字段中。
第3个和第4个构造函数传递了Looper对象,这两个构造函数会将该Looper保存到名为mLooper的成员字段中。
第2个和第4个构造函数还传递了Callback对象,Callback是Handler中的内部接口,需要实现其内部的handleMessage方法,
Handler.Callback是用来处理Message的一种手段,如果没有传递该参数,那么就应该重写Handler的handleMessage方法,也就是说为了使得Handler能够处理Message,我们有两种办法:
1. 向Hanlder的构造函数传入一个Handler.Callback对象,并实现Handler.Callback的handleMessage方法
2. 无需向Hanlder的构造函数传入Handler.Callback对象,但是需要重写Handler本身的handleMessage方法
也就是说无论哪种方式,我们都得通过某种方式实现handleMessage方法,这点与Java中对Thread的设计有异曲同工之处
形象图:【】
代码实现:
1.
package com.treasure_ct.study_demo.asyncloading;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.widget.TextView;import com.treasure_ct.study_demo.R;/** * Created by treasure on 2016.09.01. */public class CeshiHander extends Activity{ private TextView textView; private Handler handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { switch (msg.what) { case 0: textView.setText(((String) msg.obj)); } return false; } }); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler_loopnum); textView = (TextView) findViewById(R.id.text_handler); textView.setText("0"); new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 20; i++) { Message.obtain(handler,0,String.valueOf(i + 1)).sendToTarget(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); }}
2.主要思路:
1)子线程实现定义一个接口,实现success和fail的方法,传递给主类,实现
callBack接口,写handleMessage方法,把传递的Message只进行判断。
2)主类实现MyCall接口获得success和fail方法,调用runnable子线程,具体代码
子线程
package com.treasure_ct.study_demo.asyncloading;import android.os.Bundle;import android.os.Handler;import android.os.Looper;import android.os.Message;import android.util.Log;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.URL;/** * Created by treasure on 2016.09.01. */public class Ceshi_Runable implements Runnable,Handler.Callback { private String url; private MyCall myCall; private Handler handler; public Ceshi_Runable(String url, MyCall myCall) { this.url = url; this.myCall = myCall; handler = new Handler(Looper.getMainLooper(),this); } @Override public void run() { try { HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); connection.setRequestMethod("GET"); connection.setDoInput(true); int code = connection.getResponseCode(); if (code == 200) { InputStream is = connection.getInputStream(); int length; byte[] bytes = new byte[102400]; ByteArrayOutputStream bos = new ByteArrayOutputStream(); while ((length = is.read(bytes))!=-1){ bos.write(bytes,0,length); } String s = bos.toString("UTF-8"); handler.obtainMessage(0,s).sendToTarget(); }else { RuntimeException exception = new RuntimeException("Code:" + code); String s = "服务器错误"; Bundle bundle = new Bundle(); bundle.putString("msg",s); bundle.putSerializable("exception",exception); Message message = handler.obtainMessage(1); message.setData(bundle); handler.sendMessage(message); } } catch (IOException e) { String s = "网络错误"; Bundle bundle = new Bundle(); bundle.putString("msg",s); bundle.putSerializable("exception",e); Message message = handler.obtainMessage(1); message.setData(bundle); handler.sendMessage(message); } } @Override public boolean handleMessage(Message msg) { switch (msg.what) { case 0: myCall.onSuccess((String) msg.obj); break; case 1: Bundle bundle = msg.getData(); Exception exception = (Exception) bundle.getSerializable("exception"); String msg1 = bundle.getString("msg"); myCall.onFail(exception,msg1); break; } return false; } public interface MyCall{ void onSuccess(String s); void onFail(Exception e,String s); }}
主类
package com.treasure_ct.study_demo.asyncloading;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.widget.TextView;import android.widget.Toast;import com.treasure_ct.study_demo.R;/** * Created by treasure on 2016.09.01. */public class CeshiHander extends Activity implements Ceshi_Runable.MyCall{ private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler_loopnum); textView = (TextView) findViewById(R.id.text_handler); Ceshi_Runable runable = new Ceshi_Runable("http://www.baidu.com", this); new Thread(runable).start(); } @Override public void onSuccess(String s) { textView.setText(s); } @Override public void onFail(Exception e, String s) { e.printStackTrace(); Toast.makeText(CeshiHander.this, s, Toast.LENGTH_SHORT).show(); }}
3)图片下载带下载进度
package com.treasure_ct.study_demo.asyncloading;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Bundle;import android.os.Handler;import android.os.Looper;import android.os.Message;import android.util.Log;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.URL;/** * Created by treasure on 2016.09.01. */public class Ceshi_Runable implements Runnable,Handler.Callback { private String url; private MyCall myCall; private Handler handler; public Ceshi_Runable(String url, MyCall myCall) { this.url = url; this.myCall = myCall; handler = new Handler(Looper.getMainLooper(),this); } @Override public void run() { try { HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); connection.setRequestMethod("GET"); connection.setDoInput(true); int code = connection.getResponseCode(); int contentLength = connection.getContentLength(); if (code == 200) { InputStream is = connection.getInputStream(); int length; byte[] bytes = new byte[102400]; ByteArrayOutputStream bos = new ByteArrayOutputStream(); while ((length = is.read(bytes))!=-1){ bos.write(bytes,0,length); handler.obtainMessage(2,bos.size(),contentLength).sendToTarget(); } byte[] bytes1 = bos.toByteArray(); Bitmap bitmap = BitmapFactory.decodeByteArray(bytes1, 0, bytes1.length); handler.obtainMessage(0,bitmap).sendToTarget(); }else { RuntimeException exception = new RuntimeException("Code:" + code); String s = "服务器错误"; Bundle bundle = new Bundle(); bundle.putString("msg",s); bundle.putSerializable("exception",exception); Message message = handler.obtainMessage(1); message.setData(bundle); handler.sendMessage(message); } } catch (IOException e) { String s = "网络错误"; Bundle bundle = new Bundle(); bundle.putString("msg",s); bundle.putSerializable("exception",e); Message message = handler.obtainMessage(1); message.setData(bundle); handler.sendMessage(message); } } @Override public boolean handleMessage(Message msg) { switch (msg.what) { case 0: myCall.onSuccess((Bitmap) msg.obj); break; case 1: Bundle bundle = msg.getData(); Exception exception = (Exception) bundle.getSerializable("exception"); String msg1 = bundle.getString("msg"); myCall.onFail(exception,msg1); break; case 2: float percent = msg.arg1 * 100.0f / msg.arg2; myCall.onPercent(percent); break; } return false; } public interface MyCall{ void onSuccess(Bitmap s); void onFail(Exception e,String s); void onPercent(float percent); }}
package com.treasure_ct.study_demo.asyncloading;import android.app.Activity;import android.graphics.Bitmap;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.widget.ImageView;import android.widget.TextView;import android.widget.Toast;import com.treasure_ct.study_demo.R;import java.util.Locale;/** * Created by treasure on 2016.09.01. */public class CeshiHander extends Activity implements Ceshi_Runable.MyCall{ private ImageView textView; private TextView text1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler_loopnum); textView = (ImageView) findViewById(R.id.text_handler); text1 = (TextView) findViewById(R.id.text_percent); Ceshi_Runable runable = new Ceshi_Runable("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1472712632&di=cb63eb9b4ffd5fe38804e1dd8d9df2ba&src=http://img3.duitang.com/uploads/item/201608/02/20160802212751_CLtXz.thumb.700_0.jpeg", this); new Thread(runable).start(); } @Override public void onSuccess(Bitmap s) { textView.setImageBitmap(s); } @Override public void onFail(Exception e, String s) { e.printStackTrace(); Toast.makeText(CeshiHander.this, s, Toast.LENGTH_SHORT).show(); } @Override public void onPercent(float percent) { text1.setText(String.format(Locale.CHINA,"%.2f%%",percent)); }}
图灵机器人 小样
Model
package com.treasure_ct.chatboy_xt;/** * Created by treasure on 2016.09.18. */public class Entry { private String icon; private String userName; private String text; private long time; private boolean received; public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getText() { return text; } public void setText(String text) { this.text = text; } public long getTime() { return time; } public void setTime(long time) { this.time = time; } public boolean isReceived() { return received; } public void setReceived(boolean received) { this.received = received; }}
自定义多布局 baseAdapter
package com.treasure_ct.chatboy_xt;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;import java.util.List;/** * Created by treasure on 2016.09.18. */public class MyBaseAdapter extends BaseAdapter{ private Context context; private List<Entry> list; public MyBaseAdapter(Context context, List<Entry> list) { this.context = context; this.list = list; } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public int getViewTypeCount() { return 2; } @Override public int getItemViewType(int position) { int ret = 0; Entry entry = list.get(position); if (entry.isReceived()) { ret = 0; }else { ret = 1; } return ret; } @Override public View getView(int position, View convertView, ViewGroup parent) { View ret = null; int type = getItemViewType(position); switch (type) { case 0: ret = getLeftView(position,convertView,parent); break; case 1: ret = getRightView(position,convertView,parent); break; } return ret; } private View getLeftView(int position, View convertView, ViewGroup parent){ View ret = null; if (convertView != null){ ret = convertView; }else { ret = LayoutInflater.from(context).inflate(R.layout.chat_user_left_item,parent,false); } ViewHolder holder = (ViewHolder) ret.getTag(); if (holder == null){ holder = new ViewHolder(ret); ret.setTag(holder); } holder.bindView(position,list.get(position)); return ret; } private View getRightView(int position, View convertView, ViewGroup parent){ View ret = null; if (convertView != null){ ret = convertView; }else { ret = LayoutInflater.from(context).inflate(R.layout.chat_user_right_item,parent,false); } ViewHolder holder = (ViewHolder) ret.getTag(); if (holder == null){ holder = new ViewHolder(ret); ret.setTag(holder); } holder.bindView(position,list.get(position)); return ret; } private static class ViewHolder{ private TextView name,text; private ImageView icon; public ViewHolder(View view) { name = (TextView) view.findViewById(R.id.userName); text = (TextView) view.findViewById(R.id.userText); icon = (ImageView) view.findViewById(R.id.userIcon); } public void bindView(int position,Entry entry){ name.setText(entry.getUserName()); text.setText(entry.getText()); } }}
实现方法 主类
package com.treasure_ct.chatboy_xt;import android.os.Build;import android.os.Handler;import android.os.Looper;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.EditText;import android.widget.ListView;import android.widget.Toast;import com.treasure_ct.post_network_xt.HttpUtil;import org.json.JSONException;import org.json.JSONObject;import java.io.UnsupportedEncodingException;import java.util.ArrayList;import java.util.List;/** * 题型:图灵机器人 * 思路:首先使用子线程处理消息,根据点击事件发来的“发送信息”,网络申请加JSON解析,将信息传给接收消息的Handler,进行显示 * 用到两个Handler,第一个sonHandler 用来进行用户发送到子线程的任务,第二个mainHandler用来子线程处理好信息, * 接受网络信息,然后发回主线程,进行显示 */public class MainActivity extends AppCompatActivity implements View.OnClickListener,Runnable { private List<Entry> list; private MyBaseAdapter adapter; private EditText input; private ListView listView; private Handler sonHandler; private Handler mainHandler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case 888: int type = msg.arg1; if (type == 100000) { String text = (String) msg.obj; Entry entry = new Entry(); entry.setText(text); entry.setUserName("小T"); entry.setReceived(true); entry.setTime(System.currentTimeMillis()); list.add(entry); adapter.notifyDataSetChanged(); int count = adapter.getCount(); listView.setSelection(count - 1); } break; } } }; @Override protected void onCreate( Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button send = (Button) findViewById(R.id.btn_send); input = (EditText) findViewById(R.id.edit); listView = (ListView) findViewById(R.id.listview); list = new ArrayList<>(); adapter = new MyBaseAdapter(this,list); if (listView != null) { listView.setAdapter(adapter); } Thread thread = new Thread(this); thread.start(); send.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_send: if (sonHandler != null) { Message message = sonHandler.obtainMessage(666); String s = input.getText().toString(); if (s != null && !s.equals("")) { message.obj = s; sonHandler.sendMessage(message); Entry entry = new Entry(); entry.setReceived(false); entry.setText(s); entry.setTime(System.currentTimeMillis()); entry.setUserName("我"); list.add(entry); adapter.notifyDataSetChanged(); int count = adapter.getCount(); listView.setSelection(count - 1); input.setText(""); }else { Toast.makeText(MainActivity.this, "请输入信息", Toast.LENGTH_SHORT).show(); } } break; } } @Override public void run() { Looper.prepare(); Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case 666: JSONObject object = new JSONObject(); try { object.put("key","f88cd2cdc8ea4953b51154567ca356d7"); object.put("info",msg.obj.toString()); object.put("loc","北京市海淀区"); object.put("userid",Build.SERIAL); byte[] data = HttpUtil.doPostJson("http://www.tuling123.com/openapi/api", object.toString()); if (data != null) { String s = new String(data, "UTF-8"); Log.d("-------------------", "handleMessage: "+s); JSONObject jsonObject = new JSONObject(s); int code = jsonObject.getInt("code"); if (code == 100000) { String text = jsonObject.getString("text"); Message message = mainHandler.obtainMessage(888); message.obj = text; message.arg1= code; mainHandler.sendMessage(message); } } } catch (JSONException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } }; sonHandler = handler; Looper.loop(); }}
- Android程序开发之异步加载机制 之 Handler 笔记
- Android开发学习笔记十四 异步线程之Handler
- android异步加载之Handler、AsyncTask(一)
- Android异步任务机制之Handler
- Android异步消息处理机制之handler机制
- Android开发之Handler消息传递机制
- Android开发之Handler消息机制
- android异步加载之Handler、AsyncTask(二)
- 26、Android之Handler异步消息处理机制
- Android之异步处理Handler和消息机制处理
- Android理论梳理-No1异步处理之Handler相关机制
- Android之多线程----异步消息处理机制之Handler详解
- Android多线程----异步消息处理机制之Handler
- Android多线程----异步消息处理机制之Handler详解
- Android异步之Thread+Handler传递消息机制原理
- Android之handler异步消息处理机制原理
- Android多线程----异步消息处理机制之Handler详解
- Android异步消息处理机制之Handler、Looper、Message
- css3中的content字符编码
- Spring入门(一)
- adb shell top
- 【Android】AndroidStudio打包apk出现的一些问题 `Error:Execution failed for task ':app:lintVitalRelease'.
- 项目实战:引导动画-千变万化的ViewPager(文末小彩蛋)
- Android程序开发之异步加载机制 之 Handler 笔记
- 《编写可维护的JavaScript》读书笔记——3.语句和表达式
- leetcode:数学:spuer pow(372)
- You are using safe update mode and you tried to update a table without a WHERE that uses a KEY colum
- Centos javaMail 邮件无法发出
- 微信公众平台开发,微信JS-SDK对接invalid signature报错解决
- XMLParser 使用
- spring bean对象的声明周期
- 性能測試——并发用户数估算