Android recyclerview 没有显示任何数据
Android recyclerview does not show any data
我正在使用一个模板,我用 Retrofit 2 请求替换了占位符数据,该请求解析了 URL 中数据的 JSON 文件并将其放入对象列表中。我 运行 遇到了一个问题,我的改造调用首先被执行并且 returns items = 0,然后代码使用值 items=0 进一步执行并且在调试器中执行了相当多的步骤后,它返回到调用并显示正确的响应(items=12)但是 Adapter/RecycleView 操作似乎已经执行并且它们不使用迟到的解析数据.
MainActivity.java
public class MainActivity extends AppCompatActivity {
private View parent_view;
List<Task> items = new List<Task>() {...}
private RecyclerView recyclerView;
private AdapterTasks mAdapter;
private int animation_type = ItemAnimation.BOTTOM_UP;
@Override
protected void onCreate(Bundle savedInstanceState) {
items = DataGenerator.getTasksData();
items.addAll(DataGenerator.getTasksData());
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_animation);
parent_view = findViewById(android.R.id.content);
initComponent();
}
private void initComponent() {
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
animation_type = ItemAnimation.FADE_IN;
setAdapter();
}
private void setAdapter() {
//set data and list adapter
mAdapter = new AdapterTasks(this, items, animation_type);
recyclerView.setAdapter(mAdapter);
// on item list clicked
mAdapter.setOnItemClickListener(new AdapterTasks.OnItemClickListener() {
@Override
public void onItemClick(View view, Task obj, int position) {
//open task view
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_list_animation, menu);
return true;
}
改造请求
public static List<Task> getTasksData() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd HH:mm:ss")
.create();
Retrofit retrofit= new Retrofit.Builder()
.baseUrl("http://10.0.2.2/index.php/")
.addConverterFactory(GsonConverterFactory.create(gson))
.client(client)
.build();
TasksApi taskAPI =retrofit.create(TasksApi.class);
Call<List<Task>> call = taskAPI.getAllTasks();
call.enqueue(new Callback<List<Task>>() {
@Override
public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
items = response.body();
}
@Override
public void onFailure(Call<List<Task>> call, Throwable t) {
}
});
return items;
}
适配器
public class AdapterTasks extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Task> items;
private Context ctx;
private OnItemClickListener mOnItemClickListener;
private int animation_type = 0;
public interface OnItemClickListener {
void onItemClick(View view, Task obj, int position);
}
public void setOnItemClickListener(final OnItemClickListener mItemClickListener) {
this.mOnItemClickListener = mItemClickListener;
}
public AdapterTasks(Context context, List<Task> items, int animation_type) {
this.items = DataGenerator.getTasksData();
this.items.addAll(DataGenerator.getTasksData());
ctx = context;
this.animation_type = animation_type;
}
public class OriginalViewHolder extends RecyclerView.ViewHolder {
public View lyt_parent;
public TextView laikas;
public TextView klientas;
public TextView darbas;
public TextView komentaras;
public Button atlikta;
public OriginalViewHolder(View v) {
super(v);
laikas = (TextView) v.findViewById(R.id.laikas);
klientas = (TextView) v.findViewById(R.id.name);
lyt_parent = (View) v.findViewById(R.id.lyt_parent);
darbas = (TextView) v.findViewById(R.id.darbas);
komentaras = (TextView) v.findViewById(R.id.komentaras);
atlikta = (Button) v.findViewById(R.id.atlikta);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder vh;
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_task, parent, false);
vh = new OriginalViewHolder(v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
Log.e("onBindViewHolder", "onBindViewHolder : " + position);
if (holder instanceof OriginalViewHolder) {
OriginalViewHolder view = (OriginalViewHolder) holder;
Task t = items.get(position);
view.laikas.setText((CharSequence) t.AtlikData);
view.klientas.setText(t.KlientasID);
view.darbas.setText(t.VeiksmoID);
view.komentaras.setText(t.Komentaras);
view.lyt_parent.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(view, items.get(position), position);
}
}
});
setAnimation(view.itemView, position);
}
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
on_attach = false;
super.onScrollStateChanged(recyclerView, newState);
}
});
super.onAttachedToRecyclerView(recyclerView);
}
@Override
public int getItemCount() {
return items.size();
}
private int lastPosition = -1;
private boolean on_attach = true;
private void setAnimation(View view, int position) {
if (position > lastPosition) {
ItemAnimation.animate(view, on_attach ? position : -1, animation_type);
lastPosition = position;
}
}
}
您的方法是异步的,因此 onResponse
中的代码将在您的 getTaskData
方法返回空列表后运行。您需要修改您的程序流程以适应这种情况。
这是一个示例,说明如何定义自己的自定义回调来处理该问题,首先将 RecyclerView 设置为空,然后在数据到达后添加数据。
第 1 步:在某处定义接口(例如在 activity 或改装请求 class 中)
interface OnTasksRetrieved {
void getResult(List<Task> result);
}
第 2 步:更改您的 getTasksData
方法以获取实现该接口的回调而不是返回列表
public static void getTasksData(OnTasksRetrieved callback) {
//...
call.enqueue(new Callback<List<Task>>() {
@Override
public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
// Call your callback once you have retrieved the data
callback.getResult(response.body());
}
@Override
public void onFailure(Call<List<Task>> call, Throwable t) {
}
});
// do not return anything
}
第三步:当你在onCreate
中开始异步调用时,创建一个回调接口的实例传递给它来处理结果
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_animation);
parent_view = findViewById(android.R.id.content);
initComponent();
// start the async fetch here - it won't finish until
// later in the future, when it will call the callback code
// below to update the RecyclerView data
getTasksData(
new OnTasksRetrieved() {
@Override
public void getResult(List<Task> result) {
// The code in here runs much later in the future - the adapter
// will already have been set up, but will be empty.
myAdapter.setItems(result); // add this method to the adapter
}
}
);
}
您将需要修改适配器,使其不将列表作为输入,而是具有类似这样的 setItems
方法,一旦检索到数据就会调用该方法:
private List<Task> items = new ArrayList<>();
public AdapterTasks(Context context, int animation_type) {
ctx = context;
this.animation_type = animation_type;
}
public void setItems(List<Task> data) {
items.clear();
items.addAll(data);
notifyDataSetChanged();
}
我正在使用一个模板,我用 Retrofit 2 请求替换了占位符数据,该请求解析了 URL 中数据的 JSON 文件并将其放入对象列表中。我 运行 遇到了一个问题,我的改造调用首先被执行并且 returns items = 0,然后代码使用值 items=0 进一步执行并且在调试器中执行了相当多的步骤后,它返回到调用并显示正确的响应(items=12)但是 Adapter/RecycleView 操作似乎已经执行并且它们不使用迟到的解析数据.
MainActivity.java
public class MainActivity extends AppCompatActivity {
private View parent_view;
List<Task> items = new List<Task>() {...}
private RecyclerView recyclerView;
private AdapterTasks mAdapter;
private int animation_type = ItemAnimation.BOTTOM_UP;
@Override
protected void onCreate(Bundle savedInstanceState) {
items = DataGenerator.getTasksData();
items.addAll(DataGenerator.getTasksData());
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_animation);
parent_view = findViewById(android.R.id.content);
initComponent();
}
private void initComponent() {
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
animation_type = ItemAnimation.FADE_IN;
setAdapter();
}
private void setAdapter() {
//set data and list adapter
mAdapter = new AdapterTasks(this, items, animation_type);
recyclerView.setAdapter(mAdapter);
// on item list clicked
mAdapter.setOnItemClickListener(new AdapterTasks.OnItemClickListener() {
@Override
public void onItemClick(View view, Task obj, int position) {
//open task view
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_list_animation, menu);
return true;
}
改造请求
public static List<Task> getTasksData() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd HH:mm:ss")
.create();
Retrofit retrofit= new Retrofit.Builder()
.baseUrl("http://10.0.2.2/index.php/")
.addConverterFactory(GsonConverterFactory.create(gson))
.client(client)
.build();
TasksApi taskAPI =retrofit.create(TasksApi.class);
Call<List<Task>> call = taskAPI.getAllTasks();
call.enqueue(new Callback<List<Task>>() {
@Override
public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
items = response.body();
}
@Override
public void onFailure(Call<List<Task>> call, Throwable t) {
}
});
return items;
}
适配器
public class AdapterTasks extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Task> items;
private Context ctx;
private OnItemClickListener mOnItemClickListener;
private int animation_type = 0;
public interface OnItemClickListener {
void onItemClick(View view, Task obj, int position);
}
public void setOnItemClickListener(final OnItemClickListener mItemClickListener) {
this.mOnItemClickListener = mItemClickListener;
}
public AdapterTasks(Context context, List<Task> items, int animation_type) {
this.items = DataGenerator.getTasksData();
this.items.addAll(DataGenerator.getTasksData());
ctx = context;
this.animation_type = animation_type;
}
public class OriginalViewHolder extends RecyclerView.ViewHolder {
public View lyt_parent;
public TextView laikas;
public TextView klientas;
public TextView darbas;
public TextView komentaras;
public Button atlikta;
public OriginalViewHolder(View v) {
super(v);
laikas = (TextView) v.findViewById(R.id.laikas);
klientas = (TextView) v.findViewById(R.id.name);
lyt_parent = (View) v.findViewById(R.id.lyt_parent);
darbas = (TextView) v.findViewById(R.id.darbas);
komentaras = (TextView) v.findViewById(R.id.komentaras);
atlikta = (Button) v.findViewById(R.id.atlikta);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder vh;
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_task, parent, false);
vh = new OriginalViewHolder(v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
Log.e("onBindViewHolder", "onBindViewHolder : " + position);
if (holder instanceof OriginalViewHolder) {
OriginalViewHolder view = (OriginalViewHolder) holder;
Task t = items.get(position);
view.laikas.setText((CharSequence) t.AtlikData);
view.klientas.setText(t.KlientasID);
view.darbas.setText(t.VeiksmoID);
view.komentaras.setText(t.Komentaras);
view.lyt_parent.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(view, items.get(position), position);
}
}
});
setAnimation(view.itemView, position);
}
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
on_attach = false;
super.onScrollStateChanged(recyclerView, newState);
}
});
super.onAttachedToRecyclerView(recyclerView);
}
@Override
public int getItemCount() {
return items.size();
}
private int lastPosition = -1;
private boolean on_attach = true;
private void setAnimation(View view, int position) {
if (position > lastPosition) {
ItemAnimation.animate(view, on_attach ? position : -1, animation_type);
lastPosition = position;
}
}
}
您的方法是异步的,因此 onResponse
中的代码将在您的 getTaskData
方法返回空列表后运行。您需要修改您的程序流程以适应这种情况。
这是一个示例,说明如何定义自己的自定义回调来处理该问题,首先将 RecyclerView 设置为空,然后在数据到达后添加数据。
第 1 步:在某处定义接口(例如在 activity 或改装请求 class 中)
interface OnTasksRetrieved {
void getResult(List<Task> result);
}
第 2 步:更改您的 getTasksData
方法以获取实现该接口的回调而不是返回列表
public static void getTasksData(OnTasksRetrieved callback) {
//...
call.enqueue(new Callback<List<Task>>() {
@Override
public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
// Call your callback once you have retrieved the data
callback.getResult(response.body());
}
@Override
public void onFailure(Call<List<Task>> call, Throwable t) {
}
});
// do not return anything
}
第三步:当你在onCreate
中开始异步调用时,创建一个回调接口的实例传递给它来处理结果
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_animation);
parent_view = findViewById(android.R.id.content);
initComponent();
// start the async fetch here - it won't finish until
// later in the future, when it will call the callback code
// below to update the RecyclerView data
getTasksData(
new OnTasksRetrieved() {
@Override
public void getResult(List<Task> result) {
// The code in here runs much later in the future - the adapter
// will already have been set up, but will be empty.
myAdapter.setItems(result); // add this method to the adapter
}
}
);
}
您将需要修改适配器,使其不将列表作为输入,而是具有类似这样的 setItems
方法,一旦检索到数据就会调用该方法:
private List<Task> items = new ArrayList<>();
public AdapterTasks(Context context, int animation_type) {
ctx = context;
this.animation_type = animation_type;
}
public void setItems(List<Task> data) {
items.clear();
items.addAll(data);
notifyDataSetChanged();
}