关闭

Handelr的异步回掉机制

205人阅读 评论(0) 收藏 举报
分类:

1.通过Handelr实现UI线程与子线程的异步加载,首先要在AndroidMainfest.xml中声明访问权限

 <uses-permission android:name="android.permission.INTERNET"/>

2.回掉方法,我们通过创建接口来实现:

public interface MyImageCallback {
    void onSuccess(Bitmap bitmap);//访问成功,并从网络上获取一张图片
    void onFail(Exception e,String msg);//访问失败,抛出异常以及消息
    void onProgress(Float percent);//进度条
}
3.由于访问网络是耗时操作,所以我们要开辟子线程来执行耗时操作:

public class ImageRunnable implements Runnable, Handler.Callback {
    private String url;
    private MyImageCallback callback;
    /*
    *  Message 产品
    *  MessageQueue 仓库(正常编程的话永远用不到)
    *  Looper 循环
    *  Handler 物流
    *  Handler.Callback  回调接口
    * 任何与网络连接都不能在主线程中运行
    *
    * */
    private Handler handler;
    public ImageRunnable(String url, MyImageCallback callback) {
        this.url = url;
        this.callback = callback;
        /*查找到的资料:
         *Handler一定要在主线程实例化吗?
         * new Handler()和new Handler(Looper.getMainLooper())的区别
         * 如果你不带参数的实例化:Handler handler = new Handler();
         * 那么这个会默认用当前线程的looper
         * 一般而言,如果你的Handler是要来刷新操作UI的,
         * 那么就需要在主线程下跑。
         *情况:
         *1.要刷新UI,handler要用到主线程的looper。
         * 那么在主线程 Handler handler = new Handler();
         * 如果在其他线程,也要满足这个功能的话,
         * 要Handler handler = new Handler(Looper.getMainLooper());
         *
         *2.不用刷新ui,只是处理消息。
         * 当前线程如果是主线程的话,Handler handler = new Handler();
         * 不是主线程的话,Looper.prepare();
         * Handler handler = new Handler();Looper.loop();
         * 或者Handler handler = new Handler(Looper.getMainLooper());
         *若是实例化的时候用Looper.getMainLooper()就表示放到主UI线程去处理。
         * 如果不是的话,因为只有UI线程默认Loop.prepare();Loop.loop();过,
         * 其他线程需要手动调用这两个,否则会报错。
         *
         *
         * */
        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 contentLength = connection.getContentLength();
                int length;
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                byte[] buffer = new byte[102400];
                while ((length = is.read(buffer)) != -1){
                    bos.write(buffer,0,length);

                    handler.obtainMessage(2, bos.size(), contentLength).sendToTarget();
                }
                byte[] bytes = bos.toByteArray();
                Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                /*handler数据传递的三种方式
                * 方式一:
                * Message message = new Message();message创建方式(不推荐)
                * Message message = Message.obtain(handler,0,String.valueOf(i + 1));//推荐使用
                * message.sendToTarget();
                * handler.sendMessage(message);
                * 方式二:
                *  Message message = Message.obtain();
                *  message.obj = String.valueOf(i + i);
                *  message.what = 0;
                *  handler.sendMessage(message);
                * 方式三:
                *handler.obtainMessage(0,String.valueOf(1 + i)).sendToTarget()
                *
                * */
                handler.obtainMessage(0,bitmap).sendToTarget();
            }else{
                RuntimeException exception = new RuntimeException("response" + code);
                String string = "服务器异常";
                Bundle bundle = new Bundle();
                bundle.putString("str",string);
                bundle.putSerializable("exception",exception);
                Message message = handler.obtainMessage(1);
                message.setData(bundle);
                handler.sendMessage(message);
            }
        } catch (IOException e) {
            String str = "网络异常";
            /*
            * 当要传递多条数据时,
            * 采用bundle打包数据(bundle使用方法类似于map集合),
            * 毕竟message.obj只能赋值一种类型的数据,
            * 如果是同一个进程,最好用setData,
            *message.obj一般是Messenger类来用来跨进程传递可序列化的对象的,
            * 这个比setData,更消耗性能一些。
            * */
            Bundle bundle = new Bundle();
            bundle.putString("str",str);
            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:
                callback.onSuccess((Bitmap) msg.obj);
                break;
            case 1:
                Bundle data = msg.getData();
                String string = data.getString("str");
                Exception exception = (Exception) data.getSerializable("exception");
                callback.onFail(exception,string);
                break;
            case 2:
                int size = msg.arg1;
                int length = msg.arg2;
                float percent = size * 100.0f / length;
                callback.onProgress(percent);
                break;
        }

        return true;//返回值true代表message数据已经传输完成
    }
}

