1. 程式人生 > >Android中的Volley通訊框架

Android中的Volley通訊框架

首先使用Volley類建立 RequestQueue queue = Volley.newRequestQueue(this); 

Making GET Requests

<span style="font-size:14px;">final String url = "http://httpbin.org/get?param1=hello";
 
// prepare the Request
JsonObjectRequest getRequest = new JsonObjectRequest(Request.Method.GET, url, null,
    new Response.Listener<JSONObject>() 
    {
        @Override
        public void onResponse(JSONObject response) {   
                        // display response     
            Log.d("Response", response.toString());
        }
    }, 
    new Response.ErrorListener() 
    {
         @Override
         public void onErrorResponse(VolleyError error) {            
            Log.d("Error.Response", response);
       }
    }
);
 
// add it to the RequestQueue   
queue.add(getRequest);</span>

Making POST Requests

url = "http://httpbin.org/post";
StringRequest postRequest = new StringRequest(Request.Method.POST, url, 
    new Response.Listener<String>() 
    {
        @Override
        public void onResponse(String response) {
            // response
            Log.d("Response", response);
        }
    }, 
    new Response.ErrorListener() 
    {
         @Override
         public void onErrorResponse(VolleyError error) {
             // error
             Log.d("Error.Response", response);
       }
    }
) {     
    @Override
    protected Map<String, String> getParams() 
    {  
            Map<String, String>  params = new HashMap<String, String>();  
            params.put("name", "Alif");  
            params.put("domain", "http://itsalif.info");
             
            return params;  
    }
};
queue.add(postRequest);

Making PUT Requests

url = "http://httpbin.org/put";
StringRequest putRequest = new StringRequest(Request.Method.PUT, url, 
    new Response.Listener<String>() 
    {
        @Override
        public void onResponse(String response) {
            // response
            Log.d("Response", response);
        }
    }, 
    new Response.ErrorListener() 
    {
         @Override
         public void onErrorResponse(VolleyError error) {
                         // error
             Log.d("Error.Response", response);
       }
    }
) {
 
    @Override
    protected Map<String, String> getParams() 
    {  
            Map<String, String>  params = new HashMap<String, String> ();  
            params.put("name", "Alif");  
            params.put("domain", "http://itsalif.info");
             
            return params;  
    }
 
};
 
queue.add(putRequest);

Making DELETE Requests

url = "http://httpbin.org/delete";
StringRequest dr = new StringRequest(Request.Method.DELETE, url, 
    new Response.Listener<String>() 
    {
        @Override
        public void onResponse(String response) {
            // response
            Toast.makeText($this, response, Toast.LENGTH_LONG).show();
        }
    }, 
    new Response.ErrorListener() 
    {
         @Override
         public void onErrorResponse(VolleyError error) {
             // error.
              
       }
    }
);
queue.add(dr);

Volley中圖片載入

volley圖片載入有三種方式:

記得:Volley中已經實現了磁碟快取了,檢視原始碼得知通過

context.getCacheDir()獲取到了 /data/data/<application package>/cache內部儲存路徑,預設大小是5MB.所以我們只需要再實現記憶體快取就可以了

1. ImageRequest

singleImg=(ImageView)findViewById(R.id.volley_img_single_imgeview);
        ImageRequest imgRequest=new ImageRequest(url, new Response.Listener<Bitmap>() {
            @Override
            public void onResponse(Bitmap arg0) {
                // TODO Auto-generated method stub
                singleImg.setImageBitmap(arg0);
            }
        }, 300, 200, Config.ARGB_8888, new ErrorListener(){
            @Override
            public void onErrorResponse(VolleyError arg0) {
                // TODO Auto-generated method stub
                
            }            
        });
        mRequestQueue.add(imgRequest);

可以看到,ImageRequest的建構函式接收六個引數,第一個引數就是圖片的URL地址,這個沒什麼需要解釋的。第二個引數是圖片請求成功的回撥,這裡我們把返回的Bitmap引數設定到ImageView中。第三第四個引數分別用於指定允許圖片最大的寬度和高度,如果指定的網路圖片的寬度或高度大於這裡的最大值,則會對圖片進行壓縮,指定成0的話就表示不管圖片有多大,都不會進行壓縮。第五個引數用於指定圖片的顏色屬性,Bitmap.Config下的幾個常量都可以在這裡使用,其中ARGB_8888可以展示最好的顏色屬性,每個圖片畫素佔據4個位元組的大小,而RGB_565則表示每個圖片畫素佔據2個位元組大小。第六個引數是圖片請求失敗的回撥,這裡我們當請求失敗時在ImageView中顯示一張預設圖片。

