访问网络的框架(Volley和OkHttp3)使用

本博客:http://blog.csdn.net/xiaowu_zhu/article/details/70141015

Volley

Volley是在Google/IO大会上提出的,使得android应用网络操作更方便快捷

Volley既可以非常简单的访问网络,也可以轻松的加载图片,在不同的线程上异步执行所有请求而避免了阻塞主线程

设计目标: 适合数据量不大但通信操作频繁的网络操作,不适合大数据量的网络操作,比如文件下载

使用

  • Velloy中的RequestQueue和Request

    • RequestQueue用来执行请求的请求队列
    • Request用来构造一个请求对象
    • Request对象主要有以下几种类型:

      • StringReqeust 响应的主体为字符串
      • JsonArrayReqeust 发送和接收JSON对象
      • JsonObjectRequest发送和接收Json对象
      • ImageRequest发送和接收Image
  • 基本使用

    • 创建一个RequestQueue实例

      //这里的this指的是Context
      RequestQueue requestQueue = Volley.newRequestQueue(this);
      
    • 创建一个Request(义JsonObjectRequest为例,其它几个类似)

      private final String url="http:/xxxxx"//所需url
          JsonObjectRequest req=new JsonObjectRequest(url,null,new Response.Listener<JsonObject>(){
              @Override
              public void onResponse(JsonObject response){
                  //添加自己的响应逻辑,
              }
          },
          new ResponseError.Listener(){
              @Override
              public void onResponseError(VollerError error){
                  //错误处理
                  L.d("Error Message:","Error is"+error);
              }
         });  
      
      • 将request实例添加到requestQueue中

        requestQueue.add(jsonObjectRequest);

  • ImageLoader

    ImageLoader比ImageRequest更加高效,它不仅可以图片进行缓存,还可以过滤掉重复的链接,避免重复发送请求。

    由于ImageLoader不是继承Request的所以它的使用发送和以前不同,步骤如下:

    • 创建一个RequestQueue对象

      //这里的this指的是Context
      RequestQueue requestQueue = Volley.newRequestQueue(this);
      
    • 创建一个ImageLoader对象

      ImageLoader imageLoader = new ImageLoader(mQueue, new ImageCache() {  
          @Override  
          public void putBitmap(String url, Bitmap bitmap) {  
          }  
      
          @Override  
          public Bitmap getBitmap(String url) {  
              return null;  
          }  
      });  
      
    • 获取一个ImageListerner对象

      ImageListener listener = ImageLoader.getImageListener(imageView,  
              R.drawable.default_image, R.drawable.failed_image);  
      
    • 调用ImageLoader的get()方法加载网络上的图片

      imageLoader.get("https://img-my.csdn.net/uploads/201404/13/1397393290_5765.jpeg", listener); 
      //重载 
      mageLoader.get("https://img-my.csdn.net/uploads/201404/13/1397393290_5765.jpeg",  
                      listener, 200, 200);  
      
    • 为了很好的缓存图片,借助Android提供的LruCache功能,创建一个ImageCache

      • 新建一个BitmapCache并实现ImageCache接口

        public class BitmapCache implements ImageCache {  
        
            private LruCache<String, Bitmap> mCache;  
        
            public BitmapCache() {  
                int maxSize = 10 * 1024 * 1024;  
                mCache = new LruCache<String, Bitmap>(maxSize) {  
                    @Override  
                    protected int sizeOf(String key, Bitmap bitmap) {  
                        return bitmap.getRowBytes() * bitmap.getHeight();  
                    }  
                };  
            }  
            @Override  
            public Bitmap getBitmap(String url) {  
                return mCache.get(url);  
            }  
            @Override  
            public void putBitmap(String url, Bitmap bitmap) {  
                mCache.put(url, bitmap);  
            }  
        }  
        
  • NetworkImageView的用法

    除了ImageReqeust和ImageLoader外,Volley还提供了NetworkImageView。NetworkImageView是一个自定义控制,它继承自ImageView,具备ImageView控件的所有功能,并且在原生的基础之上加入了加载网络图片的功能。NetworkImageView控件的用法简单,步骤如下:

    • 创建一个RequestQueue对象
    • 创建一个ImageLoader对象
    • 在布局文件中添加一个NetworkImageView控件
    • 在代码中获取该控件的实例
    • 设置要加载的图片地址

    其中,第一第二步和ImageLoader的用法是完全一样的,因此这里我们就从第三步开始学习了。首先修改布局文件中的代码,在里面加入NetworkImageView控件,如下所示:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
        android:layout_width="fill_parent"  
        android:layout_height="fill_parent"  
        android:orientation="vertical" >  
    
        <Button  
            android:id="@+id/button"  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:text="Send Request" />  
    
        <com.android.volley.toolbox.NetworkImageView   
            android:id="@+id/network_image_view"  
            android:layout_width="200dp"  
            android:layout_height="200dp"  
            android:layout_gravity="center_horizontal" />  
    
    </LinearLayout> 
    

    接着在Activity获取到这个控件的实例,这就非常简单了,代码如下所示:

    networkImageView = (NetworkImageView) findViewById(R.id.network_image_view);  
    

    得到了NetworkImageView控件的实例之后,我们可以调用它的setDefaultImageResId()方法、setErrorImageResId()方法和setImageUrl()方法来分别设置加载中显示的图片,加载失败时显示的图片,以及目标图片的URL地址,如下所示:

    networkImageView.setDefaultImageResId(R.drawable.default_image);  
    networkImageView.setErrorImageResId(R.drawable.failed_image);  
    networkImageView.setImageUrl("https://img-my.csdn.net/uploads/201404/13/1397393290_5765.jpeg",  
                    imageLoader);  
    
  • 关闭

    如果在一个Activity里面启动了网络请求,而在这个网络请求还没返回结果的时候,如果Activity被结束了,则我们需要写如下代码作为防守:

    @Override public void onPostExecute(Result r) {  
        if (getActivity() == null) {  
            return;  
        }  
        // ...  
    }  
    

    Activity被终止之后,如果继续使用其中的Context等,除了无辜的浪费CPU,电池,网络等资源,有可能还会导致程序crash,所以,我们需要处理这种一场情况。

    使用Volley的话,我们可以在Activity停止的时候,同时取消所有或部分未完成的网络请求。

    Volley里所有的请求结果会返回给主进程,如果在主进程里取消了某些请求,则这些请求将不会被返回给主线程。
    比如,可以针对某些个request做取消操作:

    @Override  
    public void onStop() {  
        for (Request <?> req : mInFlightRequests) {  
            req.cancel();  
        }  
        ...  
    }  
    

    或者,取消这个队列里的所有请求:

    @Override pubic void onStop() {  
        mRequestQueue.cancelAll(this);  
        ...  
    }  
    

    也可以根据RequestFilter或者Tag来终止某些请求:

    @Override 
    public void onStop() {  
        mRequestQueue.cancelAll( new RequestFilter() {})  
        ...  
        // or  
        mRequestQueue.cancelAll(new Object());  
        ... 
    } 
    