3.在UI线程中通过回调接口来获取子线程中存储的数据:

public class MainActivity extends AppCompatActivity implements MyImageCallback{

    private ImageView imageView;
    private TextView text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView) findViewById(R.id.main_image);
        text = (TextView) findViewById(R.id.main_tv);
        ImageRunnable runnable = new ImageRunnable("http://p4.so.qhmsg.com/t018349127914f495ce.jpg", this);
        new Thread(runnable).start();
    }

    @Override
    public void onSuccess(Bitmap bitmap) {
        imageView.setImageBitmap(bitmap);
    }

    @Override
    public void onFail(Exception e, String msg) {
        e.printStackTrace();
        Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onProgress(Float precent) {
        text.setText(String.format(Locale.CHINA,"%.2f%%",precent));//显示加载文本图片的百分比
    }
}





0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

异步事件回调机制原理探索

自定义的异步事件回调机制: 可以在自己的应用程序中,先注册事件和事件对应的回调函数(回调函数可以是函数指针法,虚函数方法的方式);自己程序中每帧检测事件是否发生或者条件是否满足,满足的时候就进入回调函...
  • Blues1021
  • Blues1021
  • 2015-03-15 12:58
  • 5249

函数回调机制、异步函数回调机制图例详解

无论是JS的函数回调还是Java回调机制,它们思想都是类似的,简单来说就是,如下图所示:                             &#...
  • zhangliangzi
  • zhangliangzi
  • 2016-07-29 20:10
  • 6250

一个经典例子让你彻彻底底理解java回调机制

以前不理解什么叫回调,天天听人家说加一个回调方法啥的,心里想我草,什么叫回调方法啊?然后自己就在网上找啊找啊找,找了很多也不是很明白,现在知道了,所谓回调:就是A类中调用B类中的某个方法C,然后B类中...
  • xiaanming
  • xiaanming
  • 2013-03-21 23:43
  • 260432

深入浅出Java回调机制 / 回掉函数 / 深入浅出理解 Java回调机制(异步) GOOD

http://hellosure.iteye.com/blog/1130176 Java回调异步调用  前几天看了一下Spring的部分源码,发现回调机制被大量使用,觉得有必要把Java...
  • liangxw1
  • liangxw1
  • 2016-02-20 01:10
  • 1042

java接口回掉—异步处理耗时操作

在Java程序或者是Android程序中,如果需要更新UI必须在主线程中进行,比如你要在网络中获取一个值,然后更新UI。网络获取值属于耗时操作,在主线程中操作的话,会导致线程阻塞,进而导致程序奔溃,所...
  • qq_36102598
  • qq_36102598
  • 2017-05-24 19:27
  • 351

线程池异步回掉的简单例子

本文是一个基于android activity请求网络数据情景,做的一个java的模拟网络异步请求的简单例子,包括了线程池和软引用的简单应用,如果有不对的地方,希望大家可以指正。 1.异步请求是为了...
  • u013488064
  • u013488064
  • 2017-11-16 22:08
  • 107

MFCDLL回掉函数小例子

  • 2015-08-27 15:29
  • 144KB
  • 下载

ListView回掉

  • 2016-01-11 02:35
  • 2.89MB
  • 下载

simple_udp_register中回掉函数解析

contiki系统中关于simple_udp_register中回掉函数解析 simple-udp.c中的simple_udp_register()函数的解析,重点为回掉函数,结合broadcast-...
  • frank_jb
  • frank_jb
  • 2015-06-09 09:54
  • 907

通过js看类似C#中的回掉

我认为并行有两种形式,第一种是异步,第二种是多线程,目的都是为了实现并行,只不过异步和多线程都是手段而已 - 第一种异步 异步,执行完函数或方法后,不必阻塞性地等待返回值或消息,只需要向系统委托...
  • menglin2010
  • menglin2010
  • 2016-04-27 22:50
  • 236
    个人资料
    • 访问:33117次
    • 积分:947
    • 等级:
    • 排名:千里之外
    • 原创:44篇
    • 转载:8篇
    • 译文:18篇
    • 评论:2条
    文章分类
    最新评论