最後將這個ImageRequest物件新增到RequestQueue裡就可以了

2. ImageLoader

RequestQueue mRequestQueue = Volley.newRequestQueue(this);
        final LruCache<String, Bitmap> mImageCache = new LruCache<String, Bitmap>(
                20);
        ImageCache imageCache = new ImageCache() {
            @Override
            public void putBitmap(String key, Bitmap value) {
                mImageCache.put(key, value);
            }

            @Override
            public Bitmap getBitmap(String key) {
                return mImageCache.get(key);
            }
        };
        ImageLoader mImageLoader = new ImageLoader(mRequestQueue, imageCache);
        // imageView是一個ImageView例項
        // ImageLoader.getImageListener的第二個引數是預設的圖片resource id
        // 第三個引數是請求失敗時候的資源id,可以指定為0
        ImageListener listener = ImageLoader
                .getImageListener(imageView, android.R.drawable.ic_menu_rotate,
                        android.R.drawable.ic_delete);
        mImageLoader.get(url, listener);

可以看出ImageLoader這個類需要一個Request的例項以及一個ImageCache的例項。圖片通過一個URL和一個ImageListener例項的get()方法就可以被載入。從哪裡,ImageLoader會檢查ImageCache,而且如果快取裡沒有圖片就會從網路上獲取。Volley的ImageCache介面允許你使用你喜歡的L1快取實現。不幸的是Volley沒有提供預設的實現。在I/O的介紹中展示了BitmapLruCache的一點程式碼片段,但是Volley這個庫本身並不包含任何相關的實現。

ImageCache介面有兩個方法,getBitmap(String url)和putBitmap(String url, Bitmap bitmap).這兩個方法足夠簡單直白,他們可以新增任何的快取實現。

3.NetworkImageView

除了以上兩種方式之外,Volley還提供了第三種方式來載入網路圖片,即使用NetworkImageView。不同於以上兩種方式,NetworkImageView是一個自定義控制,它是繼承自ImageView的,具備ImageView控制元件的所有功能,並且在原生的基礎之上加入了載入網路圖片的功能。NetworkImageView控制元件的用法要比前兩種方式更加簡單,大致可以分為以下五步:

1. 建立一個RequestQueue物件。

2. 建立一個ImageLoader物件。

3. 在佈局檔案中新增一個NetworkImageView控制元件。

4. 在程式碼中獲取該控制元件的例項。

5. 設定要載入的圖片地址。

其中,第一第二步和ImageLoader的用法是完全一樣的,因此這裡我們就從第三步開始學習了。首先修改佈局檔案中的程式碼,在裡面加入NetworkImageView控制元件,如下所示

XML

<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地址,如下所示:

1 networkImageView.setDefaultImageResId(R.drawable.default_image);  
2 
3 networkImageView.setErrorImageResId(R.drawable.failed_image); 
4 
5 networkImageView.setImageUrl("http://img.my.csdn.net/uploads/201404/13/1397393290_5765.jpeg", imageLoader); 

好了,就是這麼簡單,現在重新執行一下程式,你將看到和使用ImageLoader來載入圖片一模一樣的效果,這裡我就不再截圖了。

這時有的朋友可能就會問了,使用ImageRequest和ImageLoader這兩種方式來載入網路圖片,都可以傳入一個最大寬度和高度的引數來對圖片進行壓縮,而NetworkImageView中則完全沒有提供設定最大寬度和高度的方法,那麼是不是使用NetworkImageView來載入的圖片都不會進行壓縮呢?

其實並不是這樣的,NetworkImageView並不需要提供任何設定最大寬高的方法也能夠對載入的圖片進行壓縮。這是由於NetworkImageView是一個控制元件,在載入圖片的時候它會自動獲取自身的寬高,然後對比網路圖片的寬度,再決定是否需要對圖片進行壓縮。也就是說,壓縮過程是在內部完全自動化的,並不需要我們關心,NetworkImageView會始終呈現給我們一張大小剛剛好的網路圖片,不會多佔用任何一點記憶體,這也是NetworkImageView最簡單好用的一點吧。

當然了,如果你不想對圖片進行壓縮的話,其實也很簡單,只需要在佈局檔案中把NetworkImageView的layout_width和layout_height都設定成wrap_content就可以了,這樣NetworkImageView就會將該圖片的原始大小展示出來,不會進行任何壓縮。

這樣我們就把使用Volley來載入網路圖片的用法都學習完了。

Volley自定義Request及使用單例封裝RequestQueue

一.自定義Request

Volley的所有的請求的超型別是Resuest,所有我們常用的請求都是這個類的子類,那麼我們自定義View肯定也是基於這個類的。

案例:

package com.zhy.velloydemo;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;

public class JsonRequestWithAuth<T> extends Request<T>
{
    private final Gson gson = new Gson();
    private final Class<T> clazz;
    private final Listener<T> listener;

    private static Map<String, String> mHeader = new HashMap<String, String>();
    /**
     * 設定訪問自己伺服器時必須傳遞的引數,金鑰等
     */
    static
    {
        mHeader.put("APP-Key", "LBS-AAA");
        mHeader.put("APP-Secret", "ad12msa234das232in");
    }

    /**
     * @param url
     * @param clazz
     *            我們最終的轉化型別
     * @param headers
     *            請求附帶的頭資訊
     * @param listener
     * @param appendHeader
     *            附加頭資料
     * @param errorListener
     */
    public JsonRequestWithAuth(String url, Class<T> clazz, Listener<T> listener, Map<String, String> appendHeader,
            ErrorListener errorListener)
    {
        super(Method.GET, url, errorListener);
        this.clazz = clazz;
        this.listener = listener;
        mHeader.putAll(appendHeader);
    }

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError
    {
        // 預設返回 return Collections.emptyMap();
        return mHeader;
    }

    @Override
    protected void deliverResponse(T response)
    {
        listener.onResponse(response);
    }

    @Override
    protected Response<T> parseNetworkResponse(NetworkResponse response)
    {
        try
        {
            /**
             * 得到返回的資料
             */
            String jsonStr = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
            /**
             * 轉化成物件
             */
            return Response.success(gson.fromJson(jsonStr, clazz), HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e)
        {
            return Response.error(new ParseError(e));
        } catch (JsonSyntaxException e)
        {
            return Response.error(new ParseError(e));
        }
    }
}

這裡說一下,我在Header中放置了APP-key等資料,也就是說只要我們這個請求發的都會有這幾個值,大家開發app時肯定有很多請求引數是需要每次都發往伺服器校驗的,可以在這裡設定。

二 使用單例模式(封裝RequestQueue )

如果app連線網路比較頻繁,最合理的方式就是把RequestQueue實現為單例項型別,並這個例項在app執行的整個生命週期中存活。有兩種方式實現 單例項,推薦的一種做法就是實現一個封裝了請求佇列和其他volley功能的單例類。還有一種不建議使用的方式就是建立一個繼承Application的 字類,並在Application.onCreate()方法中建立請求佇列。一個靜態的單例項類能夠以模組化的方式提供同樣的功能。

使 用推薦的方式實現單例項最重要的概念就是請求佇列物件必須以應用上下文(application context)而不是活動上下文(activity context)的形式進行例項化。以此確保了請求佇列物件在app執行的整個生命週期中存在,而不是隨著活動的重新建立而建立。結合設計模式單例模式的 實現,來看看MySingleton.java類的實現,這個類提供了一個請求佇列和圖片載入:

private static MySingleton mInstance;
    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;
    private static Context mCtx;
     
