欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

上门洗车APP --- Android客户端开发 之 网络框架封装介绍(一),appandroid,本项目采用的通讯框架是

来源: 开发者 投稿于  被查看 32215 次 评论:233

上门洗车APP --- Android客户端开发 之 网络框架封装介绍(一),appandroid,本项目采用的通讯框架是


上篇文章中给大家简单介绍了一些业务,上门洗车APP --- Android客户端开发 前言及业务简介,本篇文章给大家介绍下网络框架,之前也了解过一些开源网络通讯架构,也大概看了一部分源码,比如Afinal、Volley、AndBase、Android-async-http等,感觉各自都有各自的优劣,自己也曾封装过一些简单的网络架构,感觉有很多地方需要注意和优化,这里就不贴出来献丑了,感兴趣的朋友可以去查阅学习上面所说的那些开源项目,也可以查看之前整理的博客:Android开源框架(整理)进行相关学习,这里不过多介绍了。


本项目采用的通讯框架是 Android-async-http,之前也写过一篇文章对其进行简单的介绍过,android-async-http开源项目介绍及使用方法,大家可以简单的了解下,本项目中基于该架构对数据的请求访问及数据结果的返回做了一系列的封装。


这里分享下我的思路和想法,和大家共同学习。对于发出的网络请求可以这样理解,Request --->  包括(请求时,请求中,请求成功,请求失败,请求结束),而服务器响应成功后取到数据,对数据结果进行解析,存储等处理,基本的框架都是这样,个人觉得此处不够完善,总感觉返回请求数据的地方可以再次处理,进一步进行优化,那该怎么样呢?


我是这样想的,发出请求后,获取的数据希望是已经解析完成的数据,而不是从返回结果中再去解析,也就是说,请求完成后已经将数据结果Result进行了解析,返回的Result已经是可直接使用的对象。这样的话,整个请求解析就方便多了。


那么到底效果如何呢?我们来看如下的一个登录请求例子:

private void login(String name,String pwd){
		GenericDataManager mDataManager = GenericDataManager.getInstance();//通用网络管理类
		RequestParams mParams = RequestParameterFactory.getInstance().login(name, pwd);//请求参数管理类
		mDataManager.dataRequest(0,Constants.REQUEST.GET, RequestURL.URL_LOGIN, mParams,new ResultParser(), this);//执行网络请求
	}

只需要 3行代码 便可发起一个请求,那么具体在 Activity 中如何使用呢?我们向外抛了一个IRequestCallback 请求响应回调接口,该接口提供了三个回调方法,供 Activity 实现即:

/**
 * IRequestCallback of Washer
 * 请求响应回调接口
 * @author gao_chun
 */
public interface IRequestCallback {

    public void onRequestStart(int requestId);//开始请求

    public void onRequestSuccess(int requestId,int statusCode,Result<?> result);//请求成功,返回请求Id,状态响应码,数据结果(解析后的数据对象)

    public void onRequestError(int requestId,Throwable error);//请求错误

}

注:requestId 即请求 id,目的是为了区分哪一个请求,比如:一个 Activity 中需要有两次或更多次的请求,如何在回调中区分具体的哪一个请求呢?使用 requestId 区分便可。

只需要在 Activity 中实现该接口,实现具体方法,便可得到数据:

/*******************************************************************************
 *
 * Copyright (c) Weaver Info Tech Co. Ltd
 *
 * LoginActivity
 *
 * app.ui.activity.LoginActivity.java
 * TODO: File description or class description.
 *
 * @author: gao_chun
 * @since:  2015-6-23
 * @version: 1.0.0
 *
 * @changeLogs:
 *     1.0.0: First created this class.
 *
 ******************************************************************************/
package org.gaochun.activity;

/**
 * @author gao_chun
 *
 */
public class LoginActivity extends TitleActivity implements IRequestCallback{

