android开发游记:封装http请求,快速实现网络加载

http请求在每个需要网络访问的应用中都是必须的,每次请求中都会 去new一个 HttpRequest,重复的写Handlder的callBack回调却是一件很麻烦的事情,有些页面的请求情况较多的话,往往会使得代码变得很冗长且不易于维护,这样,我们就有必要封装一下了。

我们使用一个统一处理过程,比如请求开始时做什么,结束时做什么,失败时做什么… 把这个过程放在一个类中CommonNet,在类中初始化一个HttpRequest(我使用了XUtil框架所以使用的是HttpUtils,这并不影响流程,换成自己熟悉的请求工具类就可以了),并定义一个send方法来发送请求:

/**
 * 网络请求执行过程,app中所有的网络请求都有通过此类执行访问,主要方法是send方法
 * @author Administrator
 *
 */
public class CommonNet {

    NetHander hander;
    HttpUtils http = new HttpUtils();

    public CommonNet(NetHander hander) {
        super();
        this.hander = hander;
    }
    public void send(...){
        ...
        //这个方法比较长,后面再解释
    }
}

可能你已经注意到了构造函数的必须参数NetHander了,这是一个接口,定义了请求过程中的所有回调,发送请求的类必须实现这个接口:

/**
 * 需要发送请求的Activity都需要实现此类的回调方法
 * @author Administrator
 *
 */
public interface NetHander {

    void netGo(int code,Object pojo,Object obj);

    void netStart(int code);

    void netEnd(int code);

    void netSetFalse(int code,int status,String text);

    void netSetFail(int code,int errorCode,String text);

    void netSetError(int code,String text);

    void netException(int code,String text);
}

最常用的,比如是在Activity发生http请求,那么先初始化一个CommonNet,然后用Activity来实现这个接口:

public class CenterActivity extends Activity implements NetHander{

    private CommonNet net = new CommonNet(this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_center);
    }

    @Override
    public void netGo(int code, Object pojo, Object obj) {
    }

    @Override
    public void netStart(int code) {
    }

    @Override
    public void netEnd(int code) {
    }

    @Override
    public void netSetFalse(int code,int status,String text) {
    }

    @Override
    public void netSetFail(int code, int errorCode, String text) {
    }

    @Override
    public void netSetError(int code, String text) {
    }

    @Override
    public void netException(int code, String text) {
    }
}

然后再使用CommonNet发生请求就可以了,如何请求成功,那么会回调netGo方法,比如我在onCreate中发送一个请求:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_center);

        RequestParams params = new RequestParams();
        params.addBodyParameter("param1", "hello");
        net.send(url, params, 1, CommonPojo.class,null);
    }

    @Override
    public void netGo(int code, Object pojo, Object obj) {
        Toast.makeText(this, "httpRequest Success!", Toast.LENGTH_SHORT).show();
    }

params 是参数的map集合,包含了所有的请求参数。
这样一个请求就发出去了,下面详细的说下上文忽略掉的send方法:

public void send(final String url,final RequestParams params,final int code,final Class entityClass,final Object obj)

先解释参数:

参数类型解释
urlStringhttp请求的请求地址
paramsRequestParamshttp请求的请求参数的map集合
codeint请求标志(标示这个请求的编号)
entityClassClass请求返回的实体对象(用于自动封装实体类)
objObject附加的参数(不进行任何处理,直接传给回调方法,供开发者使用)

前2个参数就不解释了,大家都懂的,注意解释下后面3个参数的意义和作用

code:

我们使用CommonNet来发生请求的话,请求的回调都在我们用来发送请求的类中(如上例子是Activity),不管发生多少种请求,在这个Activity中回调的都是同一套方法,这样我们在回调方法中就不清楚到底到底该处理哪一次请求的回调,所以我增加了一个code的参数,来给不同的请求编号,
比如:获取验证码的请求为1,登录的请求为2

    RequestParams params = new RequestParams();
    net.send(url1, params, 1, CommonPojo.class,null);

    RequestParams params = new RequestParams();
    params.addBodyParameter("username", "liaoinstan");
    params.addBodyParameter("password", "123456");
    net.send(url2, params, 2, CommonPojo.class,null);

回调:

    @Override
    public void netGo(int code, Object pojo, Object obj) {
    switch (code) {
        case 1:
            CommonPojo compojo = (CommonPojo)pojo;
            Toast.makeText(this, "验证码为:"+compojo.getVcode(), Toast.LENGTH_SHORT).show();
            break;
        case 2:
            Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
            break;
        }
    }

entityClass:

这个参数表示的是你请求的返回数据的实体类型,在CommonNet的send方法成功后可以进行实体类型的自动封装
比如返回的json数据格式是

{
    status:1, 
    message:"login success", 
    text:"登录成功"
}

那么你应该新建并传入一个这样的实体类:

public class MyPojo implements Serializable{
    private Integer status;
    private String text;
    private String message;

    //必须给出get set方法
    public Integer getStatus() {
        return status;
    }
    public void setStatus(Integer status) {
        this.status = status;
    }
    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
}

然后在netGo(int code, Object pojo, Object obj)返回给你,返回给你的是Object类型,需要进行强制转换成你需要的类型,如上的代码中,我传入的是CommonPojo类型,那么就强制转化成CommonPojo类型。

obj:

这个参数主要是为了方便用户传递参数而添加的,CommonNet中不会对它进行任何处理,例如:
我请求前传入一个参数hello:

    RequestParams params = new RequestParams();
    net.send(url1, params, 1, CommonPojo.class,"hello");

