关闭

Handelr的异步回掉机制

172人阅读 评论(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网站的观点或立场
    个人资料
    • 访问:28349次
    • 积分:894
    • 等级:
    • 排名:千里之外
    • 原创:44篇
    • 转载:8篇
    • 译文:18篇
    • 评论:2条
    文章分类
    最新评论