Android 写一个简单的网络请求框架

    虽然市面上有很多优秀的开源网络框架,例如volley,Okhttp。为啥还要自己来手写一个呢?主要是为了加深一下自己的记忆,还有把自己的技术点串联起来。代码并不难,都挺简单的,有详细的注释。可以优化的地方很多,但是写文的时候状态不是特别好,所以就懒得去改了。再者,大部分情况下我也是会去用OKHttp的!写下来是对自己花费时间的认可。

    我相信大部分朋友手写一个简单的网络请求框架都没什么问题。不过温故而知新嘛,我再写一遍的时候,倒是发现了一些以前未曾注意的地方

    这个框架稍微注重了一下多并发的问题。但是没有集合命令模式,所以没有撤销请求这个功能。

    第一个类是展示给应用层调用的静态方法。写成静态方法是因为我懒,喜欢的可以自己改成链式调用。这个方法需要传入的参数也写的很清楚啦!

public class SimpleHttp {

    /**
     * 访问地址URL
     * 请求参数DATA
     * 回调函数 Listener
     * 需要的类型Cls
     */

    public static<T,K> void sendRequest(String url, T data, Class<K> cls, IHttpRequestListener listener){
        //构建一个请求对象
        IHttpRequest iHttpRequest=new HttpRequest();
        //构建一个返回回调
        IHttpResponseListener iHttpResponseListener=new HttpResponseListener<>(cls,listener);
        //构建一个请求线程
        HttpTask httpTask=new HttpTask(iHttpRequest,url,data,iHttpResponseListener);
        //构建一个线程管理
        ThreadManager.getInstance().addTask(httpTask);

    }

}

 这个是请求的对象接口,至少得满足可扩展性嘛!

public interface IHttpRequest {

    //访问的链接URL
    void setUrl(String Url);

    //请求的参数
    void setBytes(byte[] data);

    //请求返回的回调
    void setIDnHttpResponseListener(IHttpResponseListener iDnHttpResponseListener);

    //请求方法
    void execute();
}

 这个是请求的实现类啦!选的是HttpURLConnection 因为足够轻量,基本能满足需求。请求方法我没有封装到外面,想要使用的可以自行封装一下。

public class HttpRequest implements IHttpRequest {

    private String Url;
    private byte[] data;
    private IHttpResponseListener iDnHttpResponseListener;

    private HttpURLConnection httpURLConnection;

    @Override
    public void setUrl(String Url) {
        this.Url = Url;

    }

    @Override
    public void setBytes(byte[] data) {
        this.data = data;
    }

    @Override
    public void setIDnHttpResponseListener(IHttpResponseListener iDnHttpResponseListener) {

        this.iDnHttpResponseListener=iDnHttpResponseListener;
    }

    @Override
    public void execute() {

        URL url = null;
        try {
            url = new URL(this.Url);
            httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setConnectTimeout(6000);  //连接超时时间
            httpURLConnection.setUseCaches(false);  //不使用缓存
            httpURLConnection.setInstanceFollowRedirects(true); //是成员变量 仅作用域当前函数,设置当前这个对象
            httpURLConnection.setReadTimeout(3000); //响应超时的时间
            httpURLConnection.setDoInput(true);  //设置这个连接对否可以写入数据;
            httpURLConnection.setDoOutput(true);  //设置这个连接对否可以输出数据;
            httpURLConnection.setRequestMethod("POST");    //设置这个请求的方法
            httpURLConnection.setRequestProperty("Content-Type","application/json;charset=UTF-8");
            httpURLConnection.connect();    //建立连接
            //---------------使用字节流发送数据---------------------------
            OutputStream out = httpURLConnection.getOutputStream();
            //缓冲字节流  包装字节流
            BufferedOutputStream bos = new BufferedOutputStream(out);
            //把字节流数组写入缓冲区中
            bos.write(data);
            //刷新缓冲区 发送数据
            bos.flush();
            out.close();
            bos.close();
            //如果响应码为200代表请求访问成功
            if(httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK){
                InputStream in = httpURLConnection.getInputStream();
                //回调内部的回调接口
                iDnHttpResponseListener.onSuccess(in);
            }else{
                throw new RuntimeException("请求失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("请求失败");
        }finally {
            //关闭httpURLConnection对象
            httpURLConnection.disconnect();
        }


    }
}

这是返回时用的回调接口,实现2个方法即可。 


public interface IHttpResponseListener {

    //返回成功
    void onSuccess(InputStream inputStream);

    //反回失败
    void onFailed();

}

 返回回调接口的实现类,把返回回来的参数转换成自己想要的数据类型。

public class HttpResponseListener<T> implements IHttpResponseListener {

    private IHttpRequestListener listener;
    private Class<T> cls ;
    //切换线程
    Handler handler=new Handler(Looper.getMainLooper());

    public HttpResponseListener(Class<T>cls , IHttpRequestListener listener){
        this.cls=cls;
        this.listener=listener;
    }


    @Override
    public void onSuccess(InputStream inputStream) {
        String responseStr=getContent(inputStream);
        final T t= JSON.parseObject(responseStr,cls);
        handler.post(new Runnable() {
            @Override
            public void run() {
                listener.onSuccess(t);
            }
        });

    }

    @Override
    public void onFailed() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                listener.onFailed();
            }
        });
    }


    /**
     * inputStream转为String类型
     * @param inputStream
     * @return
     */
    private String getContent(InputStream inputStream) {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        StringBuilder sb = new StringBuilder();
        String line = null;
        try {
            while ((line = bufferedReader.readLine()) != null) {
                sb.append(line + "/n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString().replace("/n","");
    }

}

 线程池的管理类,这里为什么要用LinkedBlockingQueue不用ArrayBlockingQueue的原因在于

链表持有2把锁,可以同时进出,但是Array只有一把锁。

在只进或者只出的时候,用数组会有明显优势,但是要满足同时进出,链表会更快。

这里还用了DelayQueue,这是一个延时列表。如果不设置延时时间,会出问题

虽然拒绝策略大部分时候都没啥用,但是你不写肯定是不行的

public class ThreadManager {
    private static ThreadManager threadManager=new ThreadManager();

    public static ThreadManager getInstance(){
        return threadManager;
    }

    //请求队列
    private LinkedBlockingQueue<Runnable> requestQueue=new LinkedBlockingQueue<>();
    //失败队列
    private DelayQueue<Delayed> failedQueue=new DelayQueue<>();
    //线程池
    private ThreadPoolExecutor threadPoolExecutor;


    private ThreadManager(){

        threadPoolExecutor = new ThreadPoolExecutor(3, 10, 15,
                TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(4), new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                addTask(r);
            }
        });
        threadPoolExecutor.execute(runnable);
        threadPoolExecutor.execute(failRunnable);
    }

    //添加线程
    public void addTask(Runnable runnable){
        if(runnable==null){
            return;
        }
        try {
            requestQueue.put(runnable);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //添加失败线程
    public void addFailedTask(HttpTask httpTask){
        if(httpTask==null){
            return;
        }

        httpTask.setDelayTIme(3000);
        failedQueue.offer(httpTask);
    }

    //核心线程
    private Runnable runnable=new Runnable() {
        @Override
        public void run() {
            while (true){
                try {
                    Runnable runnable=requestQueue.take();
                    threadPoolExecutor.execute(runnable);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

    //失败核心线程
    private Runnable failRunnable=new Runnable() {
        @Override
        public void run() {
            while (true){
                try {
                    HttpTask httpTask= (HttpTask) failedQueue.take();

                    if(httpTask.getRetryTimes()<3){

                        httpTask.setRetryTimes(httpTask.getRetryTimes()+1);
                        threadPoolExecutor.execute(httpTask);
                    }else {
                        IHttpResponseListener httpResponseListener=httpTask.getListener();
                        httpResponseListener.onFailed();
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

}

 这个就是请求的线程啦!之后需要把请求线程交给线程池去管理。

public class HttpTask<T> implements Runnable, Delayed {
    private IHttpRequest iHttpRequest;
    private IHttpResponseListener listener;
    //延迟时间
    private long delayTIme;
    //重试次数
    private int retryTimes;


    public HttpTask(IHttpRequest iHttpRequest,String url,T Data,IHttpResponseListener listener){
        this.iHttpRequest=iHttpRequest;
        this.listener=listener;
        this.iHttpRequest.setUrl(url);
        this.iHttpRequest.setIDnHttpResponseListener(listener);

        if(Data!=null){
            String jsonStr= JSON.toJSONString(Data);
            try {
                this.iHttpRequest.setBytes(jsonStr.getBytes("UtF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

        }

    }


    @Override
    public void run() {
        try {
            this.iHttpRequest.execute();

        }catch (Exception e){

            ThreadManager.getInstance().addFailedTask(this);
        }
    }

    public IHttpResponseListener getListener() {
        return listener;
    }

    public long getDelayTIme() {
        return delayTIme;
    }

    public void setDelayTIme(long delayTIme) {
        this.delayTIme = delayTIme+System.currentTimeMillis();
    }

    public int getRetryTimes() {
        return retryTimes;
    }

    public void setRetryTimes(int retryTimes) {
        this.retryTimes = retryTimes;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(getDelayTIme()-System.currentTimeMillis(),TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        return 0;
    }
}

    大部分地方都加了注释,加上代码本身难度也不高。如果还有什么问题也可以直接问我。

发布了8 篇原创文章 · 获赞 4 · 访问量 4781

猜你喜欢

转载自blog.csdn.net/woailqy/article/details/104953311