然后在回调中打印它:

    @Override
    public void netGo(int code, Object pojo, Object obj) {
        Toast.makeText(this, (String)obj, Toast.LENGTH_SHORT).show();
    }

不要问为啥不保存在外面,要在里面传递,我都说了是为了方便,你总会用得到的。

下面上CommonNet源码:

/**
 * 网络请求执行过程,app中所有的网络请求都有通过此类执行访问,主要方法是send方法
 * @author Administrator
 *
 */
public class CommonNet {

    NetHander hander;
    HttpUtils http = new HttpUtils();

    public CommonNet(NetHander hander) {
        super();
        this.hander = hander;
    }

    public void send(final String url,final RequestParams params,final int code,final Class entityClass,final Object obj) {
        http.send(HttpRequest.HttpMethod.POST,url, params,
        new RequestCallBack<String>() {

            @Override
            public void onStart() {
                LogUtils.d("start");
                LogUtils.d("url: " + url);
                hander.netStart(code);
            }

            @Override
            public void onLoading(long total, long current,boolean isUploading) {
                if (isUploading) {
                    LogUtils.d("upload: " + current + "/" + total);
                } else {
                    LogUtils.d("reply: " + current + "/" + total);
                }
            }

            @Override
            public void onSuccess(ResponseInfo<String> responseInfo) {
                try {
                    LogUtils.d("reply: " + responseInfo.result);

                    JSONTokener jsonParser = new JSONTokener(responseInfo.result);
                    JSONObject root;
                    Integer status = null;
                    String text = "";
                    try {
                        root = (JSONObject) jsonParser.nextValue();
                        if (root.has("status")) status = root.getInt("status");
                        if (root.has("text")) text = root.getString("text");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    Object pojo = new Gson().fromJson(responseInfo.result, entityClass);
                    System.out.println(pojo);

                    switch (status) {
                    case 1:
                        hander.netGo(code,pojo,obj);
                        break;
                    default:
                        break;
                    }
                    if (status<0) {
                        hander.netSetFalse(code,status,text);
                        hander.netSetError(code,text);
                    }
                    hander.netEnd(code);
                } catch (Exception e) {
                    e.printStackTrace();
                    hander.netException(code, "未知错误");
                }
            }

            @Override
            public void onFailure(HttpException error, String msg) {
                try {
                    LogUtils.d(error.getExceptionCode() + ":" + msg);
                    hander.netSetFail(code,error.getExceptionCode(),msg);
                    System.out.println(params);
                    if (error.getExceptionCode()==0) {
                        hander.netSetError(code,"网络不太好额~");
                    }else{
                        hander.netSetError(code,"服务器异常:"+error.getExceptionCode());
                    }
                    hander.netEnd(code);
                } catch (Exception e) {
                    e.printStackTrace();
                    hander.netException(code, "未知错误");
                }
            }
        });
    }
}

上面的请求执行过程可以自行根据需要修改,这里只是符合我的需求:

返回json数据必带status,为1表示成功,其他代表不同的失败情况

下面解释下几个回调方法的区别:

    //请求成功后回调
    void netGo(int code,Object pojo,Object obj);
    //请求开始后回调
    void netStart(int code);
    //请求结束后回调
    void netEnd(int code);
    //请求成功状态值返回非1后回调
    void netSetFalse(int code,int status,String text);
    //请求失败后回调
    void netSetFail(int code,int errorCode,String text);
    //请求失败或后请求成功状态值返回非1后回调
    void netSetError(int code,String text);
    //请求过程出现运行时异常后回调    
    void netException(int code,String text);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,了解了您的问题,下面是回答: 在Android中,ListView是一个常用的控件,用于显示一个垂直滚动的列表。而ArrayAdapter则是帮助ListView来显示数据的适配器。下面是实现显示游记内容的标题和时间等信息的步骤: 1. 在布局文件中添加ListView控件,并为ListView设置id,例如: ``` <ListView android:id="@+id/travel_notes_list" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 2. 在Activity或Fragment中,获取ListView控件的引用,并创建一个ArrayAdapter对象,例如: ``` ListView travelNotesList = findViewById(R.id.travel_notes_list); ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_2, android.R.id.text1, travelNotesTitles); ``` 其中,travelNotesTitles是一个包含游记标题的字符串数组。 3. 将ArrayAdapter设置为ListView的适配器,例如: ``` travelNotesList.setAdapter(adapter); ``` 这样就可以在ListView中显示游记标题了。 如果需要在ListView中显示更多的信息,例如游记时间、作者等,可以使用自定义布局来实现。具体步骤如下: 1. 创建一个自定义的布局文件,例如travel_notes_item.xml,其中可以添加游记标题、时间等信息的控件,例如: ``` <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/travel_notes_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="20sp" android:textStyle="bold" /> <TextView android:id="@+id/travel_notes_time" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="14sp" /> </LinearLayout> ``` 2. 在创建ArrayAdapter对象时,将自定义布局文件和需要显示的数据传递给构造函数,例如: ``` ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.travel_notes_item, R.id.travel_notes_title, travelNotesTitles) { @Override public View getView(int position, View convertView, ViewGroup parent) { View view = super.getView(position, convertView, parent); TextView travelNotesTime = view.findViewById(R.id.travel_notes_time); travelNotesTime.setText(travelNotesTimes[position]); return view; } }; ``` 其中,travelNotesTimes是一个包含游记时间的字符串数组,getView方法用于设置游记时间的显示。 3. 将ArrayAdapter设置为ListView的适配器,例如: ``` travelNotesList.setAdapter(adapter); ``` 这样就可以在ListView中显示游记标题和时间了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值