如何使用 Android RecyclerView 以表格形式显示数据?
RecyclerView 是作为 GridView 和 ListView 的继承者添加到 android studio 中的 ViewGroup。这是对两者的改进,可以在最新的 v-7 支持包中找到。它的创建是为了可以将任何具有 XML 布局的列表构建为可以大量定制的项目,同时提高 ListViews 和 GridViews 的效率。这种改进是通过回收用户不可见的视图来实现的。例如,如果用户向下滚动到项目 4 和 5 可见的位置;项目 1、2 和 3 将从内存中清除以减少内存消耗。不仅如此,Recycler View 还可以用于以表格的形式显示大量数据。就像电子表格一样,我们可以创建一个高度可定制的表格结构来填充其中的数据。在本文中,我们将了解如何构建这样的表格结构并从数据库中填充数据。在本例中,我们使用的是 Firebase 数据库,但您可以使用任何数据库。所以请按照以下步骤,让我们开始吧。
分步实施
第 1 步:创建一个新项目
要在 Android Studio 中创建新项目,请参阅如何在 Android Studio 中创建/启动新项目。请注意,选择Java作为编程语言。
第 2 步:创建模型类
创建一个名为 Model 的新类,它将保存用户输入的各种数据。在这种情况下,我们存储字符串数据用户名和其他三个整数数据正确、尝试、时间。此数据代表测验竞赛结果。下面是实现正确模型类的代码。为了创建模型类,我们声明私有类变量并生成它们的 getter 和 setter 以及类的构造函数。
Java
public class Record {
// Create private data variables
private String attempted;
private String correct;
private String time;
private String name;
// generate getters and setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAttempted() {
return attempted;
}
public void setAttempted(String attempted) {
this.attempted = attempted;
}
public String getCorrect() {
return correct;
}
public void setCorrect(String correct) {
this.correct = correct;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
XML
XML
Java
mport android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class MyViewHolder extends RecyclerView.ViewHolder {
// data variables to link with
// the respective id from the view
TextView name, attempted, correct, time;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.userName);
attempted = itemView.findViewById(R.id.attempted);
correct = itemView.findViewById(R.id.correct);
time = itemView.findViewById(R.id.time);
}
}
Java
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
// Extends the Adapter class to RecyclerView.Adapter
// and implement the unimplemented methods
public class RecordAdapter extends RecyclerView.Adapter {
Context context;
ArrayList list;
// constructor with Record's data model list and view context
public RecordAdapter(Context context, ArrayList list) {
this.context = context;
this.list = list;
}
// Binding data to the
// into specified position
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// inflate the recycler view
// layout in its view component
View v = LayoutInflater.from(context).inflate(R.layout.record_info,parent,false);
return new MyViewHolder(v);
}
// holder method to set respective
// data to their components
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Record user = list.get(position);
holder.name.setText(user.getName());
holder.attempted.setText(user.getAttempted());
holder.correct.setText(user.getCorrect());
holder.time.setText(user.getTime());
}
// method to return the
// position of the item
@Override
public int getItemCount() {
return list.size();
}
}
Java
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.ArrayList;
import java.util.Objects;
public class RecordActivity extends AppCompatActivity {
private ImageView back, profileImage;
private DatabaseReference databaseReference;
private RecyclerView recyclerView;
private RecordAdapter myAdapter;
// Using ArrayList to Record data
private ArrayList list;
private int flag = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_record);
getRecord();
}
private void getRecord() {
// Getting reference of recyclerView
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
// Setting the layout as linear
// layout for vertical orientation
recyclerView.setLayoutManager(new LinearLayoutManager(this));
list = new ArrayList<>();
myAdapter = new RecordAdapter(this,list);
// Setting Adapter to RecyclerView
recyclerView.setAdapter(myAdapter);
// get firebase instance for the desired key location
databaseReference = FirebaseDatabase.getInstance().getReference();
databaseReference.child("User").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
if(flag==0) {
for (DataSnapshot ds : snapshot.getChildren()) {
for (DataSnapshot dss : ds.getChildren()) {
if (Objects.equals(dss.getKey(), "Total")) {
// adding record data to the list
Record user = dss.getValue(Record.class);
list.add(user);
}
}
}
// notifying adapter class about the change
myAdapter.notifyDataSetChanged();
flag=1;
}
progressBar.dismiss();
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
@Override
public void onBackPressed() {
startActivity(new Intent(getApplicationContext(), MainActivity.class));
super.onBackPressed();
}
}
第 3 步:使用 activity_main.xml 文件
XML 代码用于构建活动的结构及其样式部分。在这个 XML 文件中,我们将创建一个水平方向的 LinearLayout。这将包含四个 ImageView 表示 Record 类数据模型实体的各种数据列的图标。下面我们将创建一个RecyclerView来填充数据。下面是 activity_main.xml 文件的代码。
XML
第 4 步:创建 RecyclerView 项目布局
在下一步中,我们将创建一个项目布局,它将保存每个 RecyclerView 项目的数据。在这个布局中,会有四个不同 id 属性的 TextView 视图。
XML
第 5 步:使用 ViewHolder
在此,我们将为我们的数据模型类创建一个视图持有者。视图持有者用于描述元数据及其在回收站视图中的位置。在这里,我们将使用视图持有者来放置模型类变量的数据,这些变量是名称、尝试、正确、时间。下面是 ViewHolder 的代码。
Java
mport android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class MyViewHolder extends RecyclerView.ViewHolder {
// data variables to link with
// the respective id from the view
TextView name, attempted, correct, time;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.userName);
attempted = itemView.findViewById(R.id.attempted);
correct = itemView.findViewById(R.id.correct);
time = itemView.findViewById(R.id.time);
}
}
第 6 步:处理适配器类
适配器是负责 RecyclerView 的主要代码。它包含处理 RecyclerView 实现的所有重要方法。成功实施的基本方法是:
- onCreateViewHolder:将卡片布局的膨胀处理为 RecyclerView 的一个项目。
- onBindViewHolder:处理RecyclerView的特定item点击相关的不同数据和方法的设置。
- getItemCount:返回 RecyclerView 的长度。
- onAttachedToRecyclerView:将适配器附加到 RecyclerView。
Java
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
// Extends the Adapter class to RecyclerView.Adapter
// and implement the unimplemented methods
public class RecordAdapter extends RecyclerView.Adapter {
Context context;
ArrayList list;
// constructor with Record's data model list and view context
public RecordAdapter(Context context, ArrayList list) {
this.context = context;
this.list = list;
}
// Binding data to the
// into specified position
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// inflate the recycler view
// layout in its view component
View v = LayoutInflater.from(context).inflate(R.layout.record_info,parent,false);
return new MyViewHolder(v);
}
// holder method to set respective
// data to their components
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Record user = list.get(position);
holder.name.setText(user.getName());
holder.attempted.setText(user.getAttempted());
holder.correct.setText(user.getCorrect());
holder.time.setText(user.getTime());
}
// method to return the
// position of the item
@Override
public int getItemCount() {
return list.size();
}
}
第 7 步:处理 RecordActivity 类
在这个类中,我们为 RecyclerView、Adapter Class、ViewHolder 创建实例。这里我们使用 Firebase 数据库来存储数据并对其进行请求调用,您可以使用任何其他数据库。
- 创建适配器、视图持有者、回收者视图、数据库引用的对象。
- 创建 Record 类的 Object 类型的 ArrayList。
- 请求数据并将其存储在数组列表中。
- 通知适配器列表中的更改。
Java
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.ArrayList;
import java.util.Objects;
public class RecordActivity extends AppCompatActivity {
private ImageView back, profileImage;
private DatabaseReference databaseReference;
private RecyclerView recyclerView;
private RecordAdapter myAdapter;
// Using ArrayList to Record data
private ArrayList list;
private int flag = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_record);
getRecord();
}
private void getRecord() {
// Getting reference of recyclerView
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
// Setting the layout as linear
// layout for vertical orientation
recyclerView.setLayoutManager(new LinearLayoutManager(this));
list = new ArrayList<>();
myAdapter = new RecordAdapter(this,list);
// Setting Adapter to RecyclerView
recyclerView.setAdapter(myAdapter);
// get firebase instance for the desired key location
databaseReference = FirebaseDatabase.getInstance().getReference();
databaseReference.child("User").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
if(flag==0) {
for (DataSnapshot ds : snapshot.getChildren()) {
for (DataSnapshot dss : ds.getChildren()) {
if (Objects.equals(dss.getKey(), "Total")) {
// adding record data to the list
Record user = dss.getValue(Record.class);
list.add(user);
}
}
}
// notifying adapter class about the change
myAdapter.notifyDataSetChanged();
flag=1;
}
progressBar.dismiss();
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
@Override
public void onBackPressed() {
startActivity(new Intent(getApplicationContext(), MainActivity.class));
super.onBackPressed();
}
}
输出:
要记住的事情:
- 模型类应具有特定顺序的所需数据变量。
- 视图持有者应膨胀回收器视图以填充数据。
- 要对特定行进行 onClick 调用,请使用 onItemCount 方法。