zoukankan      html  css  js  c++  java
  • Android中的异步网络请求

        本篇文章我们来一起写一个最基本的Android异步网络请求框架,借此来了解下Android中网络请求的相关姿势。由于个人水平有限,文中难免存在疏忽和谬误,希望大家可以指出,谢谢大家:)

    1. 同步网络请求

        以HTTP的GET请求为例,我们来介绍一下Android中一个基本的同步请求框架的实现。直接贴代码:

    public class HttpUtils {
        public static byte[] get(String urlString) {
            HttpURLConnection urlConnection = null;
            try {
                URL url = new URL(urlString);
                urlConnection = (HttpURLConnection) url.openConnection();
                //设置请求方法
                urlConnection.setRequestMethod("GET");
                //设置超时时间
                urlConnection.setConnectTimeout(5000);
                urlConnection.setReadTimeout(3000);
    
                //获取响应的状态码
                int responseCode = urlConnection.getResponseCode();
                if (responseCode == 200) {
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    InputStream in = urlConnection.getInputStream();
                    byte[] buffer = new byte[4 * 1024];
                    int len = -1;
                    while((len = in.read(buffer)) != -1) {
                        bos.write(buffer, 0, len);
                    }
                    close(in);
                    byte[] result = bos.toByteArray();
                    close(bos);
                    return result;
                } else {
                    return null;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
            }
    
            return null;
        }
    
        private static void close(Closeable stream) {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
    }

        相信以上的代码我们大家都不陌生,以上代码就实现了基本的同步网络请求功能,get 方法会返回一个byte[]数组,后续我们可以根据返回的相应类型(文本或图片)对这个字节数组作进一步处理。

    2. 异步网络请求

        通常一个异步HTTP GET请求是这样的:发出get方法的调用后,相关任务会在后台线程中自动执行,而我们在主线程中继续处理其他工作,它成功获取GET请求的响应时,就会回调onSuccess方法。最直接的写法通常如下所示:

    public class AsyncHttpUtils {public static byte[] get(String url, ResponseHandler handler) {
            final Handler mHandler = new Handler();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    final byte[] result = HttpUtils.get(url);
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            responseHandler.onSuccess(result);
    }
    });
    }
    });
    }
    }

         其中,ResponseHandler接口的定义如下:

    public interface ResponseHandler {
        void onSuccess(byte[] result);
    }

        我们可以看到,以上实现异步GET请求的代码很直截了当,然而存在着以下问题:每次请求时都会创建一个线程,这样当请求比较频繁的情况下会创建大量大线程,这样的话创建、销毁线程以及线程调度的开销会很大。而且Thread对象是一个匿名内部类对象,会隐式持有外围类引用,可能会引起Memory Leak。

        针对以上问题,我们可以使用线程池来复用线程,以避免不必要的创建及销毁线程的开销,改进后AsyncHttpUtils类的代码如下:

    public class AsyncHttpUtils {
        //获取当前设备的CPU数
        public static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
        //核心池大小设为CPU数加1
        private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
        //设置线程池的最大大小
        private static final int MAX_POOL_SIZE = 2 * CPU_COUNT + 1;
        //存活时间
        private static final long KEEP_ALIVE = 5L;
        
        //创建线程池对象
        public static final Executor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
                MAX_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
    
        public static void get(final String url, final ResponseHandler responseHandler) {
            final Handler mHandler = new Handler(Looper.getMainLooper());
            
            //创建一个新的请求任务
            Runnable requestRunnable = new Runnable() {
                @Override
                public void run() {
                    final byte[] result = HttpUtils.get(url);
                    if (result != null) {
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                //result不为空表明请求成功,回调onSuccess方法
                                responseHandler.onSuccess(result);
                            }
                        });
                    }
                }
            };
            threadPoolExecutor.execute(requestRunnable);
        }
    }

       以上代码主要就是使用了线程池来达到线程的复用的目的,关于线程池的更加深入详细的介绍,大家可以看这里:深入理解Java之线程池

    3. 参考资料

        Android docs

  • 相关阅读:
    pyhton 163 email ssl attach file
    Database creation error: relation "ir_model" does not exist LINE 1: SELECT * FROM ir_model WHERE state='manual' ^
    爬虫心得
    WSL windows子系统ubuntu18.04建设自己的乌云
    WSL windwos 子系统 ubuntu18.04安装mysql
    python 163 email 554
    自定义的应用层协议(转)
    嵌入式杂谈之文件系统(转)
    linux VFS
    C++之保护和私有构造函数与析构函数
  • 原文地址:https://www.cnblogs.com/absfree/p/5385148.html
Copyright © 2011-2022 走看看