网络请求库和图片加载库

Posted nangongyibin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络请求库和图片加载库相关的知识,希望对你有一定的参考价值。

网络请求库

概述:所有网络库的原理是: 网络请求一般是基于HttpURLConnection和HttpClient进行封装的,也有自己编写Socket实现的,比如ion和OkHttp;请求的执行一般是通过线程池来管理,异步请求得到结果,则通过回调接口接收;并且一般接收结果的回调都通过Handler去在主线程执行

Ion的使用

详情查看Github主页https://github.com/koush/ion

介绍: 

它支持网络请求和进行图片加载的双重功能 
拥有链式api风格(Fluent API) 
当Activity结束的时候支持自动的取消操作 
支持SPDY/HTTP2,缓存,Gzip压缩,HTTP连接的重用等 
并且是基于androidAsync实现的,AndroidAsync是作者的另一个使用socket实现的,遵循http协议的类库 

添加依赖

dependencies {

    compile ‘com.koushikdutta.ion:ion:2.+‘

}

 

使用ion进行get请求

    public void click(View view) {
        Ion.with(this).load(Api.TEST).asString().setCallback(new FutureCallback<String>() {
            @Override
            public void onCompleted(Exception e, String result) {
                if (e == null) {
                    String name = Thread.currentThread().getName();
                    Log.e(TAG, "onCompleted: " + name);
                    tv.setText(name);
                } else {
                    Log.e(TAG, "onCompleted: " + e.getMessage());
                }
            }
        });
    }

 

使用ion进行post请求,提交key-value形式的参数

    public void click1(View view) {
        Ion.with(this).load(Api.LOGIN).setBodyParameter("username", "username").setBodyParameter("password", "password").asString().setCallback(new FutureCallback<String>() {
            @Override
            public void onCompleted(Exception e, String result) {
                if (e == null) {
                    tv.setText(result);
                }
            }
        });
    }

 

使用ion进行post请求,提交json对象参数

    public void click1(View view) {
        Ion.with(this).load(Api.LOGIN).setBodyParameter("username", "username").setBodyParameter("password", "password").asString().setCallback(new FutureCallback<String>() {
            @Override
            public void onCompleted(Exception e, String result) {
                if (e == null) {
                    tv.setText(result);
                }
            }
        });
    }

 

使用ion进行上传文件,并显示进度

 

    public void click2(View view) {
        Log.e(TAG, "click2: ");
        File file = new File(Environment.getExternalStorageDirectory(), "dog.jpg");
        Log.e(TAG, "click2: " + file.getPath());
        Ion.with(this).load(Api.UPLOAD).uploadProgress(new ProgressCallback() {
            @Override
            public void onProgress(long downloaded, long total) {
                Log.e(TAG, "onProgress: " + downloaded * 100 / total);
            }
        })
                .setMultipartFile("file", file)
                .asString()
                .setCallback(new FutureCallback<String>() {
                    @Override
                    public void onCompleted(Exception e, String result) {
                        if (e == null) {
                            tv.setText(result);
                        }
                    }
                });
    }

 