OkHttp3

  • Android Studio 配置gradle环境:

    compile 'com.squareup.okhttp3:okhttp:3.5.0'
    compile 'com.squareup.okio:okio:1.11.0'
    
  • 添加网络权限

    <uses-permission android:name="android.permission.INTERNET"/>
    

使用教程

  • Http Get

    • 异步的Get

      在Http请求中最常见的就是get方法了,在大多数的使用场景中,我们使用的都是异步的Get请求

      // step 1: 创建 OkHttpClient 对象    
      OkHttpClient okHttpClient = new OkHttpClient();
      
      // step 2: 创建一个请求,不指定请求方法时默认是GET。
      Request.Builder requestBuilder = new Request.Builder().url("http://www.baidu.com");
      //可以省略,默认是GET请求
      requestBuilder.method("GET",null);
      
      // step 3:创建 Call 对象
      Call call = okHttpClient.newCall(requestBuilder.build());
      
      //step 4: 开始异步请求
      call.enqueue(new Callback() {
          @Override
          public void onFailure(Call call, IOException e) {
              // TODO: 17-1-4  请求失败
          }
          @Override
          public void onResponse(Call call, Response response) throws IOException {
              // TODO: 17-1-4 请求成功
              //获得返回体
              ResponseBody body = response.body();
          }
      });
      
    • 文件下载

      //step 1: 不变的第一步创建 OkHttpClick
      OkHttpClient okHttpClient = new OkHttpClient();
      
      //step 2: 创建Requset
      Request request = new Request.Builder()
              .url("http://www.ssyer.com/uploads/org_2017010593503_775.jpg")
              .build();
      
      //step 3:建立联系,创建Call
      mOkHttpClient.newCall(request).enqueue(new Callback() {
          @Override
          public void onFailure(Call call, IOException e) {
          }
      
          @Override
          public void onResponse(Call call, Response response) {
              InputStream inputStream = response.body().byteStream();
              FileOutputStream fileOutputStream = null;
              try {
                  File file = new File(Environment.getExternalStorageDirectory() + "大狮子.jpg");
                  fileOutputStream = new FileOutputStream(file);
                  byte[] buffer = new byte[2048];
                  int len = 0;
                  while ((len = inputStream.read(buffer)) != -1) {
                      fileOutputStream.write(buffer, 0, len);
                  }
                  fileOutputStream.flush();
              } catch (IOException e) {
                  e.printStackTrace();
              }
      
              Log.d("downloadAsynFile", "文件下载成功");
          }
      });
      
    • 同步的Get

      当然 Get 也支持阻塞方式的同步请求,不过在开发中这种方法很少被使用。上面我们也说了Call有一个 execute() 方法,你也可以直接调用 call.execute() 返回一个 Response 。然后利用 isSuccessful() 判读是否成功,进行相应的结果解析。

  • 异步的Http Post

    • Post 上传键值对

      //step 1: 同样的需要创建一个OkHttpClick对象
      OkHttpClient okHttpClient = new OkHttpClient();
      //step 2: 创建  FormBody.Builder
      FormBody formBody = new FormBody.Builder()
              .add("name", "dsd")
              .build();
      //step 3: 创建请求
      Request request = new Request.Builder().url("http://www.baidu.com")
              .post(formBody)
              .build();
      //step 4: 建立联系 创建Call对象
      okHttpClient.newCall(request).enqueue(new Callback() {
          @Override
          public void onFailure(Call call, IOException e) {
              // TODO: 17-1-4  请求失败
          }
          @Override
          public void onResponse(Call call, Response response) throws IOException {
              // TODO: 17-1-4 请求成功
          }
      });
      

      在使用 Post 的时候,参数是包含在请求体中的。所以我们通过 FormBody ,添加多个String键值对,然后为 Request 添加 post(formBody) 完成我们 Request 的构造。之后的步骤就和Get的步骤一样了,是不是很简单啊!

  • Post异步上传文件

    // step 1: 创建 OkHttpClient 对象
    OkHttpClient okHttpClient = new OkHttpClient();
    //step 2:创建 RequestBody 以及所需的参数
    //2.1 获取文件
    File file = new File(Environment.getExternalStorageDirectory() + "test.txt");
    //2.2 创建 MediaType 设置上传文件类型
    MediaType MEDIATYPE = MediaType.parse("text/plain; charset=utf-8");
    //2.3 获取请求体
    RequestBody requestBody = RequestBody.create(MEDIATYPE, file);
    //step 3:创建请求
    Request request = new Request.Builder().url("http://www.baidu.com")
            .post(requestBody)
            .build();
    //step 4 建立联系
    okHttpClient.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            // TODO: 17-1-4  请求失败
        }
        @Override
        public void onResponse(Call call, Response response) throws IOException {
            // TODO: 17-1-4 请求成功
        }
    });
    
    //添加权限
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    ---------------------------------------------------------------------------
    参数  说明
    text/html   HTML格式
    text/plain  纯文本格式
    text/xml    XML格式
    image/gif   gif图片格式
    image/jpeg  jpg图片格式
    image/png   png图片格式
    application/xhtml+xml   XHTML格式
    application/xml XML数据格式
    application/atom+xml    Atom XML聚合格式
    application/json    JSON数据格式
    application/pdf pdf格式
    application/msword  Word文档格式
    application/octet-stream    二进制流数据
    
posted @ 2017-04-12 11:27  jxiaow  阅读(59)  评论(0编辑  收藏  举报