第一个元素在 GridView 适配器中的列表末尾弹出
First element pops up at the end of list in GridView adapter
所以我有 DashboardFragment 带有项目的网格视图,当按下网格中的最后一个项目时它打开 new activity用于将新类别添加到数据库,将其添加到数据库 后 activity 关闭并且 DashboardFragment 中的网格应该更新为新元素网格的末端。这是我想出的代码,问题是每当我添加新类别时,网格都会更新,但列表的第一个元素位于网格的末尾。当我重新启动应用程序时,新元素在末尾并且所有内容都按原样显示,因此它正确地将元素添加到数据库中。在调试器中,两个列表(一个在适配器中,一个在主 class 中)是相同的,并且末尾有新元素。我花了半天时间寻找解决方案,但找不到导致此问题的原因。
public class DashboardFragment extends Fragment {
private DashboardViewModel dashboardViewModel;
List<Category> categories = new ArrayList<>();
PieChart chart;
CategoryAdapter adapter;
DBHelper dbHelper;
SQLiteDatabase database;
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
dashboardViewModel = ViewModelProviders.of(this).get(DashboardViewModel.class);
View root = inflater.inflate(R.layout.fragment_dashboard, container, false);
setHasOptionsMenu(true);
//-----Database
dbHelper = new DBHelper(super.getContext());
//-----Categories
ParseCategories();
final ExpandableHeightGridView gridView = (ExpandableHeightGridView) root.findViewById(R.id.category_grid);
adapter = new CategoryAdapter(root.getContext(), categories);
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position == categories.size() - 1) {
startActivityForResult(new Intent(DashboardFragment.super.getContext(), CategoryCreation.class),1);
}
}
});
gridView.setExpanded(true);
//-----Chart
chart = (PieChart) root.findViewById(R.id.chart);
setupPieChart();
return root;
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode==1){
ParseCategories();
adapter.updateCategoryList(categories);
}
}
public void ParseCategories() {
categories.clear();
database = dbHelper.getWritableDatabase();
Cursor c = database.rawQuery("select * from categories", null);
c.moveToFirst();
for (int i = 0; i < c.getCount(); i++) {
int id = c.getInt(c.getColumnIndex("_id"));
String name = c.getString(c.getColumnIndex("name"));
double amount = c.getDouble(c.getColumnIndex("amount"));
int imageId = c.getInt(c.getColumnIndex("iconId"));
categories.add(new Category(id, name, amount, imageId));
c.moveToNext();
}
categories.add(new Category(-1, "Add", -1, R.drawable.add_category_icon));
c.close();
database.close();
}
public class CategoryAdapter extends BaseAdapter {
private Context context;
private List<Category> categories;
public CategoryAdapter(Context context, List<Category> cats) {
this.context = context;
this.categories = cats;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if (convertView == null) {
gridView = new View(context);
gridView = inflater.inflate(R.layout.dashboard_category_item, null);
TextView nameView = (TextView) gridView.findViewById(R.id.category_name);
ImageView imageView = (ImageView) gridView.findViewById(R.id.grid_item_image);
TextView amountView = (TextView) gridView.findViewById(R.id.category_amount);
nameView.setText(categories.get(position).getName());
imageView.setImageResource(categories.get(position).getIconId());
if (categories.get(position).getAmount() >= 0) {
amountView.setText("$" + categories.get(position).getAmount());
} else {
amountView.setText("");
}
} else {
gridView = (View) convertView;
}
return gridView;
}
@Override
public int getCount() {
return categories.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
public void updateCategoryList(List<Category> newlist) {
this.notifyDataSetChanged();
}
}
}
试试这个:
public View getView(int position, View convertView, ViewGroup parent) {
View gridView;
if (convertView == null) {
gridView = new View(context);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
gridView = inflater.inflate(R.layout.dashboard_category_item, null);
} else {
gridView = (View) convertView;
}
TextView nameView = (TextView) gridView.findViewById(R.id.category_name);
ImageView imageView = (ImageView) gridView.findViewById(R.id.grid_item_image);
TextView amountView = (TextView) gridView.findViewById(R.id.category_amount);
nameView.setText(categories.get(position).getName());
imageView.setImageResource(categories.get(position).getIconId());
if (categories.get(position).getAmount() >= 0) {
amountView.setText("$" + categories.get(position).getAmount());
} else {
amountView.setText("");
}
return gridView;
}
说明:
为了更好的内存使用和效率,adpater 被设计为 reuse/recycle item views。一种情况是滚动,一些项目消失,适配器从参数 convertView 获取消失的视图,可用于新项目。但是这些 convertViews 包含旧数据,因此需要用新数据填充它们。类似的情况发生在 notifyDataSetChanged() 上。因此,在项目视图中填充数据的代码应该在 if (convertView == null) {...}else{...}
.
之后
所以我有 DashboardFragment 带有项目的网格视图,当按下网格中的最后一个项目时它打开 new activity用于将新类别添加到数据库,将其添加到数据库 后 activity 关闭并且 DashboardFragment 中的网格应该更新为新元素网格的末端。这是我想出的代码,问题是每当我添加新类别时,网格都会更新,但列表的第一个元素位于网格的末尾。当我重新启动应用程序时,新元素在末尾并且所有内容都按原样显示,因此它正确地将元素添加到数据库中。在调试器中,两个列表(一个在适配器中,一个在主 class 中)是相同的,并且末尾有新元素。我花了半天时间寻找解决方案,但找不到导致此问题的原因。
public class DashboardFragment extends Fragment {
private DashboardViewModel dashboardViewModel;
List<Category> categories = new ArrayList<>();
PieChart chart;
CategoryAdapter adapter;
DBHelper dbHelper;
SQLiteDatabase database;
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
dashboardViewModel = ViewModelProviders.of(this).get(DashboardViewModel.class);
View root = inflater.inflate(R.layout.fragment_dashboard, container, false);
setHasOptionsMenu(true);
//-----Database
dbHelper = new DBHelper(super.getContext());
//-----Categories
ParseCategories();
final ExpandableHeightGridView gridView = (ExpandableHeightGridView) root.findViewById(R.id.category_grid);
adapter = new CategoryAdapter(root.getContext(), categories);
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position == categories.size() - 1) {
startActivityForResult(new Intent(DashboardFragment.super.getContext(), CategoryCreation.class),1);
}
}
});
gridView.setExpanded(true);
//-----Chart
chart = (PieChart) root.findViewById(R.id.chart);
setupPieChart();
return root;
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode==1){
ParseCategories();
adapter.updateCategoryList(categories);
}
}
public void ParseCategories() {
categories.clear();
database = dbHelper.getWritableDatabase();
Cursor c = database.rawQuery("select * from categories", null);
c.moveToFirst();
for (int i = 0; i < c.getCount(); i++) {
int id = c.getInt(c.getColumnIndex("_id"));
String name = c.getString(c.getColumnIndex("name"));
double amount = c.getDouble(c.getColumnIndex("amount"));
int imageId = c.getInt(c.getColumnIndex("iconId"));
categories.add(new Category(id, name, amount, imageId));
c.moveToNext();
}
categories.add(new Category(-1, "Add", -1, R.drawable.add_category_icon));
c.close();
database.close();
}
public class CategoryAdapter extends BaseAdapter {
private Context context;
private List<Category> categories;
public CategoryAdapter(Context context, List<Category> cats) {
this.context = context;
this.categories = cats;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if (convertView == null) {
gridView = new View(context);
gridView = inflater.inflate(R.layout.dashboard_category_item, null);
TextView nameView = (TextView) gridView.findViewById(R.id.category_name);
ImageView imageView = (ImageView) gridView.findViewById(R.id.grid_item_image);
TextView amountView = (TextView) gridView.findViewById(R.id.category_amount);
nameView.setText(categories.get(position).getName());
imageView.setImageResource(categories.get(position).getIconId());
if (categories.get(position).getAmount() >= 0) {
amountView.setText("$" + categories.get(position).getAmount());
} else {
amountView.setText("");
}
} else {
gridView = (View) convertView;
}
return gridView;
}
@Override
public int getCount() {
return categories.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
public void updateCategoryList(List<Category> newlist) {
this.notifyDataSetChanged();
}
}
}
试试这个:
public View getView(int position, View convertView, ViewGroup parent) {
View gridView;
if (convertView == null) {
gridView = new View(context);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
gridView = inflater.inflate(R.layout.dashboard_category_item, null);
} else {
gridView = (View) convertView;
}
TextView nameView = (TextView) gridView.findViewById(R.id.category_name);
ImageView imageView = (ImageView) gridView.findViewById(R.id.grid_item_image);
TextView amountView = (TextView) gridView.findViewById(R.id.category_amount);
nameView.setText(categories.get(position).getName());
imageView.setImageResource(categories.get(position).getIconId());
if (categories.get(position).getAmount() >= 0) {
amountView.setText("$" + categories.get(position).getAmount());
} else {
amountView.setText("");
}
return gridView;
}
说明:
为了更好的内存使用和效率,adpater 被设计为 reuse/recycle item views。一种情况是滚动,一些项目消失,适配器从参数 convertView 获取消失的视图,可用于新项目。但是这些 convertViews 包含旧数据,因此需要用新数据填充它们。类似的情况发生在 notifyDataSetChanged() 上。因此,在项目视图中填充数据的代码应该在 if (convertView == null) {...}else{...}
.