使用ion进行下载文件,并且显示进度

    public void click3(View view) {
        File file = new File(Environment.getExternalStorageDirectory().getPath(), "a.jpg");
        try {
            if (file.exists()) {
                file.delete();
            }
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Ion.with(getApplicationContext()).load(Api.IMAGE).
                progress(new ProgressCallback() {
                    @Override
                    public void onProgress(long downloaded, long total) {
                        Log.e(TAG, "onProgress: " + downloaded * 100 / total);
                    }
                }).write(file).setCallback(new FutureCallback<File>() {
            @Override
            public void onCompleted(Exception e, File result) {
                if (e == null) {
                    Bitmap bitmap = BitmapFactory.decodeFile(result.getAbsolutePath());
                    tv.setBackgroundDrawable(new BitmapDrawable(bitmap));
                    Log.e(TAG, "onCompleted: " + result);
                } else {
                    Log.e(TAG, "onCompleted: " + e.getMessage());
                }
            }
        });
    }

 

Retrofit的使用

详情查看https://github.com/square/retrofit

介绍

Square公司为Android开源的类型安全的Http客户端 
底层基于OkHttp,使用OkHttp进行请求 
将java API的定义转换为interface形式 
使用annotation描述http请求 
支持配置json解析器 

添加依赖

compile ‘com.squareup.retrofit2:retrofit:2.1.0‘

compile ‘com.squareup.retrofit2:converter-gson:2.0.2‘

 

创建Retrofit实例对象

        Retrofit retrofit = new Retrofit.Builder().baseUrl(Api.SERVER_HOST).addConverterFactory(GsonConverterFactory.create()).build();
        retrofitApi = retrofit.create(RetrofitApi.class);

 

定义业务逻辑接口

public interface RetrofitApi {
    @GET("test")
    Call<People> getTest();

    @FormUrlEncoded
    @POST("login")
    Call<User> login(@Field("username") String username, @Field("password") String password);

    @GET("image")
    Call<ResponseBody> download();

    @Multipart
    @POST("uploadMulti")
    Call<ResponseBody> upload(@PartMap Map<String, RequestBody> map);
}

 

创建接口实例对象

        retrofitApi = retrofit.create(RetrofitApi.class);

 

获取业务方法的调用对象,并进行请求

    public void click1(View view) {
        Call<People> call = retrofitApi.getTest();
        call.enqueue(new Callback<People>() {
            @Override
            public void onResponse(Call<People> call, Response<People> response) {
                People body = response.body();
                Log.e(TAG, "onResponse: " + body.getNickname());
                tv.setText(body.getNickname());
            }

            @Override
            public void onFailure(Call<People> call, Throwable t) {

            }
        });
    }

 

Retrofit的url注解处理

使用@Path注解来处理url路径不固定的需求,如

 @GET("test/{order}")//获取订单的某段路径不固定,

    @GET("test")
    Call<People> getTest();

 

使用@Query注解来替换url后面跟的参数,如:

    @FormUrlEncoded
    @POST("login")
    Call<User> login(@Field("username") String username, @Field("password") String password);

 

使用@QueryMap来替换多个查询参数,如

    @Multipart
    @POST("uploadMulti")
    Call<ResponseBody> upload(@PartMap Map<String, RequestBody> map);

 

使用@Post注解进行post请求,提交key-value数据,如

    @FormUrlEncoded
    @POST("login")
    Call<User> login(@Field("username") String username, @Field("password") String password);

 

使用@Post注解进行post请求,提交json数据,如

    @GET("image")
    Call<ResponseBody> download();

 

使用@Headers定义请求头,如

//定义请求头

@Headers({

        "Accept: application/vnd.github.v3.full+json",

        "User-Agent: Retrofit-Sample-App"

})

 

使用ResponseBody来接收流的数据,比如下载文件

    @GET("image")
    Call<ResponseBody> download();

 

使用@Muptipart和@Part或者@PartMao封装多块请求体

    @Multipart
    @POST("uploadMulti")
    Call<ResponseBody> upload(@PartMap Map<String, RequestBody> map);

 

需要注意的是,构建RequestBody的时候要注意拼接:

    public void click4(View view) {
        File file = new File(Environment.getExternalStorageDirectory(), "a.jpg");
        File file2 = new File(Environment.getExternalStorageDirectory(), "dog.jpg");
        RequestBody fileBody = RequestBody.create(MediaType.parse("image/jpeg"), file);
        RequestBody fileBody2 = RequestBody.create(MediaType.parse("image/jpeg"), file2);
        HashMap<String, RequestBody> map = new HashMap<>();
        map.put("file"; filename="" + file.getName(), fileBody);
        map.put("file"; filename="" + file2.getName(), fileBody2);
        Call<ResponseBody> call = retrofitApi.upload(map);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                try {
                    String string = response.body().string();
                    tv.setText(string);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.e(TAG, "onFailure: " + t.getLocalizedMessage());
            }
        });
    }

 

Volley的使用

介绍 


谷歌开源的,专注于处理高频率的数据比较小的请求 
内部仍然是使用的HttpURLConnection和HttpClient进行网络请求的,只是对于不同的Android版本进行了响应的切换,2.3之前使用的HttpClient,2.3之后使用的是HttpURLConnection 
支持取消请求 
具有网络请求和图片加载的功能 


添加依赖

compile ‘com.android.volley:volley:1.0.0‘

 

创建RequestQueue请求队列,它是用来执行请求对象的

        queue = Volley.newRequestQueue(this);

 

创建请求对象,这里使用最简单的StringRequest:

    public void click(View view) {
        StringRequest stringRequest = new StringRequest(Api.TEST, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                tv.setText(response);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e(TAG, "onErrorResponse: " + error.getLocalizedMessage());
            }
        });
        queue.add(stringRequest);
    }

 

执行请求,将Request对象添加到RequestQueue中,即可

    public void click1(View view) {
        MyQuest request = new MyQuest(Request.Method.POST, Api.LOGIN, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                tv.setText(response);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e(TAG, "onErrorResponse: " + error.getLocalizedMessage());
            }
        });
        HashMap<String, String> map = new HashMap<>();
        map.put("username", "username");
        map.put("password", "password");
        request.setParam(map);
        queue.add(request);
    }

 

使用Volley发送post请求,需要自己重写Request的getParams方法

    private class MyQuest extends StringRequest {
        private Map<String, String> param = null;

        public void setParam(Map<String, String> param) {
            this.param = param;
        }

        public MyQuest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
            super(url, listener, errorListener);
        }

        public MyQuest(int method, String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
            super(method, url, listener, errorListener);
        }

        protected Map<String, String> getParam() throws AuthFailureError {
            return param;
        }
    }

 

图片加载库

原理概述:图片加载的工作流(task flow)都是3级缓存的流程;图片的内存缓存一定是LruCache实现;图片下载和读取线程的调度一定是通过线程池管理

