代码不全,但尽可能详细的讲解了主要实现步骤,希望能对各位看官有所帮助!
步骤:
一、准备一个RecyclerView列表用于展示数据
二、找到对应的API接口并根据Json格式构造用于解析的Gson类
三、创建ViewModel类承担数据操作的责任
四、将解析好的数据放入RecyclerView中
一、准备一个RecyclerView列表用于展示数据
- 在闭包中加入相应的依赖库
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "androidx.recyclerview:recyclerview-selection:1.1.0-rc03"
-
在对应的xml文件中加入RecyclerView控件
<androidx.recyclerview.widget.RecyclerView android:id="@+id/news_recyc" android:layout_width="match_parent" android:layout_height="match_parent"/>
-
为列表中的子项创建一个xml布局页面,再建立一个类存放展示所需的字段
-
接下来要为RecyclerView准备一个适配器,新建NewAdapter类继承自RecyclerView.Adapter,重写和加载参数相关的方法,onCreateViewHolder()、onBindViewHolder ()和getItemCount()这三个方法。NewAdapter的泛型数据类型是自定义的ViewHolder。NewAdapter中有一个构造函数,把要展示的数据源传进来,并赋值给一个全局变量,作为数据源。后续操作都在数据源的基础上进行。
-
onCreateViewHolder()用于创建ViewHolder实例。加载news_item布局,创建ViewHolder实例,并把加载出来的布局传入到构造函数中,最后将ViewHolder的实例返回。
public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) { //加载item布局 final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.new_item, parent, false); //创建ViewHolder实例 final ViewHolder holder = new ViewHolder(view); //未来:实现下面两个页面跳转到仓库主页的activity holder.newView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int position = holder.getAdapterPosition(); News news= newsList.get(position); Toast.makeText(v.getContext(), "you will see repo ", Toast.LENGTH_SHORT).show(); } }); //未来:实现下面两个点击事件跳转到个人主页的activity holder.userImage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int position = holder.getAdapterPosition(); News news= newsList.get(position); Toast.makeText(v.getContext(), "you will see profile of " + news.getUserName(), Toast.LENGTH_SHORT).show(); } }); holder.userName.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int position = holder.getAdapterPosition(); News news= newsList.get(position); Toast.makeText(v.getContext(), "you will see profile of " + news.getUserName(), Toast.LENGTH_SHORT).show(); } }); return holder; }
-
onBindViewHolder ()用于对RecyclerView子项的数据进行赋值。我们通过position参数得到当前项的News实例。
public void onBindViewHolder(final ViewHolder holder, int position) { final News news = newsList.get(position); holder.userName.setText(news.getUserName()); holder.time.setText(news.getTime()); holder.action.setText(news.getAction()); }
-
getItemCount()统计子项个数,返回数据源的长度。
public int getItemCount() { return newsList.size(); }
二、找到对应的API接口并根据Json格式构造用于解析的Gson类
-
通过GraphQL找到想找的API,复制到postman里生成请求代码。获取到的请求代码我把它放到了一个函数里,以便调用和修改。
public static String getUserNews() { return "{\"query\":\"query MyQuery {\\r\\n viewer {\\r\\n following(first: 10) {\\r\\n edges {\\r\\n node {\\r\\n avatarUrl(size: 10)\\r\\n login\\r\\n starredRepositories {\\r\\n edges {\\r\\n starredAt\\r\\n }\\r\\n nodes {\\r\\n nameWithOwner\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n}\",\"variables\":{}}"; }
-
通过OkHttp发起HTTP请求,建立网络连接
发起HTTP请求,需要创建一个Request对象。可以在最终的bulid方法前连缀很多方法来丰富Request对象,比如指定服务器返回数据格式为json,将上一步得到的请求代码放入body中。
-
调用OkHttpClient的newCall(request)来创建一个call对象,重写onFailure和onResponse方法。
//构造请求 Request.Builder builder = BaseRequestBuilder.getBuilder(); MediaType mediaType = MediaType.parse("application/json"); //Json代码 RequestBody body = RequestBody.create(mediaType, RequestBodyHelper.getUserNews()); //构建请求 Request request = builder.method("POST", body).build(); OkHttpClient client = OkhttpUtil.getInstance(); //请求数据 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { doFailure(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { Log.d("tag", "List数组创建成功"); doSuccess(response); } }); //服务器返回的数据 String data = response.body().string();
-
通过Gson方法解析服务器返回的JSON数据
-
先在闭包中添加依赖项
implementation 'com.google.code.gson:gson:2.8.6'
-
再用Gson反序列化服务器返回的数据。我获取的数据是一个List数组。先对返回来的数据进行字符串处理,<u>确保待解析的字符串是完整的[XXXXXX]</u>。这里说明一下,{}代表里面的代码块是一个类,[]代表里面的代码块是一个数组。根据在GraphQL中看到的Json格式,从内往外的去定义相应的类和数组,层层嵌套,确保变量命名和Json数据中名字一致。这里用简单的例子举例说明一下吧。
//String data = response.body().string();服务器返回的数据 String userJson = " [{'isDeveloper':false,'name':'xiaoqiang','age':26,'email':'578570174@qq.com'}, {'isDeveloper':true,'name':'xiaoqiang123','age':27,'email':'578570174@gmail.com' }]"; Gson gson = new Gson(); Type userListType = new TypeToken<ArrayList<User>>(){}.getType(); List<User> userList = gson.fromJson(userJson, userListType); //这个List将为后续操作的数据源
对于 List ,反序列化时必须提供它的Type,通过 Gson 提供的 TypeToken<T>.getType() 方法可以定 义当前List的 Type 。这个Type应为服务器返回数据的最外层所定义的类。
-
三、创建ViewModel类承担数据操作的责任
ViewModel的生命周期比Activity和Fragment都要长,用ViewModel存储数据不用担心数据保存和恢复的问题。再者UI controller 比如 Activity 、Fragment 是设计用来渲染展示数据、响应用户行为、处理系统的某些交互。如果再要求他去负责加载网络或数据库数据,会让其显得臃肿和难以管理。所以为了简洁、清爽、 丝滑,我们可以分离出数据操作的职责给 ViewModel。下面来看看怎么用ViewModel管理数据。
-
创建一个NewsViewModel继承自ViewModel,并在构造函数中初始化了数据源,虽然Google为防止内存泄漏禁止在 ViewModel 中持有 Context 或 activity 或 view 的引用,但是为了在ViewModel里操作UI线程,我从外部传了个Context进来。
private MutableLiveData<ArrayList<News>> Listdata; List<News> newList = new ArrayList<>(); Context newsContext; public NewsViewModel() { Listdata = new MutableLiveData<>(); initNewList(); } public LiveData<ArrayList<News>> getList() { return Listdata; } private void initNewList(){//上文通过API获取数据源,在doSuccess中完成了数据解析,并调用了setListValue()将数据装入ViewModel的Listdata中 } public void setContext(Context context) { newsContext = context; } public void setListValue() { ((MainActivity) newsContext).runOnUiThread(new Runnable() { @Override public void run() { Listdata.setValue((ArrayList<News>) newList); } }); }
-
在UI控制器里(Fragment或Activity)生成一个ViewModel对象。通过对象调用getList()就可以获取数据源进行操作了。
newsViewModel= new ViewModelProvider(this).get(NewsViewModel.class);
四、将解析好的数据放入RecyclerView中
-
先把RecyclerView与布局页绑定(我的RecyclerView是放在fragment里的)
View root = inflater.inflate(R.layout.fragment_news, container, false); final RecyclerView newsRecyclView = root.findViewById(R.id.news_recyc); LinearLayoutManager layoutManager = new LinearLayoutManager(this.getActivity()); newsRecyclView.setLayoutManager(layoutManager);
-
之前已经加载了item的布局页到适配器中,因此需要将适配器与newsRecyclView进行绑定
//ViewModel里用于刷新UI的观察者,getList()获取到数据后则在这个方法中显示在UI上 newsViewModel.getList().observe(getViewLifecycleOwner(), new Observer<ArrayList<News>>() { @Override public void onChanged(@Nullable ArrayList<News> s) { //将数据传入适配器,将适配器绑定到RecyclerView NewAdapter adapter=new NewAdapter(s); newsRecyclView.setAdapter(adapter); //负责页面刷新效果的代码 progressBar.setVisibility(View.GONE); newsRecyclView.setVisibility(View.VISIBLE); } });