	public Context context;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		context = this;
		initUI();

	}

	private void initUI() {
		setContentView(R.layout.activity_login);
		setTitle(R.string.text_login);
	}


	@Override
	public void onRequestStart(int requestId) {//onRequestStart
		//此处可以显示Dialog
	}

	@Override
	public void onRequestSuccess(int requestId, int statusCode, Result<?> result) {	//onRequestSuccess

		Log.i(TAG,result.getMessage()+"--"+result.getStatus()+"--"+result.getData());//数据打印

	}

	
	@Override
	public void onRequestError(int requestId, Throwable error) {		//onRequestError

		Log.e(TAG,error.getMessage());//请求失败,错误信息打印

	}

}

有没有感觉还是挺简便的赶脚?说了那么多,下面我们来进一步配合代码进行了解。


之前博文介绍过,使用该框架两种方式:

第一种 是将 releases 包中的最新jar拷贝到应用的 libs 目录下

第二种 是将 library 里的项目源码拷贝到你应用的 src 目录下(这里采用的是第二种方式)

以下是AsyncHttpClient简单用法,即创建一个请求

AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
    @Override
    public void onSuccess(String response) {
        System.out.println(response);
    }
});

注:该框架可执行多种网络请求,包括 getputpostheaddelete 。有关不同请求的介绍,大家不了解的可以去查阅资料了解相关差异,这里就不介绍了。


我们就是对 AsyncHttpClient类进行了处理,上面执行请求时有出现这两行代码:

GenericDataManager mDataManager = GenericDataManager.getInstance();//通用网络管理类

mDataManager.dataRequest(0,Constants.REQUEST.GET, RequestURL.URL_LOGIN, mParams,new ResultParser(), this);//执行网络请求

GenericDataManager是什么玩意呢?


这个类是封装的一个通用数据请求类,下面给出这个类,结合注释大家可以了解学习:

/*******************************************************************************
 *
 * Copyright (c) Weaver Info Tech Co. Ltd
 *
 * DataManager
 *
 * app.backend.manager.DataManager.java
 * 用来访问服务器上的数据
 *
 * @author: gao_chun
 * @since:  Jul 23, 2014
 * @version: 1.0.0
 *
 * @changeLogs:
 *     1.0.0: First created this class.
 *
 ******************************************************************************/
package org.gaochun.android.http.manager;

import java.io.File;

import org.apache.http.Header;
import org.gaochun.android.http.AsyncHttpClient;
import org.gaochun.android.http.RequestParams;
import org.gaochun.android.http.network.IRequestCallback;
import org.gaochun.android.http.network.RequestCallBack;
import org.gaochun.model.Result;
import org.gaochun.parser.AbstractParser;
import org.gaochun.utils.Log;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;


/**
 * @author gao_chun
 * 通用数据通讯类,不涉及认证与授权的数据。
 * 这个类的任务:通过相应参数,获取数据对象。
 * 这个类不会涉及到URL地址。
 */
public class GenericDataManager {

    private static final String TAG = GenericDataManager.class.getSimpleName();

    private static GenericDataManager sInstance;
    private final String mServerHost;	//服务器地址前缀
    private final Handler mHandler;		//执行异步回调的Handler

    private static AsyncHttpClient client;	//AsyncHttpClient对象


    // 设置超时时间
    static{
        client = new AsyncHttpClient();   //初始化AsyncHttpClient对象
        client.setTimeout(6 * 1000);     //设置超时时间(重要)
    }


    //单例
    public synchronized static GenericDataManager getInstance() {
        if (sInstance == null) {
            Log.e(TAG, "ConfigManager.initiate method not called in the application.");
        } // else ignored.
        return sInstance;
    }

    //需要在Application中初始化
    public static void initialize(Context applicationContext, String serverHost) {
        sInstance = new GenericDataManager(applicationContext, serverHost);
    }


    private GenericDataManager(Context applicationContext, String serverHost) {

        // 初始化Handler,用于在主线程中执行任务
        mHandler = new Handler(Looper.getMainLooper());
        // 初始化服务器地址
        mServerHost = serverHost;
    }



