Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Volley解析(二)之表單提交篇

Android Volley解析(二)之表單提交篇

編輯:關於Android編程

上一篇文章中,講了 Volley 的 get 和 post 請求,並且對 volley 的基本使用和基本分析做了講解,而這篇 blog 將講解用 volley 實現表單的提交

表單提交的數據格式

要實現表單的提交,就要知道表單提交的數據格式是怎麼樣,這裡我從某知名網站抓了一條數據,先來分析別人提交表單的數據格式。
數據包:

Connection: keep-alive
Content-Length: 123
X-Requested-With: ShockwaveFlash/16.0.0.296
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36
Content-Type: multipart/form-data; boundary=----------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
Cookie: bdshare_firstime=1409052493497

------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1
Content-Disposition: form-data; name="position"

1425264476444
------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1
Content-Disposition: form-data; name="editorIndex"

ue_con_1425264252856
------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1
Content-Disposition: form-data; name="cm"

100672
------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1--

看到上面的數據包,我們不需要全部分析,我們主要關心的是數據如何封裝,因為http請求頭,在網絡請求中已經為我們封裝好了;可以看到這裡總共是提交了三條數據,每一條數據的格式都是一樣的,所以我們只需要分析一條數據即可,這裡拿最後一條數據來說,因為在所有的數據之後還有一個結尾的標志。

------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1
Content-Disposition: form-data; name="cm"

100672
------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1--

這條數據一共有四行組成,加上結尾標志共有五行
1、第一行:

"--" + boundary + "\r\n" ;

說明:”–”為數據開始標志,boundary為http實體頭定義的邊界分割線,boundary可以是任意的字符串,只要和Content-Type: multipart/form-data; boundary=———-Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1中保持一直即可,”\r\n”為回車換行;
2、第二行:

"Content-Disposition: form-data; name="參數的名稱"" + "\r\n" ;

說明:Content-Disposition表示上傳的內容特性,form-data上傳內容特性為表單的形式;
3、第三行:

"\r\n" ;

4、說明:這是一個空行,只有一個回車換行 ;
第四行:

"參數的值" + "\r\n" ;

說明:每個參數都是由一個key和value組成,而這一行就是value跟回車換行符
結尾行:

"--" + boundary + "--" + "\r\n" ;

說明:在所有的數據結束之後,需要有這個結尾標志。
如果有多個參數,則重復1、2、3、4,直至最後一個參數的最後加上結尾行。

參數實體類

這裡對參數做一個封裝,因為往往提交表單的時候,都需要提交多個參數

/**
 * Created by gyzhong on 15/3/2.
 */
/*表單提交的參數*/
public class FormText {
    /*參數的名稱*/
    private String mName ;
    /*參數的值*/
    private String mValue ;

    public FormText(String mName, String mValue) {
        this.mName = mName;
        this.mValue = mValue;
    }

    public String getName() {
        return mName;
    }

    public String getValue() {
        return mValue;
    }

}

Volley 對數據的封裝

在上一篇文章中我們講了如何定制自己的 Request,在這裡同樣需要用到。在定制 Request 的時候,需要重寫獲取實體的方法

public byte[] getBody() throws AuthFailureError {}

把參數通過二進制的形式傳給服務器,當然就不需要重寫獲取參數的方法

protected Map getParams() throws AuthFailureError {}

最核心的方法也就在getBody()中,這個方法的實現,如果對表單提交的數據格式很了解,實現起來非常簡單,因為這個方法就是把參數拼接成我們所分析的數據格式;

    @Override
    public byte[] getBody() throws AuthFailureError {
        if (mListItem == null||mListItem.size() == 0){
            return super.getBody() ;
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream() ;
        int N = mListItem.size() ;
        FormText formText ;
        for (int i = 0; i < N ;i++){
            formText = mListItem.get(i) ;
            StringBuffer sb= new StringBuffer() ;
            /*第一行:"--" + boundary + "\r\n" ;*/
            sb.append("--"+BOUNDARY);
            sb.append("\r\n") ;
            /*第二行:"Content-Disposition: form-data; name="參數的名稱"" + "\r\n" ;*/
            sb.append("Content-Disposition: form-data;");
            sb.append("name=\"");
            sb.append(formText.getName()) ;
            sb.append("\"") ;
            sb.append("\r\n") ;
            /*第三行:"\r\n" ;*/
            sb.append("\r\n") ;
            /*第四行:"參數的值" + "\r\n" ;*/
            sb.append(formText.getValue()) ;
            sb.append("\r\n") ;
            try {
                bos.write(sb.toString().getBytes("utf-8"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        /*結尾行:"--" + boundary + "--" + "\r\n" ;*/
        String endLine = "--" + BOUNDARY + "--"+ "\r\n" ;
        try {
            bos.write(endLine.toString().getBytes("utf-8"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        Log.v("zgy","=====formText====\n"+bos.toString()) ;
        return bos.toByteArray();
    }

可以看到,這個方法的實現,就是對數據按照我們所分析的格式組裝。
在 Request 中還有一個關鍵的地方,需要在 http 頭部中聲明內容類型為表單數據

Content-Type: multipart/form-data; boundary=----------8888888888888

所以的重寫下面方法為

public String getBodyContentType() {
        return MULTIPART_FORM_DATA+"; boundary="+BOUNDARY;
    }

同樣,我們還是前面我們blog 中講到的接口http://www.minongbang.com/test.php?test=minongbang來測試,所以解析數據那一塊跟 前面我們將的一樣,具體實現如下:

/**
 * Created by gyzhong on 15/3/2.
 */
public class PostFormRequest<T> extends Request<T> {

    /**
     * 正確數據的時候回掉用
     */
    private ResponseListener mListener ;
    /*用來解析 json 用的*/
    private Gson mGson ;
    /*在用 gson 解析 json 數據的時候,需要用到這個參數*/
    private Type mClazz ;
    /*請求 數據通過參數的形式傳入*/
    private List mListItem ;

    private String BOUNDARY = "---------8888888888888"; //數據分隔線
    private String MULTIPART_FORM_DATA = "multipart/form-data";

    public PostFormRequest(String url, List listItem, Type type, ResponseListener listener) {
        super(Method.POST, url, listener);
        this.mListener = listener ;
        mGson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() ;
        mClazz = type ;
        setShouldCache(false);
        mListItem = listItem ;
    }

    /**
     * 這裡開始解析數據
     * @param response Response from the network
     * @return
     */
    @Override
    protected Response parseNetworkResponse(NetworkResponse response) {
        try {
            T result ;
            String jsonString =
                    new String(response.data, HttpHeaderParser.parseCharset(response.headers));
            Log.v("zgy", "====SearchResult===" + jsonString);
            result = mGson.fromJson(jsonString,mClazz) ;
            return Response.success(result,
                    HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        }
    }

    /**
     * 回調正確的數據
     * @param response The parsed response returned by
     */
    @Override
    protected void deliverResponse(T response) {
        mListener.onResponse(response);
    }

    @Override
    public byte[] getBody() throws AuthFailureError {
        if (mListItem == null||mListItem.size() == 0){
            return super.getBody() ;
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream() ;
        int N = mListItem.size() ;
        FormText formText ;
        for (int i = 0; i < N ;i++){
            formText = mListItem.get(i) ;
            StringBuffer sb= new StringBuffer() ;
            /*第一行:"--" + boundary + "\r\n" ;*/
            sb.append("--"+BOUNDARY);
            sb.append("\r\n") ;
            /*第二行:"Content-Disposition: form-data; name="參數的名稱"" + "\r\n" ;*/
            sb.append("Content-Disposition: form-data;");
            sb.append("name=\"");
            sb.append(formText.getName()) ;
            sb.append("\"") ;
            sb.append("\r\n") ;
            /*第三行:"\r\n" ;*/
            sb.append("\r\n") ;
            /*第四行:"參數的值" + "\r\n" ;*/
            sb.append(formText.getValue()) ;
            sb.append("\r\n") ;
            try {
                bos.write(sb.toString().getBytes("utf-8"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        /*結尾行:"--" + boundary + "--" + "\r\n" ;*/
        String endLine = "--" + BOUNDARY + "--"+ "\r\n" ;
        try {
            bos.write(endLine.toString().getBytes("utf-8"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        Log.v("zgy","=====formText====\n"+bos.toString()) ;
        return bos.toByteArray();
    }

    /*獲取內容類型,這裡為表單類型*/
    @Override
    public String getBodyContentType() {
        return MULTIPART_FORM_DATA+"; boundary="+BOUNDARY;
    }
}

表單提交接口

接口我們在上一篇博文中也做了比較詳細的講解,這裡就不累贅了。

    /**
     *  minong 測試post表單提交接口
     * @param  value 測試數據
     * @param listener 回調接口,包含錯誤回調和正確的數據回調
     */
    public static void postFormMiNongApi(String value,ResponseListener listener){
        List formTextList = new ArrayList() ;
        formTextList.add(new FormText(" test",value));
        Request request = new PostFormRequest(Constant.MiNonghost,formTextList,new TypeToken(){}.getType(),listener) ;
        VolleyUtil.getRequestQueue().add(request) ;
    }

測試

PostFormActivity.Java的測試代碼如下

public class PostFormActivity extends ActionBarActivity {

    private ListView mListView ;
    private SongAdapter mAdapter ;
    private List mSongList ;
    private ProgressDialog mDialog ;
    private View mHeaderView ;
    private TextView mShowPostData ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_post_form);
        mSongList = new ArrayList() ;
        mListView = (ListView) findViewById(R.id.id_list_view);
        mAdapter = new SongAdapter(this,mSongList) ;
        mHeaderView = getLayoutInflater().inflate(R.layout.list_header_item,null) ;
        mShowPostData = (TextView) mHeaderView.findViewById(R.id.id_post_data) ;
        mListView.addHeaderView(mHeaderView);
        mListView.setAdapter(mAdapter);
        mDialog = new ProgressDialog(this) ;
        mDialog.setMessage("數據提交中...");
        mDialog.show() ;
        /*請求網絡獲取數據*/
        MiNongApi.postFormMiNongApi(" minongbang",new DataResponseListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.v("zgy","======onErrorResponse====="+error);
                mDialog.dismiss();
            }

            @Override
            public void onResponse(SearchResult response) {
                Log.v("zgy","======onResponse====="+response);
                mSongList.addAll(response.getData().getInfo()) ;
                mAdapter.notifyDataSetChanged();
                mDialog.dismiss();
            }

            @Override
            public void postData(String data) {
                mShowPostData.setText(data);
            }
        });
    }

通過以上內容我們不難發現,表單提交就是把文本通過二進制的形式傳給服務器,從而得到對應的響應,這篇 blog 其實也算是一篇過度的文章,因為一般我們不會這麼提交文字數據,而是通過我們上一篇 blog 中的post 請求的方式,那什麼時候我們需要用到表單提交呢,當表單中含有附件,如圖片,視頻等文件的的時候

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved