第一个元素在 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{...}.

之后