封装一个异步下载的工具包

在我们进行一些下载的工作时, 有一部分代码是重复的, 那么,我们每一次进行这样的工作的时候, 都要重复写这些代码, 这样是非常浪费时间哒. 所以, 我们可以将这部分代码封装起来, 形成一个工具包, 每次用的时候只要导入就可以啦(这里只是针对网络数据, 不包含图片).

工具类NetWorkAsync

为了实现封装, 要把url作为一个属性, 通过构造方法传入值, 并且返回一个结果(Object 类型)
代码如下:

public class NetWorkAsync<T> extends AsyncTask<NetWorkAsync.Callback<T>, Void, Object> {
    private Callback<T> callback;
    private String url;
    private Class<T> t;

    public NetWorkAsync(String url, Class<T> t) {
        this.url = url;
        this.t = t;
    }
}

这个类要继承AsyncTask, 并实现里面的几个方法. 在这几个方法里, 我们执行的工作有这么几个:
下载之前的准备工作(可以没有), 下载(必须有), 下载结束之后的判断工作(是否是空)
代码如下:

 protected Object doInBackground(Callback<T>... params) {
        callback = params[0];
        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();
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len;
                while ((len = is.read(buffer)) != -1){
                    bos.write(buffer, 0, len);
                }
                String s = bos.toString("UTF-8");
                //解析
                Gson gson = new Gson();
                return gson.fromJson(s, t);
            }else {
                return new RuntimeException("error");
            }
        } catch (IOException e) {
           return e;
        }
    }
 @Override
    protected void onPostExecute(Object o) {
        super.onPostExecute(o);
        if (t.isInstance(o)){
        //如果下载成功, 就回调onSuccess方法
            callback.onSuccess((T) o);
        }else if (o instanceof Exception){
        //如果下载失败, 就回调onFail方法
            callback.onFail((Exception) o);

        }
    }

无论成功与失败, 都要调用onSuccess/onFail方法, 将信息传送出去. 回调的接口在MainActivity中实现, 达到传递信息的功能

 public interface Callback<S>{
        void onSuccess(S text);
        void onFail(Exception e);
    }

我们可以观察到, 很多地方都用到了泛型T, 这就保证了在不同的情形下, 这个类就可以面向不同的类型使用.

添加注解

说到添加注解, 就会想到用动态接口去实现获取信息.
首先要先创建一个得到url的注解 代码如下:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UrlString {
//得到url的方法
    String url();
}

那么, 动态接口与普通接口有什么区别呢? 如果要对一个接口进行实例化, 就一定要实现这个接口, 再实例化. 动态接口就不需要实现这个接口, 可以直接通过一个工厂, 用getInstace方法得到实例 代码如下:

    public static<T> T getInstace(Class<T> type) {
        Object o = Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, new MyHandler());
        return ((T) o);
    }

通过观察newProxyInstance方法我们可以发现, 需要有一个Handler参数, 所以, 我们要写一个Handler来实现自己的需求.
在写Handler之前, 我们要知道, 为什么需要这样一个Handler呢? 之前讲到, 动态接口是不需要实现的, 那么, 也就是说, 这个接口里的方法是没有没有实现方法体的, 那么, 我们的需求在哪里实现呢? 在Handler中, 我们会实现一个invoke方法, 在调用到接口中的方法时, 会自动跳转进入invoke方法.

    private static class MyHandler implements InvocationHandler{
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            UrlString annotation = method.getAnnotation(UrlString.class);
            if (annotation != null) {
                String url = String.format(Locale.CHINA, annotation.url(), args);
                Class<?> returnType = method.getReturnType();
                if (returnType.equals(NetWorkAsync.class)){
                    ParameterizedType type = (ParameterizedType) method.getGenericReturnType();
                    Type entryType = type.getActualTypeArguments()[0];
                    return new NetWorkAsync<>(url, (Class<Object>) entryType);
                }
            }
            return null;
        }
    }

这样, 这个下载的功能已经实现完毕, 只需要在实用的时候, 创建一个接口, 将url作为注解添加上就可以获取并传入NetWorkAsync类, 进行下载.

接口是这个样子哒

public interface TopServer {
    @UrlString(url = "http://www.tngou.net/api/top/list?id=%d&page=%d&rows=%d")
    NetWorkAsync<Result> getList(int id, int page, int rows);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值