    private MySingleton(Context context){
        mCtx = context;
        mRequestQueue = getRequestQueue();
         
        mImageLoader = new ImageLoader(mRequestQueue,n
              new ImageLoader.ImageCache(){
                  private final LruCache<String,Bitmap>(20)
                      cache = new LruCache<String,Bitmap>(20);
                     
                   @Override
                   public Bitmap getBitmap(String url){
                       return cache.get(url);                   
                   }
                   @Override
                   public void putBitmap(String url,Bitmap bitmap){
                       cache.put(url,bitmap);
                   }
              });
    }
 
//非同步獲取單例項
public static synchronized MySingleton getInstance(Context context){
    if(mInstance == null){
        mInstance = new MySingleton(context);
    }
    return mInstance
}
 
public RequestQueue getRuquestQueue(){
    if(mRequestQueue == null){
        //getApplication()方法返回一個當前程序的全域性應用上下文,這就意味著
        //它的使用情景為:你需要一個生命週期獨立於當前上下文的全域性上下文,
        //即就是它的存活時間繫結在程序中而不是當前某個組建。
        mRequestQueue = Volley.newRequestQueue(mCtx.getApplication());
    }
    return mRequestQueue;
}
 
public <T> void addToRequestQueue(Request<T>req){
    getRequestQueue.add(req);
}
 
public ImageLoader getImageLoader(){
    return mImageLoader;
}

在上面的程式碼中,構造方法中封裝了請求佇列和圖片載入,接著就是非同步獲取例項、獲取請求佇列、把請求新增到請求佇列、獲取圖片載入。

最後我們使用這個單例類執行請求佇列操作:

//獲取請求佇列
RequestQueue queue = MySingleton.getInstance(this.getApplication().
        getRequest();
.......
//把請求(在這個例子中請求為StringRequest)新增到請求佇列
MySingleton.getInstance(this).addToRequestQueue(StringRequest);

Volley二次封裝

產品中使用Volley框架已有多時,本身已有良好封裝的Volley確實給程式開發帶來了很多便利與快捷。但隨著產品功能的不斷增加,伺服器介面的不斷複雜化,直接使用Volley原生的JSONObjectRequest已經導致Activity或Fragment層中耦合了大量的資料解析程式碼,同時當多處呼叫同一介面時,類似的資料解析程式碼還不可複用,導致大量重複程式碼的出現,已經讓我越發地無法忍受。基於此,最近思考著對Volley原生的JSONObjectRequest(因為產品中目前和伺服器互動所有的介面,資料都是json格式的)進行二次封裝,把Activity和Fragment中大量的資料解析程式碼剝離出來,同時實現資料解析程式碼的複用。

為了把問題表現出來,先上一段坑爹的程式碼。

</pre><pre class="java" name="code">package com.backup;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.json.JSONException;
import org.json.JSONObject;

import com.amuro.volleytest01_image.R;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;

public class TestActivity02 extends Activity
{
    private RequestQueue mQueue;
    private ListView listView;
    private List<Map<String, String>> list = new ArrayList<Map<String,String>>();
    
    String url = "http://10.24.4.196:8081/weather.html";
    
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test02_layout);
        listView = (ListView)findViewById(R.id.lv_test02);
        mQueue = Volley.newRequestQueue(this);
        getWeatherInfo();
        
        SimpleAdapter simpleAdapter = new SimpleAdapter(this, list,   
                        android.R.layout.simple_list_item_2, new String[] {"title","content"},   
                       new int[] {android.R.id.text1, android.R.id.text2});              
                  
        listView.setAdapter(simpleAdapter);  

        listView.setOnItemClickListener(new OnItemClickListener()
        {

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id)
            {
                TextView tv = (TextView)view.findViewById(android.R.id.text1);
                tv.setText("111111111111111111");
            }
        });
    }
    
    public void getWeatherInfo()
    {
        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null,

        new Response.Listener<JSONObject>()
        {

            @SuppressWarnings("unchecked")
            @Override
            public void onResponse(JSONObject jsonObject)
            {
                list.clear();
                Iterator<String> it = jsonObject.keys();
                while (it.hasNext())
                {
                    String key = it.next();
                    JSONObject obj = null;
                    try
                    {
                        obj = jsonObject.getJSONObject(key);
                    }
                    catch (JSONException e)
                    {
                        e.printStackTrace();
                    }
                    if (obj != null)
                    {
                        Iterator<String> objIt = obj.keys();
                        while (objIt.hasNext())
                        {
                            String objKey = objIt.next();
                            String objValue;
                            try
                            {
                                objValue = obj.getString(objKey);
                                HashMap<String, String> map = new HashMap<String, String>();
                                map.put("title", objKey);
                                map.put("content", objValue);
                                list.add(map);
                            }
                            catch (JSONException e)
                            {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        },

        new Response.ErrorListener()
        {
            @Override
            public void onErrorResponse(VolleyError arg0)
            {
            }
        });

        mQueue.add(jsonObjectRequest);
    }
}

上面的程式碼大家可以看到,複雜的json解析程式碼全部寫在Activity裡,現在如果又來一個Activity需要呼叫這個介面,這些解析json的程式碼是完全無法複用的,這不科學

下面開始分析:
1. 面向物件,對於Activity這層來說,它要的只是拿到資料進行展示,至於資料怎麼變出來的,它不應該關注,所以第一件事,對資料進行封裝,每個介面返回的最終資料,不應該是一個未經解析的jsonObject,而應該是一個bean,千千萬萬的bean最終可通過泛型來統一,so,我們先需要一個監聽器,讓我們封裝後的Volley層直接把bean回撥給Activity。
2. 對錯誤的處理,從目前的產品需求來看,上層Activity就是要對不同的錯誤展示不同的介面或跳轉不同的介面,所以我們把錯誤統一為errorCode和errorMessage,在底層封裝好後,直接拋給Activity。所以這樣一個返回bean或者error的介面就出來了。

package com.amuro.volley_framwork.network_helper;

public interface UIDataListener<T>
{
    public void onDataChanged(T data);
    public void onErrorHappened(String errorCode, String errorMessage);
}

3. 好,監聽器剝離了Activity與我們的Volley層,下面我們就要自己對Volley的JsonObjectRequest進行封裝了,先貼這個類:

package com.amuro.volley_framwork.network_request;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;

import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.json.JSONObject;

import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;
import com.android.volley.toolbox.JsonRequest;

public class NetworkRequest extends JsonRequest<JSONObject>
{
    private Priority mPriority = Priority.HIGH;
    
    public NetworkRequest(int method, String url,
            Map<String, String> postParams, Listener<JSONObject> listener,
            ErrorListener errorListener) 
    {
        super(method, url, paramstoString(postParams), listener, errorListener);
        setRetryPolicy(new DefaultRetryPolicy(30000, 0, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
    }

    public NetworkRequest(String url, List<NameValuePair> params,
            Listener<JSONObject> listener, ErrorListener errorListener) 
    {
        this(Method.GET, urlBuilder(url, params), null, listener, errorListener);
    }
    
    public NetworkRequest(String url, Listener<JSONObject> listener, ErrorListener errorListener) 
    {
        this(Method.GET, url, null, listener, errorListener);
    }
    
    private static String paramstoString(Map<String, String> params)
    {
        if (params != null && params.size() > 0)
        {
            String paramsEncoding = "UTF-8";
            StringBuilder encodedParams = new StringBuilder();
            try
            {
                for (Map.Entry<String, String> entry : params.entrySet())
                {
                    encodedParams.append(URLEncoder.encode(entry.getKey(),
                            paramsEncoding));
                    encodedParams.append('=');
                    encodedParams.append(URLEncoder.encode(entry.getValue(),
                            paramsEncoding));
                    encodedParams.append('&');
                    
                }
                return encodedParams.toString();
            }
            catch (UnsupportedEncodingException uee)
            {
                throw new RuntimeException("Encoding not supported: "
                        + paramsEncoding, uee);
            }
        }
        return null;
    }

    @Override
    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response)
    {
        
        try
        {

            JSONObject jsonObject = new JSONObject(new String(response.data, "UTF-8"));

            return Response.success(jsonObject,
                    HttpHeaderParser.parseCacheHeaders(response));

        }
        catch (Exception e)
        {

            return Response.error(new ParseError(e));

        }
    }

    @Override
    public Priority getPriority()
    {
        return mPriority;
    }

    public void setPriority(Priority priority)
    {
        mPriority = priority;
    }

    private static String urlBuilder(String url, List<NameValuePair> params) 
    {
        return url + "?" + URLEncodedUtils.format(params, "UTF-8");
    }
}

4. 接下來就是我們的重頭戲,寫一個Controller來操作這個request,同時對資料進行bean或error的封裝,這是一個抽象類,讓不同的子類根據不同的介面,趨實現不同的資料解析方式:

package com.amuro.volley_framwork.network_helper;

import java.util.List;
import java.util.Map;

import org.apache.http.NameValuePair;
import org.json.JSONObject;

import android.content.Context;
import android.util.Log;

import com.amuro.volley_framwork.network_request.NetworkRequest;
import com.amuro.volley_framwork.volley_queue_controller.VolleyQueueController;
import com.android.volley.Request.Method;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.VolleyError;

public abstract class NetworkHelper<T> implements Response.Listener<JSONObject>, ErrorListener
{
    private Context context;
    
    public NetworkHelper(Context context)
    {
        this.context = context;
    }
    
    protected Context getContext()
    {
        return context;
    }
    
    protected NetworkRequest getRequestForGet(String url, List<NameValuePair> params)
    {
        if(params == null)
        {
            return new NetworkRequest(url, this, this);
        }
        else
        {
            return new NetworkRequest(url, params, this, this);
        }
        
    }
    
    protected NetworkRequest getRequestForPost(String url, Map<String, String> params)
    {
        return new NetworkRequest(Method.POST, url, params, this, this);
    }
    
    public void sendGETRequest(String url, List<NameValuePair> params)
    {
        VolleyQueueController.getInstance().
            getRequestQueue(getContext()).add(getRequestForGet(url, params));
    }
    
    public void sendPostRequest(String url, Map<String, String> params)
    {
        VolleyQueueController.getInstance().
            getRequestQueue(context).add(getRequestForPost(url, params));
    }

    @Override
    public void onErrorResponse(VolleyError error)
    {
        Log.d("Amuro", error.getMessage());
        disposeVolleyError(error);
    }

    protected abstract void disposeVolleyError(VolleyError error);

    @Override
    public void onResponse(JSONObject response)
    {
        Log.d("Amuro", response.toString());
        disposeResponse(response);
    }

    protected abstract void disposeResponse(JSONObject response);

    private UIDataListener<T> uiDataListener;
    
    public void setUiDataListener(UIDataListener<T> uiDataListener)
    {
        this.uiDataListener = uiDataListener;
    }
    
    protected void notifyDataChanged(T data)
    {
        if(uiDataListener != null)
        {
            uiDataListener.onDataChanged(data);
        }
    }
    
    protected void notifyErrorHappened(String errorCode, String errorMessage)
    {
        if(uiDataListener != null)
        {
            uiDataListener.onErrorHappened(errorCode, errorMessage);
        }
    }
    
}
這裡對外直接提供了sendGetRequest方法和sendPostRequest方法,做為api就是要清晰明瞭,不要讓呼叫者去了解還有Method.GET這樣的東西,同時getRequestForGet方法和getRequestForPost方法把最常用的request直接封裝好,不需要子類再去寫new request的程式碼。當然為了拓展,這兩個方法是protected的,default的request不能符合要求的時候,子類就可直接覆蓋這兩個方法返回自己的request,而disposeResponse和disponseError兩個方法都為抽象方法,讓子類針對不同的介面,實現不同的功能。

5. 下面來個子類例項,一看就懂。
package com.amuro.controller.networkhelper;

import org.json.JSONObject;

import android.content.Context;

import com.amuro.bean.RRBean;
import com.amuro.utils.SystemParams;
import com.amuro.volley_framwork.network_helper.NetworkHelper;
import com.android.volley.VolleyError;

//{"errorCode":"0000","errorMessage":"成功","respMsg":"success","success":"true"}
public class ReverseRegisterNetworkHelper extends NetworkHelper<RRBean>
{
    

    public ReverseRegisterNetworkHelper(Context context)
    {
        super(context);
    }

    @Override
    protected void disposeVolleyError(VolleyError error)
    {
        notifyErrorHappened(
                SystemParams.VOLLEY_ERROR_CODE, 
                error == null ? "NULL" : error.getMessage());
    }

    @Override
    protected void disposeResponse(JSONObject response)
    {
        RRBean rrBean = null;
        
        if(response != null)
        {
            try
            {
                String errorCode = response.getString("errorCode");
                String errorMessage = response.getString("errorMessage");
                String respMsg = response.getString("respMsg");
                String success = response.getString("success");
                
                if("0000".equals(errorCode))
                {
                    rrBean = new RRBean();
                    rrBean.setErrorCode(errorCode);
                    rrBean.setErrorMessage(errorMessage);
                    rrBean.setRespMsg(respMsg);
                    rrBean.setSuccess(success);
                    
                    notifyDataChanged(rrBean);
                }
                else
                {
                    notifyErrorHappened(errorCode, errorMessage);
                }
            }
            catch(Exception e)
            {
                notifyErrorHappened(SystemParams.RESPONSE_FORMAT_ERROR, "Response format error");
            }
        }
        else
        {
            notifyErrorHappened(SystemParams.RESPONSE_IS_NULL, "Response is null!");
        }
    }
}
5. 大功告成,這個NetworkHelper封裝了資料解析的程式碼,完全可複用,最後看Activity
package com.amuro.ui;

import com.amuro.bean.RRBean;
import com.amuro.controller.networkhelper.ReverseRegisterNetworkHelper;
import com.amuro.utils.SystemParams;
import com.amuro.volley_framwork.network_helper.NetworkHelper;
import com.amuro.volley_framwork.network_helper.UIDataListener;
import com.amuro.volleytest01_image.R;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MyVolleyTestActivity extends Activity implements UIDataListener<RRBean>
{
    private Button button;
    
    private NetworkHelper<RRBean> networkHelper;
    
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_volley_test_layout);
        
        networkHelper = new ReverseRegisterNetworkHelper(this);
        networkHelper.setUiDataListener(this);
        
        button = (Button)findViewById(R.id.bt);
        button.setOnClickListener(new OnClickListener()
        {
            
            @Override
            public void onClick(View v)
            {
                sendRequest();
            }
        });
    }
    
    private void sendRequest()
    {
        networkHelper.sendGETRequest(SystemParams.TEST_URL, null);
    }

    @Override
    public void onDataChanged(RRBean data)
    {
        Toast.makeText(
                this, 
                data.getErrorCode() + ":" + 
                data.getErrorMessage() + ":" + 
                data.getRespMsg() + ":" + 
                data.getSuccess(), 
                Toast.LENGTH_SHORT).show();
        
    }

    @Override
    public void onErrorHappened(String errorCode, String errorMessage)
    {
        Toast.makeText(
                this, 
                errorCode + ":" + errorMessage, 
                Toast.LENGTH_SHORT).show();
        
    }
}
看,Activity直接拿到的就是資料或者errorCode,把一大堆複雜的資料解析程式碼剝離了







相關推薦

androidvolley通訊框架簡介

1. 什麼是Volley?        在這之前,我們在程式中需要和網路通訊的時候,大體使用的東西莫過於AsyncTaskLoader,HttpURLConnection,AsyncTask,HTTPClient(Apache)等,在2013年Google I/O 上,Volley釋出了。Volley是A

AndroidVolley通訊框架

首先使用Volley類建立 RequestQueue queue = Volley.newRequestQueue(this);  Making GET Requests <span style="font-size:14px;">final String url = "http://httpb

Android使用開源框架EventBus3.0實現Fragment之間的通訊互動

1.概述 在之前的博文中簡單介紹過如何實現fragment之間的資訊互動:《Android中Fragment與Activity之間的互動(兩種實現方式)》,今天繼續給大家介紹一種可以實現此效果的另外一種方式EventBus。(相比於handler,介面回撥,bundle傳參

AndroidVolley框架Get,POST封裝使用及自動解析JSON

  DEMO下載地址:http://download.csdn.net/detail/song2810106/9471616 網路請求使用的Volley.Jar.Json解析使用的谷歌的Gson,此封裝可以 重複呼叫 一個網路請求,並可以自動解析JSON為一個物件,我們都知

Android 進階 教你打造 Android 的 IOC 框架 【ViewInject】 (下)

本篇部落格將帶大家實現View的事件的注入。 1、目標效果 上篇部落格,我們的事件的程式碼是這麼寫的: package com.zhy.zhy_xutils_test; import android.app.Activity; import android.os.Bund

AndroidHttps通訊實現_ 單向認證

客戶端與服務端單向認證即是在客戶端的網路請求和webview中設定信任所有證書,然後在與服務端進行Https網路通訊的時候,客戶端不必進行證書校驗也能進行網路通訊,否則就會報證書不受信異常。 缺陷:容易受到中間人攻擊。 概覽 TrustManager和Hos

AndroidHttps通訊實現_瞭解Https

概覽 什麼是Https Https和Http的區別 Https證書 什麼是Https HTTPS(全稱:Hypertext Transfer Protocol over Secure Socket Layer),是以安全為目標的HTTP通道,簡單講是

android使用OkHttp框架處理網路請求

OkHttp網路處理框架,分成下面幾個使用過程: 1.Get: 同步Get private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception {

AndroidHttps通訊實現_中間人攻擊、DNS欺騙和會話劫持

上一篇文章記述了在Android中使用Https進行單向認證的配置,但單向認證存在中嚴重的安全漏洞,其中最容易受到中間人攻擊和DNS欺騙以及會話劫持,本文主要講述進行中間人攻擊、DNS欺騙和會話劫持的方式。 概覽 什麼是中間人攻擊 模擬中間人攻擊

AndroidSocket通訊的簡單實現

前言Android Framework 層程式碼中大量使用了 Binder IPC 通訊方式,除此之外,Socket 也是一種重要的 IPC 通訊方式,比如StorageManagerService(8.0 之前叫 MountService)與 Vold 之前的通訊,Syst

Android圖片載入框架Picasso的使用

技術要點 基本顯示(非同步載入,圖片壓縮,圖片快取) 載入中和載入錯誤的圖片顯示 設定圖片尺寸(Resize)、縮放(Scale)和裁剪(Crop) 圖片旋轉 設定轉換器 取消預設的記憶體快取 設定快取指示器 請求優先順序設定 圖片還未加載出來時取消

Android熱修復框架Robust原理解析+並將框架程式碼從"閉源"變成"開源"(上篇)

一、前言Android中熱修復框架比較多,每家公司都有對應的方案和框架,比如阿里的AndFix框架,關於這個框架在之前的文章已經詳細講解了,不瞭解的同學可以點選這裡:AndFix熱修復框架原理分析 。本

Android使用IOC框架讓程式碼更清爽

 控制反轉(Inversion of Control,英文縮寫為IoC)是一個重要的面向對角程式設計的法則來削減計算機程式的耦合問題,也是輕量級的Spring框架的核心。 控制反轉一般分為兩種型別,依賴注入(Dependency Injection,簡稱DI)和依賴查詢

Android 網路通訊框架Volley簡介(Google IO 2013)

1. 什麼是Volley在這之前,我們在程式中需要和網路通訊的時候,大體使用的東西莫過於AsyncTaskLoader,HttpURLConnection,AsyncTask,HTTPClient(Apache)等,今年的Google I/O 2013上,Volley釋出了。

Android基於HTTP的通訊技術(5)Google開源庫 使用 Volley 實現 JSON 字串請求

使用 Volley 實現 JSON 字串請求,通過極少的程式碼以及更方便理解的引數完成通訊。 (來自極客學院的學習筆記,我是搬運工- -)   Volley是谷歌開發android平臺的網路通訊庫:更

Android 谷歌 開源 通訊框架 VOLLEY(六)——應用例項

五、應用例項 package com.example.test; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.vo

Android 谷歌 開源 通訊框架 VOLLEY(一)

  HTTP 是應用層協議,TCP 是傳輸層協議(位於應用層之下)。   一般來說,移動應用推薦使用 HTTP 協議,有很多優點:   1. HTTP 發展成熟   HTTP 幾乎已經快成為一種通用的 Web 標準,Web Services、Open AP

Android 網路通訊框架Volley完全解析(一)

Volley簡介及Request基本用法  Google I/O 2013上,Volley釋出了。Volley是Android平臺上的網路通訊庫,能使網路通訊更快,更簡單,更健壯。這是Volley名

Android 網路框架Volley的用法

Volley是在Google I/O 2013上釋出的一框網路通訊http模組,新版本的Android已經廢除了HttpClient的使用,目前主流的android網路通訊庫有:Async-Http、NoHttp、xUtil等。本文就自己學習了Volley一些相

android Volley網路通訊框架學習

1. 什麼是Volley 在這之前,我們在程式中需要和網路通訊的時候,大體使用的東西莫過於AsyncTaskLoader,HttpURLConnection,AsyncTask,HTTPClient(Apache)等,Google I/O 2013上,Volley釋出了。Vo