画图说明图片加载原理

Glide的使用 
详情查看https://github.com/bumptech/glide

介绍:

专注于处理平滑滑动的图片类库 
默认使用HttpUrlConnection下载图片 
支持设置渐渐显示的动画 
支持设置加载中的图片 

添加依赖

compile ‘com.github.bumptech.glide:glide:3.7.0‘

 

使用Glide加载图片

        Glide.with(this).load(Constants.IMAGES[1]).centerCrop().placeholder(R.mipmap.ic_launcher)
                .error(R.mipmap.ic_launcher).crossFade(500).into(iv);

 

Picasso的使用

详情查看https://github.com/square/picasso

介绍:

 

Square开源的比较早的图片加载类库 
自动处理adapter中的ImageView的回收时取消下载图片 
支持加载多种来源的图片,比如网络,sd卡,res资源 
支持设置占位图片 
支持对图片的自定义处理 


添加依赖

compile ‘com.squareup.picasso:picasso:2.5.2‘

 

使用Picasso加载图片

        Picasso.with(this)
                .load(Constants.IMAGES[1])
                .centerCrop()
                .placeholder(R.mipmap.ic_launcher)
                .error(R.mipmap.ic_launcher)
                .noFade()
                .resize(200,140)
                .into(iv);

 

加载其他资源路径的图片

Picasso.with(context).load(R.drawable.landing_screen).into(imageView1);

Picasso.with(context).load("file:///android_asset/DvpvklR.png").into(imageView2);

Picasso.with(context).load(new File(...)).into(imageView3);

 

注意:如果不设置resize(120,120),则Picasso会加载整个图片,显然这样消耗的内存比较大,一般都需要指定一下,而Glide内部已经默认参考了控件的宽高来进行缩放了。

Fresco的使用

详情查看https://github.com/facebook/fresco

介绍:

 

Facebook开源的专注于优化java堆内存,最大程度减少OOM 
在Android4.4以及以下,将图片存储在Android的一块特殊的内存区域,这会让图片处理更加快速 
支持Gif和WebP格式的图片 


添加依赖

compile ‘com.facebook.fresco:fresco:0.11.0‘

 

首先初始化Fresco,一般在Application的onCreate中初始化

        Fresco.initialize(getApplicationContext());

 

使用Fresco提供的SimpleDraweeView显示图片

        iv.setImageURI(Constants.IMAGES[1]);

 

由于使用的是自定义控件加载图片,那么通过定义属性来进行设置:

    <com.facebook.drawee.view.SimpleDraweeView
        android:id="@+id/iv"
        android:layout_width="200dp"
        android:layout_height="140dp"
        fresco:actualImageScaleType="centerCrop"
        fresco:fadeDuration="300"
        fresco:failureImage="@mipmap/dialog_title_default_icon"
        fresco:failureImageScaleType="centerInside"
        fresco:placeholderImage="@mipmap/ic_launcher"
        fresco:placeholderImageScaleType="fitCenter"
        fresco:pressedStateOverlayImage="@color/colorRed"
        fresco:progressBarAutoRotateInterval="1000"
        fresco:progressBarImage="@mipmap/loading"
        fresco:progressBarImageScaleType="centerInside"
        fresco:retryImage="@mipmap/dialog_title_default_icon"
        fresco:retryImageScaleType="centerCrop"
        fresco:roundAsCircle="true"
        fresco:roundBottomLeft="false"
        fresco:roundBottomRight="true"
        fresco:roundTopLeft="true"
        fresco:roundTopRight="false"
        fresco:roundedCornerRadius="15dp"
        fresco:roundingBorderColor="@color/colorAccent"
        fresco:roundingBorderWidth="2dp" />

 

 

属性解释:

placeholderImage就是所谓的展位图啦,在图片没有加载出来之前你看到的就是它

 

failureIamge看到名字就知道是什么了,图片加载失败时显示的图片就是它了

 

retryImage图片加载失败时显示,提示用户点击重新加载,重复加载4次还是没有加载出来的时候才会显示failureImage的图片

 

progressBarImage进度条图片

backgroundImage背景图片,这里的背景图片首先被绘制

 

overlayImage设置叠加图,在xml中只能设置一张叠加图片,如果需要多张图片的话,需要在java代码中设置哦

pressedStateOverlayImage设置点击状态下的叠加图,此叠加图不能缩放

 

ImageScaleType这个就是各种各样的图片缩放样式了,center,centerCrop,fouseCrop,centerInside,fitCenter,fitStart,fitEnd,fitXY

 


























以上是关于网络请求库和图片加载库的主要内容,如果未能解决你的问题,请参考以下文章

关于Linux静态库和动态库的分析

什么叫静态库和动态库

ESP8266 – WiFiClient库和ESP8266HTTPClient库

koltin协程图片加载库Coil介绍

vue3.0中用自定义指令实现图片懒加载

如何进行前端优化