最近需要实现一个答题功能,参考网上很多方法都是ViewPage实现的,出于各种原因我并不是很想用ViewPage
于是决定研究怎么用RecyclerView实现
但是踩了各种坑,大概也知道为什么几乎没有用RecyclerView实现的了。。。。
需求是这样的:有一套题目,每个题目固定5个选项,但是选项分值可能不同,我的选项只有两种情况:
1、A到E 分值1到5
2、A到E 分值5到1
出于偷懒,我把选项分值存储这一步化简了,直接把题目分值类型设定一个正向/逆向
这样每次读取通过正向/逆向去判断这题的分值如何计算
然后比如说现在有这样一套题目(以下是自己写的web端展示效果)
现在我要给它展示到APP上面,并且能算分出来
我用RecyclerView时,一开始很天真的把算分写在adapter当中,结果,怎么算都算不对!而且一样的答案,返回再提交可能会出现不一样的结果,打了log之后我发现,原因是RecyclerView是根据页面的加载项来加载题目的,比如说当前我有8题,但是手机第一页面大小只够显示4题,那只有这4题被加载了,后面的是没有被加载的。当屏幕滑动,下面的题目会被加载
但是如果上下滑动,上下题目就会重复加载,导致了加载多少,分数就积累了多少。
于是我给单选组设置了点击监听,将分值回传出来
rg_main.setOnCheckedChangeListener(
new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (myItemChangeCheckView != null) {
myItemChangeCheckView.onItemChangeClick(getLayoutPosition());
Problem problem = item.get(getLayoutPosition());
if(problem.getAnswerType().equals("正向")) {
if(radioButton1.isChecked()){
x = 1;
} else if(radioButton2.isChecked()){
x = 2;
} else if(radioButton3.isChecked()){
x = 3;
} else if(radioButton4.isChecked()){
x = 4;
} else if(radioButton5.isChecked()){
x = 5;
}
} else {
if(radioButton1.isChecked()){
x = 5;
} else if(radioButton2.isChecked()){
x = 4;
} else if(radioButton3.isChecked()){
x = 3;
} else if(radioButton4.isChecked()){
x = 2;
} else if(radioButton5.isChecked()){
x = 1;
}
}
//这里我把x的值回传出来
setAa(x);
Log.e("TAG", "change x:"+x);
}
}
});
调用的时候
adapter.setMyItemChangeCheckView(new ProblemAdapter.checkChangeOnClickView() {
@Override
public void onItemChangeClick(int position) {
// integers.get(position) = adapter.getX();
//通过位置找对应题目的位置,替换分值
integers.set(position, adapter.getX());
}
});
但是这样就有一个问题,我打的日志,明明每次选择后x值的是对的,但是到几分的时候,它被替换成了0
经过一番断点之后,我发现程序是先执行get方法,adapter当中的set方法,所以它会先获取默认值,被选中后更改的值并没有取到。
最后经过一番修改。。。我把调用时,和adapter当中的值通过一个数组传递,获取题目时,首先要根据默认值来构建这个数组(因为如果没有滑动就提交,程序只加载显示的那几题)
然后把这个数组y传入到adaper当中
更改题目被选中的项目时,由adapter来修改这个数组对应的值
提交时把adapter的数组回传出来,通过递归计算总分,问题解决~~
下面是完整代码:
ProblemAdapter
package com.swl.food.adapter;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.swl.food.R;
import com.swl.food.bean.Influence;
import com.swl.food.bean.ProType;
import com.swl.food.bean.Problem;
import java.util.ArrayList;
/*
* @Author:Swallow
* @Date:2020/3/21
* 展示文章信息的RecyclerView的适配器
*/
public class ProblemAdapter extends RecyclerView.Adapter<ProblemAdapter.ViewHoledr> {
private static checkChangeOnClickView myItemChangeCheckView;
private static ArrayList<Problem> item;
private Context context;
private ArrayList<Integer> integers;
//设置点击监听
private static ProblemAdapter.ArticleItemOnClickView myItemOnClickView;
public static int x = 0;
public static int aa = 0;
public static int[] y;
public static int[] getY() {
return y;
}
public static void setY(int[] y) {
ProblemAdapter.y = y;
}
public int getAa() {
Log.e("TAG getAa", "aa:"+aa);
return aa;
}
public static void setAa(int aa) {
Log.e("TAG setAa", "aa:" + aa);
ProblemAdapter.aa = aa;
}
public interface ArticleItemOnClickView{
public void onItemClick(int position);
}
public interface checkChangeOnClickView{
public void onItemChangeClick(int position);
}
public static void setMyItemOnClickView(ProblemAdapter.ArticleItemOnClickView myItemOnClickView) {
ProblemAdapter.myItemOnClickView = myItemOnClickView;
}
public static void setMyItemChangeCheckView(ProblemAdapter.checkChangeOnClickView myItemChangeCheckView) {
ProblemAdapter.myItemChangeCheckView = myItemChangeCheckView;
}
public ProblemAdapter(ArrayList<Problem> item, Context context) {
if(item == null) {
item = new ArrayList<>();
}
Log.e("TAG----->>","初始化适配器"+item.size());
this.item = item;
this.context = context;
integers = new ArrayList<>();
}
static class ViewHoledr extends RecyclerView.ViewHolder{
TextView tv_item;
RadioGroup rg_main;
RadioButton radioButton1, radioButton2, radioButton3, radioButton4, radioButton5;
public ViewHoledr(@NonNull final View itemView) {
super(itemView);
tv_item = itemView.findViewById(R.id.tv_item);
radioButton1 = itemView.findViewById(R.id.radioButton1);
radioButton2 = itemView.findViewById(R.id.radioButton2);
radioButton3 = itemView.findViewById(R.id.radioButton3);
radioButton4 = itemView.findViewById(R.id.radioButton4);
radioButton5 = itemView.findViewById(R.id.radioButton5);
rg_main = itemView.findViewById(R.id.rg_main);
rg_main.setOnCheckedChangeListener(
new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (myItemChangeCheckView != null) {
myItemChangeCheckView.onItemChangeClick(getLayoutPosition());
Problem problem = item.get(getLayoutPosition());
if(problem.getAnswerType().equals("正向")) {
if(radioButton1.isChecked()){
x = 1;
} else if(radioButton2.isChecked()){
x = 2;
} else if(radioButton3.isChecked()){
x = 3;
} else if(radioButton4.isChecked()){
x = 4;
} else if(radioButton5.isChecked()){
x = 5;
}
} else {
if(radioButton1.isChecked()){
x = 5;
} else if(radioButton2.isChecked()){
x = 4;
} else if(radioButton3.isChecked()){
x = 3;
} else if(radioButton4.isChecked()){
x = 2;
} else if(radioButton5.isChecked()){
x = 1;
}
}
setAa(x);
Log.e("TAG", "change x:"+x);
int[] p = getY();
p[getLayoutPosition()] = x;
setY(p);
}
}
});
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (myItemOnClickView != null) {
myItemOnClickView.onItemClick(getLayoutPosition());
}
}
});
}
}
@NonNull
@Override
public ProblemAdapter.ViewHoledr onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(context).inflate(R.layout.list_problems,null);
return new ProblemAdapter.ViewHoledr(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHoledr viewHoledr, int i) {
Problem problem = item.get(i);
String n = problem.getContext();
viewHoledr.tv_item.setText(n);
}
@Override
public int getItemCount() {
if(item == null) {
item = new ArrayList<>();
System.out.println("item.size():"+item.size());
return 0;
}
System.out.println("item.size():"+item.size());
return item.size();
}
public int getNum(){
int num = 0;
for (Integer integer : integers){
num += integer;
Log.e("TAG getNum------>", integer+" ");
}
return num;
}
public static int getX() {
return x;
}
public static void setX(int x) {
ProblemAdapter.x = x;
}
}
调用的类 TestActivity
package com.swl.food;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.RadioButton;
import android.widget.TextView;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.swl.food.adapter.MyArticleAdapter;
import com.swl.food.adapter.ProblemAdapter;
import com.swl.food.adapter.TestAdapter;
import com.swl.food.base.MyConstant;
import com.swl.food.bean.Food;
import com.swl.food.bean.ProType;
import com.swl.food.bean.Problem;
import com.swl.food.utils.DestroyActivityUtil;
import com.swl.food.utils.JsonUtils;
import com.swl.food.utils.OkHttpUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class TestActivity extends Activity implements View.OnClickListener {
private RecyclerView rv_main;
private TextView tv_title;
private ImageButton ib_back;
private ArrayList<Problem> problemArrayList;
private ProblemAdapter adapter;
private Button btn_save;
private Integer typeId;
private ArrayList<Integer> integers;
private int[] use;
private LinearLayoutManager linearLayoutManager;
private Handler handler = new Handler(){
public void handleMessage(Message msg){
switch (msg.what){
//题目内容从服务端获取json数组
case MyConstant.COM_SUCCESS:
JSONObject jsonObject = JSONObject.parseObject((String) msg.obj);
JSONArray jsonArray = JSON.parseArray(jsonObject.getString("item"));
problemArrayList = new ArrayList<>();
for(int i = 0; i < jsonArray.size(); i++) {
JSONObject json = jsonArray.getJSONObject(i);
// RescueTeam team = JSONObject.parseObject(jsonObject.toJSONString(), RescueTeam.class);
Problem problem = JSONObject.parseObject(json.toJSONString(), Problem.class);
problemArrayList.add(problem);
}
use = new int[problemArrayList.size()];
for (int i = 0; i < problemArrayList.size(); i++) {
Problem problem = problemArrayList.get(i);
//根据类型先构造默认分值数组
if(problem.getAnswerType().equals("正向")){
use[i] = 1;
integers.add(1);
} else {
use[i] = 5;
integers.add(5);
}
Log.e("TAG", "change cc y:"+integers.get(i));
}
adapter.setY(use);
adapter = new ProblemAdapter(problemArrayList,TestActivity.this);
adapter.setMyItemChangeCheckView(new ProblemAdapter.checkChangeOnClickView() {
@Override
public void onItemChangeClick(int position) {
// integers.get(position) = adapter.getX();
// integers.set(position, adapter.getX());
use[position] = adapter.getAa();
}
});
rv_main.setLayoutManager(linearLayoutManager);
rv_main.setAdapter(adapter);
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
initView();
integers = new ArrayList<>();
typeId = getIntent().getIntExtra("typeId", 0);
data(typeId);
}
private void data(final int typeId) {
new Thread(){
public void run(){
Message message = handler.obtainMessage();
Map<String,Object> map = new HashMap<>();
map.put("typeId",typeId);
String result = null;
try {
result = OkHttpUtil.sendGet(MyConstant.QUERY_TEST_PRO, map);
Boolean success = JsonUtils.JsonSuccess(result);
if(success) {
//请求成功发送用户数据
message.what = MyConstant.COM_SUCCESS;
message.obj = result;
handler.sendMessage(message);
}else {
//请求失败发送失败信息
String msg = JSONObject.parseObject(result).getString("msg");
message.what = MyConstant.NET_ERROR;
message.obj = msg;
handler.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
private void initView() {
linearLayoutManager = new LinearLayoutManager(TestActivity.this);
rv_main = findViewById(R.id.rv_main);
tv_title = findViewById(R.id.tv_title);
tv_title.setVisibility(View.GONE);
// tv_title.setText("类别选择");
ib_back = findViewById(R.id.ib_back);
ib_back.setOnClickListener(this);
btn_save = findViewById(R.id.btn_save);
btn_save.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_save:
int sum = 0;
for (Integer integer : adapter.getY()) {
Log.e("TAG", " adapter.y:"+ integer);
sum += integer;
}
// int sum = adapter.getNum();
Log.e("TAG NUM------>", sum+"");
//转换计算百分制分值
double x = (double)((double)sum/ (double) (problemArrayList.size()*5))*100;
toPage(typeId,x);
break;
case R.id.ib_back :
finish();
break;
}
}
private void toPage(Integer id,Double num) {
Intent intent = new Intent(this, TestResultActivity.class);
intent.putExtra("typeId",id);
intent.putExtra("num",num);
DestroyActivityUtil.addDestoryActivityToMap(TestActivity.this,"TestActivity");
startActivity(intent);
}
public static RecyclerView.ViewHolder getHolder(RecyclerView rv, int index){
int count = rv.getAdapter().getItemCount();
if((index < 0 || index > count -1)) {
return null;
}
RecyclerView.ViewHolder holder = rv.findViewHolderForAdapterPosition(index);
if(holder == null) {
RecyclerView.RecycledViewPool pool = rv.getRecycledViewPool();
int rvCount = pool.getRecycledViewCount(0);
holder = pool.getRecycledView(0);
try {
pool.putRecycledView(holder);
} catch (Exception e) {
e.printStackTrace();
}
}
return holder;
}
}
JSON数组
{
"item": [{
"id": 1,
"typeId": 9,
"type": null,
"context": "您精力充沛吗?",
"answerType": "正向"
}, {
"id": 2,
"typeId": 9,
"type": null,
"context": "您容易疲乏吗?",
"answerType": "逆向"
}, {
"id": 3,
"typeId": 9,
"type": null,
"context": "您说话声音低弱无力吗?",
"answerType": "逆向"
}, {
"id": 4,
"typeId": 9,
"type": null,
"context": "您感到闷闷不乐、情绪低沉吗?",
"answerType": "逆向"
}, {
"id": 5,
"typeId": 9,
"type": null,
"context": "您比一般人耐受不了寒冷(冬天的寒冷,夏天的冷空调、电扇等)吗?",
"answerType": "逆向"
}, {
"id": 6,
"typeId": 9,
"type": null,
"context": "您能适应外界自然和社会环境的变化吗?",
"answerType": "正向"
}, {
"id": 7,
"typeId": 9,
"type": null,
"context": "您容易失眠吗?",
"answerType": "逆向"
}, {
"id": 8,
"typeId": 9,
"type": null,
"context": "您容易忘事(健忘)吗?",
"answerType": "逆向"
}],
"success": true
}
这个BUG改了花了一些时间,几个小时,感觉办法有点土,后续有空还会继续优化
欢迎有更优办法的同学交流讨论。