    /**
     * 该方法封装了网络数据请求和数据解析
     * 并传入回调接口
     * @param requestId     请求ID
     * @param requestType   请求类型(此处根据传入的常量只提供了get请求和post请求)
     * @param urlString     请求URL
     * @param mParams       请求参数
     * @param parser        通用数据解析抽象解析器
     * @param mCallback     自定义接口回调
     */

    private RequestCallBack mRequestCallBack;	//该抽象类继承了AsyncHttpResponseHandler,并重写了回调方法


    public <T> void dataRequest(final int requestId,String requestType,String urlString,RequestParams mParams,
            final AbstractParser<T> mParser,final IRequestCallback mCallback){

        Log.i(TAG,"url:--->"+mServerHost + File.separator + urlString);

        //请求数据开始之前的回调
        if (mCallback != null) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mCallback.onRequestStart(requestId);
                }
            });
        } // else ignored


        //实例化回调对象
        mRequestCallBack = new RequestCallBack() {

            @Override
            public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {

                String data = new String(responseBody);	//获取数据结果
                //Log.d(TAG,"服务器获取数据:"+data);
                final Result<T> result = mParser.parse(data);	//解析类
                if (result != null) {
                    //return the requestId + statusCode + result
                    mCallback.onRequestSuccess(requestId,statusCode,result);	//返回请求成功且解析完成的数据回调
                } // else ignored.
            }

            @Override
            public void onStart() {
                if (mCallback != null) {
                    mCallback.onRequestStart(requestId);
                } // else ignored
            }

            @Override
            public void onFailure(int statusCode, Header[] headers,
                    byte[] responseBody, Throwable error) {

                if (mCallback != null) {
                    mCallback.onRequestError(requestId,error);
                } // else ignored
            }
        };

        //根据传入的 requestType 来switch具体的请求方式(注:JDK1.7中switch()支持字符串常量)
        switch (requestType) {
            case Constants.REQUEST.GET:
                client.get(mServerHost + File.separator + urlString, mParams,mRequestCallBack);
                break;

            case Constants.REQUEST.POST:
                client.post(mServerHost + File.separator + urlString, mParams,mRequestCallBack);
                break;

            default:
                client.get(mServerHost + File.separator + urlString, mParams,mRequestCallBack);
                break;
        }
    }

}

我们需要注意的是该方法中传入的参数,且使用了泛型 <T> :

/**
&nbsp; &nbsp; &nbsp;* 该方法封装了网络数据请求和数据解析
&nbsp; &nbsp; &nbsp;* 并传入回调接口
&nbsp; &nbsp; &nbsp;* @param requestId &nbsp; &nbsp; 请求ID
&nbsp; &nbsp; &nbsp;* @param requestType &nbsp; 请求类型(此处根据传入的常量只提供了get请求和post请求)
&nbsp; &nbsp; &nbsp;* @param urlString &nbsp; &nbsp; 请求URL
&nbsp; &nbsp; &nbsp;* @param mParams &nbsp; &nbsp; &nbsp; 请求参数
&nbsp; &nbsp; &nbsp;* @param parser &nbsp; &nbsp; &nbsp; &nbsp;通用数据解析抽象解析器
&nbsp; &nbsp; &nbsp;* @param mCallback &nbsp; &nbsp; 自定义接口回调
&nbsp; &nbsp; &nbsp;*/
public <T> void dataRequest(final int requestId,String requestType,String urlString,RequestParams mParams,
            final AbstractParser<T> mParser,final IRequestCallback mCallback)

将请求参数,请求类型,请求URL,解析器,回调,传入这个方法中进行处理,回调成功直接取数据

20150624104946751.png


如果项目中需要用到头像上传,下载 等功能,Android-async-http 项目中已经提供了对应的方法,大家可以自己在该类中封装方法。


忙里偷闲的挤时间整理了这篇文章,目的是先给大家简单的介绍框架的使用,让感兴趣的朋友有所了解,下篇博文中会给大家详细介绍dataRequest 中的抽象解析类 及 请求参数封装 RequestParameterFactory类,当然也需要整理好源码后给大家共享学习。


感谢大家的关注,如果觉得有需要改进的地方或者好的想法,欢迎大家发表意见。

作者:高纯

用户评论