Handelr的异步回掉机制

来源:互联网 发布:淘宝人肉一个人多钱 编辑:程序博客网 时间:2024/06/08 04:25

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
原创粉丝点击