安卓网络请求框架,数据处理
网络请求框架——请求带token与错误拦截器
参考
1、Android中token的使用
2、Android 优雅地处理后台返回的骚数据
3、Android Retrofit网络请求框架
3个组合起来就可以完成
以1为主要框架,顺序:
配置依赖——mainfest设置权限
——创建网络拦截器——创建OkHttp工具类——创建接口管理器——编写请求接口——调用请求接口
配置依赖
看他的依赖
1、Android中token的使用
mainfest设置权限
创建网络拦截器
参考
1、Android中token的使用
2、Android 优雅地处理后台返回的骚数据
两个组合起来。
1.创建ResponseBodyInterceptor
《Android 优雅地处理后台返回的骚数据》的ResponseBodyInterceptor
ResponseBodyInterceptor——作为封装好的接口,拿到 source 再获得 buffer,然后通过 buffer 去读出字符串。
为了在此加上token,修改一点点:
参考《Android中token的使用》的token拦截器
BaseApplication
由于Interceptor没有getSharedPreferences的方法,需要得到SharedPreferences要有一个BaseApplication。
Application 作为整个 App 的一个单例对象,自定义一个BaseApplication并在AndroidMainfest.xml的application中增加android:name=".BaseApplication"即可
一个简单的BaseApplication:
public class BaseApplication extends Application {
/*
* 返回application
* */
public static BaseApplication getApplication(){
return application;
}
/*
* 返回context
* */
public static Context getContext() {
return context;
}
/*
* 对于一个应用来说 android入口并不是Activity中的OnCreate()而是Application里面的Oncreate()
* 也就相当于是java中的Main方法,只不过这个方法被封装了
* */
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
//在Application创建时,读取Application
application=this;
context = getApplicationContext();
}
}
2.创建HandleErrorInterceptor
HandleErrorInterceptor继承RequestBodyInterceptor
《Android 优雅地处理后台返回的骚数据》的HandleErrorInterceptor
重写的intercept方法为得到返回的数据要进行的统一操作。
如:处理token异常的情况
public class HandleErrorInterceptor extends RequestBodyInterceptor {
@Override
Response intercept(@NonNull Response response, String url, String body) {
JsonElement je = new JsonParser().parse(body);
//返回的body不为null
if(je!=null){
int code = je.getAsJsonObject().get("code").getAsInt();
//token异常情况,去登录 以后台接口返回的数据为准
if(code==0){
String msg = je.getAsJsonObject().get("msg").getAsString();
Looper.prepare();
Toast.makeText(BaseApplication.getContext(), msg, Toast.LENGTH_SHORT).show();
Looper.loop();
//跳转登录界面操作
ARouter.getInstance().build(Constants_ARouterURL.CHOOSEUSERTYPEPATH).navigation();
}
}
return response;
}
}
拦截器跳转登录页面
Android 使用拦截器判断token过期后跳转登录界面的两种方式
ARouter之基本使用
创建OkHttp工具类
OkHttp工具类用来得到OkHttpClient,使用前面配置的HandleErrorInterceptor拦截器
《Android中token的使用》的看他的OkHttp工具类
创建接口管理器
《Android Retrofit网络请求框架》的的接口管理器ApiServiceManager和UrlConfig
举例:出现需要请求两个不同的后台的情况
编写请求接口
《Android Retrofit网络请求框架》的创建网络请求的接口写的很清晰
调用请求接口
《Android Retrofit网络请求框架》的请求网络写的很清晰
异步请求
异步请求时需要创建一个Callback实例并重写方法如图
每个请求都要创建一个Callback实例并重写两个方法太麻烦,则在此创建一个AllApiCallBack继承Callback,重写onFailure和onResponse方法,并创建一个抽象方法action,里面实现返回数据成功且code=1时才能进行的操作。
则异步请求时只需要创建一个AllApiCallBack并重写action方法即可。
效果:网络请求失败、返回的数据code!=1的情况:出现弹窗提示。
弹窗
自定义弹窗参考,写的很详细
Android让dialog充满整个屏幕
AllApiCallBack
由于弹窗需要context参数,因此在AllApiCallBack的构造器也需要加上context来获得上下文
public abstract class AllApiCallBack implements Callback<ResponseBody>{
private PromptDialog errorDialog;
private Context context;
public AllApiCallBack(Context context) {
this.context = context;
}
/**
* 需要重写的方法,返回code=1后的操作放在此
* @param jsonObject
*/
abstract public void action(JSONObject jsonObject);
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response.body()==null){
showErrorDialog("异常","请求成功没有数据,请确认接口是否正确!");
}else {
String res=null;
try {
res=new String(response.body().bytes());
JSONObject jsonObject= JSON.parseObject(res);
if(Long.parseLong(jsonObject.get("code").toString())==1) {
//成功的操作
action(jsonObject);
} else {
//返回失败原因
showErrorDialog("错误",jsonObject.get("msg").toString());
}
}catch (IOException e){
showErrorDialog("异常","接口返回数据读取异常!");
}
}
}
/**
* 重写发出api请求失败的情况,抛出弹窗
* @param call
* @param t
*/
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
showErrorDialog("异常","网络请求异常!");
}
public void showErrorDialog(String title,String content ){
errorDialog=new PromptDialog(context, title, content, "确定",new View.OnClickListener() {
@Override
public void onClick(View v) {
errorDialog.dismiss();
}
});
errorDialog.setCanotBackPress();
errorDialog.setCanceledOnTouchOutside(false);
errorDialog.show();
}
}
以上的JSONObject是使用Alibaba Fastjson
Alibaba Fastjson使用教程
进行网络请求举例
参考
Android—ViewModel实现Fragment跨页面数据共享
竟然如此简单,DataBinding 和 ViewBinding
LiveData开发文档
在ViewModel中发起网络请求得到数据并使用setValue修改数据
public class MyViewModel extends ViewModel {
private MutableLiveData<List<ListItem>> List;
private ApiService apiService;
public MyViewModel() {
List = new MutableLiveData<>();
apiService = ApiServiceManager.get().getBusinessRetrofit().create(ApiService.class);
}
//用于绑定数据
public LiveData<List<ListItem>> ListBind() {
if(List==null)
List = new MutableLiveData<>();
return List;
}
//发起请求修改数据
public void getList(String input,Long id,Long atime,Long btime, Context context){
Call<ResponseBody> list = apiService.getList(input,null,id,atime,btime);
list.enqueue(new AllApiCallBack(context) {
@Override
public void action(JSONObject jsonObject) {
//得到可见的列表其中个数为0时,置空
if(Integer.parseInt(jsonObject.getJSONObject("msg").get("count").toString())==0){
List.setValue(null);
}
else {
List<ListItem> ListItems =
JSONArray.parseArray(jsonObject.getJSONObject("msg").get("data").toString(), ListItem.class);
List.setValue(ListItems);
}
}
});
}
}
在fragment展示数据
//list绑定
myViewModel.ListBind().observe(getViewLifecycleOwner(), new Observer<List<ListItem>>() {
@Override
public void onChanged(List<ListItem> listItems) {
if(listItems==null){
//返回的list是空
binding.List.setAdapter(null);
}else {
ListAdapter=new ListAdapter(getContext(),R.layout.list_item,listItems);
binding.List.setAdapter(ListAdapter);
binding.List.setOnItemClickListener(new AdapterView.OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
ListItem ListItem = ListItems.get(i);
//list项目点击事件
Log.e("TAG", ListItem.getName());
}
});
}
}
});
//获取数据
myViewModel.getList(input,id,startTime,endTime,getContext());
ListView
自定义适配器参考
高度设置参考
美化ListView参考1
美化ListView参考2
后台json返回的数据:
{
"code": 1,
"msg": {
"data": [
{
"id": 102,
"name": "衡水1",
"phone": "19222222222",
"status": 1
},
{
"id": 103,
"name": "秦始皇",
"phone": "14444444444",
"status": 1
},
{
"id": 104,
"name": "印证1",
"phone": "15555555555",
"status": 1
},
{
"id": 105,
"name": "三月份",
"phone": "16666666666",
"status": 1
},
{
"id": 107,
"name": "eva",
"phone": "18106968235",
"status": 0
},
{
"id": 108,
"name": "eve",
"phone": "18106968234",
"status": 1
},
],
"count": 6
}
}
效果: