【Android】安卓实现网络请求,得到数据并显示于listview,包含token与拦截器

网络请求框架——请求带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
	}
}

效果:
在这里插入图片描述

  • 6
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值