【问题标题】:ListView Not Refreshing When New Record Added添加新记录时ListView不刷新
【发布时间】:2018-06-06 15:32:09
【问题描述】:

似乎无法弄清楚,我已经完成了所有代码,但没有任何成功。当我将新投球手添加到空列表时,它会正确显示,当我将第二个或更多投球手添加到列表时,投球手的名称显示为添加的第一个投球手的名称。我在下面添加了几个屏幕截图来说明我的意思。

显然,这些图像的顺序是从左到右。我也将我的 BowlerActivity 包含在这篇文章中。这是我创建和更新新的和现有的投球手的地方。

private BowlerAdapter mAdapter;
    private List<Bowler> bowlersList = new ArrayList<>();
    private CoordinatorLayout coordinatorLayout;
    private RecyclerView recyclerView;
    private TextView noBowlersView;

    private DatabaseHelper db;

    private TextView leagueId;
    private String savedLeagueId;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bowler);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowHomeEnabled(true);

        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(getApplicationContext(),MainActivity.class));
                finish();
            }
        });

        savedLeagueId = String.valueOf(getIntent().getIntExtra("leagueId",2));
        leagueId = (TextView) findViewById(R.id.tvLeagueId);

        coordinatorLayout = findViewById(R.id.coordinator_layout);
        recyclerView = findViewById(R.id.recycler_view);
        noBowlersView = findViewById(R.id.empty_bowlers_view);

        db = new DatabaseHelper(this);

        bowlersList.addAll(db.getAllBowlers(savedLeagueId));

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.add_bowler_fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                showBowlerDialog(false, null, -1);
            }
        });

        mAdapter = new BowlerAdapter(this, bowlersList);
        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.addItemDecoration(new MyDividerItemDecoration(this, LinearLayoutManager.VERTICAL, 16));
        recyclerView.setAdapter(mAdapter);

        toggleEmptyBowlers();

        //On Long Click On The RecyclerView Item An Alert Dialog Is Opened With The Option To Choose Edit/Delete
        recyclerView.addOnItemTouchListener(new RecyclerTouchListener(this,
                recyclerView, new RecyclerTouchListener.ClickListener() {
            @Override
            public void onClick(View view, final int position) {

                String seriesLeagueId = bowlersList.get(position).getLeagueId();
                int seriesBowlerId = bowlersList.get(position).getId();
                Intent myIntent = new Intent(BowlerActivity.this, SeriesActivity.class);
                myIntent.putExtra("seriesLeagueId", seriesLeagueId);
                myIntent.putExtra("seriesBowlerId", seriesBowlerId);
                startActivity(myIntent);

            }

            @Override
            public void onLongClick(View view, int position) {
                showActionsDialog(position);
            }
        }));
    }

    //Inserting New Bowler In The Database And Refreshing The List
    private void createBowler(String leagueId,  String bowlerName) {
        //Inserting Bowler In The Database And Getting Newly Inserted Bowler Id
        long id = db.insertBowler(leagueId, bowlerName);

        //Get The Newly Inserted Bowler From The Database
        Bowler n = db.getBowler(leagueId);

        if (n != null) {
            //Adding New Bowler To The Array List At Position 0
            bowlersList.add(0, n);

            //Refreshing The List
            mAdapter.notifyDataSetChanged();

            toggleEmptyBowlers();
        }
    }

    //Updating Bowler In The Database And Updating The Item In The List By Its Position
    private void updateBowler(String bowlerName, int position) {
        Bowler n = bowlersList.get(position);

        //Updating Bowler Text
        n.setLeagueId(savedLeagueId);
        n.setName(bowlerName);

        //Updating The Bowler In The Database
        db.updateBowler(n);

        //Refreshing The List
        bowlersList.set(position, n);
        mAdapter.notifyItemChanged(position);

        toggleEmptyBowlers();
    }

    //Deleting Bowler From SQLite Database And Removing The Bowler Item From The List By Its Position
    private void deleteBowler(int position) {
        //Deleting The Bowler From The Database
        db.deleteBowler(bowlersList.get(position));

        //Removing The Bowler From The List
        bowlersList.remove(position);
        mAdapter.notifyItemRemoved(position);

        toggleEmptyBowlers();
    }

    //Opens Dialog With Edit/Delete Options
    //Edit - 0
    //Delete - 0
    private void showActionsDialog(final int position) {
        CharSequence colors[] = new CharSequence[]{"Edit", "Delete"};

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Choose option");
        builder.setItems(colors, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (which == 0) {
                    showBowlerDialog(true, bowlersList.get(position), position);
                } else {
                    deleteBowler(position);
                }
            }
        });
        builder.show();
    }

    //Show Alert Dialog With EditText Options to Enter/Edit A League
    //When shouldUpdate = true, It Will Automatically Display Old Bowler Name And Change The Button Text To UPDATE
    private void showBowlerDialog(final boolean shouldUpdate, final Bowler bowler, final int position) {
        LayoutInflater layoutInflaterAndroid = LayoutInflater.from(getApplicationContext());
        View view = layoutInflaterAndroid.inflate(R.layout.dialog_bowler, null);

        AlertDialog.Builder alertDialogBuilderUserInput = new AlertDialog.Builder(BowlerActivity.this);
        alertDialogBuilderUserInput.setView(view);

        leagueId.setText(savedLeagueId);
        final EditText inputBowlerName = view.findViewById(R.id.etBowlerNameInput);
        TextView dialogTitle = view.findViewById(R.id.dialog_title);
        dialogTitle.setText(!shouldUpdate ? getString(R.string.lbl_new_bowler_title) : getString(R.string.lbl_edit_bowler_title));

        if (shouldUpdate && bowler != null) {
            leagueId.setText(bowler.getLeagueId());
            inputBowlerName.setText(bowler.getName());

        }
        alertDialogBuilderUserInput
                .setCancelable(false)
                .setPositiveButton(shouldUpdate ? "update" : "save", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialogBox, int id) {

                    }
                })
                .setNegativeButton("cancel",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialogBox, int id) {
                                dialogBox.cancel();
                            }
                        });

        final AlertDialog alertDialog = alertDialogBuilderUserInput.create();
        alertDialog.show();

        alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //Show Toast Message When No Text Is Entered
                if (TextUtils.isEmpty(inputBowlerName.getText().toString())) {
                    Toast.makeText(BowlerActivity.this, "Enter Bowler!", Toast.LENGTH_SHORT).show();
                    return;
                } else {
                    alertDialog.dismiss();
                }

                //Check If User Is Updating Bowler
                if (shouldUpdate && bowler != null) {

                    //Updating Bowler By Its Id
                    updateBowler(inputBowlerName.getText().toString(), position);

                } else {
                    //Creating New Bowler
                    createBowler(leagueId.getText().toString(), inputBowlerName.getText().toString());

                }
            }
        });
    }

    //Toggling List And Empty Bowler View
    private void toggleEmptyBowlers() {
        //You Can Check bowlerList.size() > 0

        if (db.getBowlersCount() > 0) {
            noBowlersView.setVisibility( View.GONE);
        } else {
            noBowlersView.setVisibility( View.VISIBLE);
        }
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate( R.menu.menu_main, menu );
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected( item );
    }
}

我还包含了包含 Bowler 方法的 DatabaseHelper 部分。

public long insertBowler(String leagueId, String bowlerName) {
        //Get Writable Database That We Want To Write Data Too
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        //`id` and `timestamp` Will Be Inserted Automatically
        values.put(Bowler.COLUMN_LEAGUE_ID, leagueId);
        values.put(Bowler.COLUMN_NAME, bowlerName);

         //Insert Row
        long id = db.insert( Bowler.TABLE_NAME, null, values );

        //Close Database Connection
        db.close();

        //Return Newly Inserted Row Id
        return id;
    }

    public Bowler getBowler(String leagueId) {
        //Get Readable Database If We Are Not Inserting Anything
        SQLiteDatabase db = this.getReadableDatabase();

        Cursor cursor = db.query(Bowler.TABLE_NAME,
                new String[]{Bowler.COLUMN_ID, Bowler.COLUMN_LEAGUE_ID, Bowler.COLUMN_NAME, Bowler.COLUMN_TIMESTAMP},
                Bowler.COLUMN_LEAGUE_ID + "=?",
                new String[]{String.valueOf(leagueId)}, null, null, null, null);

        if (cursor.moveToFirst()) {

            //Prepare Bowler Object
        Bowler bowler = new Bowler(
                cursor.getInt(cursor.getColumnIndex(Bowler.COLUMN_ID)),
                cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_LEAGUE_ID)),
                cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_NAME)),
                cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_TIMESTAMP)));

        //Close Database Connection
        cursor.close();
        return bowler;
    } else {return null;}
}
    public List<Bowler> getAllBowlers(String leagueId) {
        List<Bowler> bowlers = new ArrayList<>();

        //Select All Query
        String selectQuery = "SELECT  * FROM " + Bowler.TABLE_NAME + " WHERE " + Bowler.COLUMN_LEAGUE_ID + " = '" + leagueId + "'" + " ORDER BY " +
                Bowler.COLUMN_TIMESTAMP + " DESC";

        SQLiteDatabase db = this.getWritableDatabase();
        Cursor cursor = db.rawQuery(selectQuery, null);

        //Looping Through All Rows And Adding To The List
        if (cursor.moveToFirst()) {
            do {
                Bowler bowler = new Bowler();
                bowler.setId(cursor.getInt(cursor.getColumnIndex(Bowler.COLUMN_ID)));
                bowler.setLeagueId(cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_LEAGUE_ID)));
                bowler.setName(cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_NAME)));
                bowler.setTimestamp(cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_TIMESTAMP)));
                bowlers.add(bowler);
            } while (cursor.moveToNext());
        }
        cursor.close();
        //Close Database Connection
        db.close();

        //Return Bowlers List
        return bowlers;
    }

    public int getBowlersCount() {
        String countQuery = "SELECT  * FROM " + Bowler.TABLE_NAME;
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.rawQuery(countQuery, null);

        int count = cursor.getCount();
        cursor.close();

        //Return The Count
        return count;
    }

    public int updateBowler(Bowler bowler) {
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(Bowler.COLUMN_LEAGUE_ID, bowler.getLeagueId());
        values.put(Bowler.COLUMN_NAME, bowler.getName());

        //Updating Row
        return db.update(Bowler.TABLE_NAME, values, Bowler.COLUMN_ID + " = ?",
                new String[]{String.valueOf(bowler.getId())});
    }

    public void deleteBowler(Bowler bowler) {
        SQLiteDatabase db = this.getWritableDatabase();
        db.delete( Bowler.TABLE_NAME, Bowler.COLUMN_ID + " = ?",
                new String[]{String.valueOf( bowler.getId())});
        db.close();
    }

为了以防万一,我还发布了 BowlerAdapter 代码。

public class BowlerAdapter extends RecyclerView.Adapter<BowlerAdapter.MyViewHolder> {

    private Context context;
    private List<Bowler> bowlersList;

    public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView bowlerLeagueId;
        public TextView name;
        public TextView timestamp;

        public MyViewHolder(View view) {
            super(view);
            bowlerLeagueId = view.findViewById( R.id.tvLeagueId);
            name = view.findViewById(R.id.tvBowlerName );
            timestamp = view.findViewById(R.id.timestamp);
        }
    }


    public BowlerAdapter(Context context, List<Bowler> bowlersList) {
        this.context = context;
        this.bowlersList = bowlersList;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.listview_bowler, parent, false);

        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        Bowler bowler = bowlersList.get(position);

        holder.bowlerLeagueId.setText(bowler.getLeagueId());
        holder.name.setText(bowler.getName());

        //Formatting And Displaying Timestamp
        holder.timestamp.setText(formatDate(bowler.getTimestamp()));
    }

    @Override
    public int getItemCount() {
        return bowlersList.size();
    }

    //Formatting TimeStamp to 'EEE MMM dd yyyy (HH:mm:ss)'
    //Input  : 2018-05-23 9:59:01
    //Output : Wed May 23 2018 (9:59:01)
    private String formatDate(String dateStr) {
        try {
            SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = fmt.parse(dateStr);
            SimpleDateFormat fmtOut = new SimpleDateFormat("EEE MMM dd yyyy (HH:mm:ss)");
            return fmtOut.format(date);
        } catch (ParseException e) { }

        return "";
    }

我确信这是非常明显的事情,但我已经查看了几个小时的代码,但我没有发现问题。

我们将不胜感激。

我已经按照您的指示修改了我的代码,但是当我现在添加一个新的投球手时,屏幕会返回空白,直到我离开 BowlerActivity 并返回它,此时列表已更新。

//Inserting New Bowler In The Database And Refreshing The List
    private void createBowler(String leagueId,  String bowlerName) {
        //Inserting Bowler In The Database And Getting Newly Inserted Bowler Id
        long id = db.insertBowler(leagueId, bowlerName);

        //Get The Newly Inserted Bowler From The Database
        Bowler n = db.getBowler(leagueId);

        if (n != null) {
            //Adding New Bowler To The Array List At Position 0
            bowlersList.add(0, n);

            //Refreshing The List
            mAdapter.notifyDataSetChanged(bowlersList);

            toggleEmptyBowlers();
        }
    }

BowlerAdapter notifyDataSetChanged 方法

private List<Bowler> bowlersList;

    public void notifyDataSetChanged(List<Bowler> newbowlersList) {
        bowlersList.clear();
        bowlersList.addAll( newbowlersList );
        super.notifyDataSetChanged();
    }

调试日志

this = {BowlerActivity@5027} 
leagueId = "1"
bowlerName = "Robert"
id = 6
n = {Bowler@5032} 
 id = 1
 league_id = "1"
 name = "b1"
 timestamp = "2018-06-07 20:03:19"
 shadow$_klass_ = {Class@4839} "class ca.rvogl.tpbcui.database.models.Bowler"
 shadow$_monitor_ = -2106571381
mAdapter = {BowlerAdapter@5033} 
 bowlersList = {ArrayList@5037}  size = 0
 mHasStableIds = false
 mObservable = {RecyclerView$AdapterDataObservable@5088} 
 shadow$_klass_ = {Class@4930} "class ca.rvogl.tpbcui.views.BowlerAdapter"
 shadow$_monitor_ = -2088753560

log.d 日志文件 sn-p

06-08 13:00:53.807 29879-29879/ca.rvogl.tpbcui D/INSERTBOWLER: Number of bowlers in db = 4
06-08 13:00:53.814 29879-29884/ca.rvogl.tpbcui I/art: Do partial code cache collection, code=30KB, data=29KB
06-08 13:00:53.815 29879-29884/ca.rvogl.tpbcui I/art: After code cache collection, code=30KB, data=29KB
    Increasing code cache capacity to 128KB
06-08 13:00:53.815 29879-29895/ca.rvogl.tpbcui D/EGL_emulation: eglMakeCurrent: 0x9e6fa300: ver 3 0 (tinfo 0xa068a610)
06-08 13:00:53.831 29879-29879/ca.rvogl.tpbcui W/IInputConnectionWrapper: finishComposingText on inactive InputConnection
06-08 13:01:00.552 29879-29895/ca.rvogl.tpbcui D/EGL_emulation: eglMakeCurrent: 0x9e6fa300: ver 3 0 (tinfo 0xa068a610)
06-08 13:01:02.336 29879-29895/ca.rvogl.tpbcui D/EGL_emulation: eglMakeCurrent: 0x9e6fa300: ver 3 0 (tinfo 0xa068a610)
06-08 13:01:04.023 29879-29895/ca.rvogl.tpbcui D/EGL_emulation: eglMakeCurrent: 0x9e6fa300: ver 3 0 (tinfo 0xa068a610)
06-08 13:01:04.040 29879-29895/ca.rvogl.tpbcui D/EGL_emulation: eglMakeCurrent: 0x9e6fa300: ver 3 0 (tinfo 0xa068a610)
06-08 13:01:04.050 29879-29895/ca.rvogl.tpbcui D/EGL_emulation: eglMakeCurrent: 0x9e6fa300: ver 3 0 (tinfo 0xa068a610)
06-08 13:01:04.059 29879-29895/ca.rvogl.tpbcui D/EGL_emulation: eglMakeCurrent: 0x9e6fa300: ver 3 0 (tinfo 0xa068a610)
06-08 13:01:04.534 29879-29895/ca.rvogl.tpbcui D/EGL_emulation: eglMakeCurrent: 0x9e6fa300: ver 3 0 (tinfo 0xa068a610)
06-08 13:01:04.542 29879-29895/ca.rvogl.tpbcui D/EGL_emulation: eglMakeCurrent: 0x9e6fa300: ver 3 0 (tinfo 0xa068a610)
06-08 13:01:05.034 29879-29895/ca.rvogl.tpbcui D/EGL_emulation: eglMakeCurrent: 0x9e6fa300: ver 3 0 (tinfo 0xa068a610)
06-08 13:01:11.363 29879-29895/ca.rvogl.tpbcui D/EGL_emulation: eglMakeCurrent: 0x9e6fa300: ver 3 0 (tinfo 0xa068a610)
06-08 13:01:11.373 29879-29879/ca.rvogl.tpbcui D/INSERTBOWLER: Number of bowlers in db = 5
06-08 13:01:11.380 29879-29895/ca.rvogl.tpbcui D/EGL_emulation: eglMakeCurrent: 0x9e6fa300: ver 3 0 (tinfo 0xa068a610)
06-08 13:01:11.393 29879-29879/ca.rvogl.tpbcui W/IInputConnectionWrapper: finishComposingText on inactive InputConnection

【问题讨论】:

标签: java android sqlite listview


【解决方案1】:

我相信您的问题是您没有更新适配器中的实际源列表。

解决方案可能是向 BowlerAdapter 添加一个方法,例如:-

public void notifyDatasetChanged(List<Bowler> newbowlerlist) {
    bowlersList.clear();
    bowlersList.addAll(newbowlerlist);
    super.notifyDataSetChanged();
}

然后使用这个新方法,传递修改后的 Bowlerlist,而不是股票的 notifyDatasetChanged 方法。

例如而不是:-

    if (n != null) {
        //Adding New Bowler To The Array List At Position 0
        bowlersList.add(0, n);

        //Refreshing The List
        mAdapter.notifyDataSetChanged();

        toggleEmptyBowlers();
    }

使用:-

    if (n != null) {
        //Adding New Bowler To The Array List At Position 0
        bowlersList.add(0, n);

        //Refreshing The List
        mAdapter.notifyDataSetChanged(bowlerList);

        toggleEmptyBowlers();
    }

根据您使用上面的代码,获得以下结果:-

初始显示

  • 最初在应用启动时添加了 2 个保龄球。
  • 添加了按钮,而不是对所有对话框处理进行编码(因此,如果 EditText 不为空,则单击该按钮将添加一个新的投球手)。

添加新保龄球后

添加了一个新的投球手:-

  1. 在 EditText 中输入 Howard。
  2. 单击“添加投球手”按钮。
  3. 列表已刷新,显示添加的投球手。

:-

补充评论:-

好的,插入正常(您可以删除更改)。现在使 对getAllBowlers 方法进行更改后(1 编写 selectQuery sql到日志,2写入检索到的行数 日志和 3 将保龄球 ArrayList 的大小写入 日志)。运行并报告或修复。

public List<Bowler> getAllBowlers(String leagueId) {
    List<Bowler> bowlers = new ArrayList<>();

    //Select All Query
    String selectQuery = "SELECT  * FROM " + Bowler.TABLE_NAME + " WHERE " + Bowler.COLUMN_LEAGUE_ID + " = '" + leagueId + "'" + " ORDER BY " +
            Bowler.COLUMN_TIMESTAMP + " DESC";

    Log.d("GETALLBOWLERS-SQL","SQL used = >>>>" +selectQuery + "<<<<");

    SQLiteDatabase db = this.getWritableDatabase();
    Cursor cursor = db.rawQuery(selectQuery, null);

    Log.d("GETALLBOWLERS-CNT","Number of rows retrieved = " + String.valueOf(cursor.getCount()));


    //Looping Through All Rows And Adding To The List
    if (cursor.moveToFirst()) {
        do {
            Bowler bowler = new Bowler();
            bowler.setId(cursor.getInt(cursor.getColumnIndex(Bowler.COLUMN_ID)));
            bowler.setLeagueId(cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_LEAGUE_ID)));
            bowler.setName(cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_NAME)));
            bowler.setTimestamp(cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_TIMESTAMP)));
            bowlers.add(bowler);
        } while (cursor.moveToNext());
    }
    cursor.close();
    //Close Database Connection
    db.close();
    Log.d("GETALLBOWLERS-CNT","Number of elements in bowlerslist = " + String.valueOf(bowlers.size()));

    //Return Bowlers List
    return bowlers;
}

工作示例

我实际上无法确定您的问题,尽管我确实相信它与原始答案有关,因为适配器适用于/使用投球手列表的副本,这与传递给它的投球手列表不同。因此,更改活动中的投球手列表不会更改适配器中的投球手列表。因此,在更改投球手列表后发出onNotifyDatasetChanged 是对适配器说您已更改适配器中的列表(即它是副本,尚未更改)。

因此必须更改投球手名单上的副本,然后发出onNotifyDatasetChanged。我的猜测是您没有正确实现上述内容。

因此,我几乎重新创建了您的代码并拥有一个可以工作的版本:-

  • 不使用操作栏,而是使用按钮来添加投球手。
  • LeagueID 不是由 anther Activity 调用并从 Intent Extra 中获取 LeagueID,而是硬编码。
  • 为方便起见,活动中包含了 ClickListener 接口。

活动(我称之为 BowlerActivity)

public class BowlerActivity extends AppCompatActivity {

    private BowlerAdapter mAdapter;
    private List<Bowler> bowlersList = new ArrayList<>();
    private RecyclerView recyclerView;
    private DatabaseHelper db;
    private Button addbowler;
    private EditText newbowler;
    private TextView leagueId, noBowlersView;
    private String savedLeagueId;
    Context mContext;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = this;
        addbowler = this.findViewById(R.id.addbowler); // For testing
        leagueId = this.findViewById(R.id.tvLeagueId);
        noBowlersView = this.findViewById(R.id.noBowlersView);
        recyclerView = this.findViewById(R.id.recycler_view);
        db = new DatabaseHelper(this);

        savedLeagueId = "0"; //<<<< HARD CODED rather than get from IntentExtra
        leagueId.setText(savedLeagueId);
        bowlersList = db.getAllBowlers(leagueId.getText().toString());
        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this);
        mAdapter = new BowlerAdapter(this,bowlersList);
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        //recyclerView.addItemDecoration(new MyDividerItemDecoration(this, LinearLayoutManager.VERTICAL, 16));
        recyclerView.setAdapter(mAdapter);

        addbowler.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showBowlerDialog(false, null, -1);
            }
        });

        recyclerView.addOnItemTouchListener(new RecyclerTouchListener(this, recyclerView, new ClickListener() {
            @Override
            public void onClick(View view, int position) {
                Toast.makeText(mContext,"You clicked me", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onLongClick(View view, int position) {
                Toast.makeText(mContext,"You long clicked me", Toast.LENGTH_SHORT).show();
                showActionsDialog(position);

            }
        }));
    }

    //Opens Dialog With Edit/Delete Options
    //Edit - 0
    //Delete - 0
    private void showActionsDialog(final int position) {
        CharSequence colors[] = new CharSequence[]{"Edit", "Delete"};

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Choose option");
        builder.setItems(colors, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (which == 0) {
                    showBowlerDialog(true, bowlersList.get(position), position);
                } else {
                    deleteBowler(position);
                }
            }
        });
        builder.show();
    }

    //Toggling List And Empty Bowler View
    private void toggleEmptyBowlers() {
        //You Can Check bowlerList.size() > 0

        if (db.getBowlersCount() > 0) {
            noBowlersView.setVisibility( View.GONE);
        } else {
            noBowlersView.setVisibility( View.VISIBLE);
        }
    }

    //Inserting New Bowler In The Database And Refreshing The List
    private void createBowler(String leagueId,  String bowlerName) {
        //Inserting Bowler In The Database And Getting Newly Inserted Bowler Id
        long id = db.insertBowler(leagueId, bowlerName);

        //Get The Newly Inserted Bowler From The Database
       bowlersList = db.getAllBowlers(leagueId);
       mAdapter.notifyDatasetChanged(bowlersList);
       //mAdapter.notifyDataSetChanged();
    }

    //Updating Bowler In The Database And Updating The Item In The List By Its Position
    private void updateBowler(String bowlerName, int position) {
        Bowler n = bowlersList.get(position);

        //Updating Bowler Text
        n.setLeagueId(savedLeagueId);
        n.setName(bowlerName);

        //Updating The Bowler In The Database
        db.updateBowler(n);

        //Refreshing The List
        bowlersList.set(position, n); //<<<<< does not change the bowlerlist in the adapter
        //mAdapter.notifyItemChanged(position); // Saying that nothing has changed
        mAdapter.notifyDatasetChanged(db.getAllBowlers(savedLeagueId)); //<<<<< rebuilds adapter bowler list
        toggleEmptyBowlers();
    }

    //Deleting Bowler From SQLite Database And Removing The Bowler Item From The List By Its Position
    private void deleteBowler(int position) {
        //Deleting The Bowler From The Database
        db.deleteBowler(bowlersList.get(position));


        //Removing The Bowler From The List
        bowlersList.remove(position);
        //mAdapter.notifyItemRemoved(position); // Saying that nothing has changed
        mAdapter.notifyDatasetChanged(db.getAllBowlers(savedLeagueId));
        toggleEmptyBowlers();
    }

    public interface ClickListener{
        void onClick(View view,int position);
        void onLongClick(View view,int position);
    }

    //Show Alert Dialog With EditText Options to Enter/Edit A League
    //When shouldUpdate = true, It Will Automatically Display Old Bowler Name And Change The Button Text To UPDATE
    private void showBowlerDialog(final boolean shouldUpdate, final Bowler bowler, final int position) {
        LayoutInflater layoutInflaterAndroid = LayoutInflater.from(getApplicationContext());
        View view = layoutInflaterAndroid.inflate(R.layout.dialog_bowler, null);

        AlertDialog.Builder alertDialogBuilderUserInput = new AlertDialog.Builder(BowlerActivity.this);
        alertDialogBuilderUserInput.setView(view);

        leagueId.setText(savedLeagueId);
        final EditText inputBowlerName = view.findViewById(R.id.etBowlerNameInput);
        TextView dialogTitle = view.findViewById(R.id.dialog_title);
        dialogTitle.setText(!shouldUpdate ? getString(R.string.lbl_new_bowler_title) : getString(R.string.lbl_edit_bowler_title));

        if (shouldUpdate && bowler != null) {
            leagueId.setText(bowler.getLeagueId());
            inputBowlerName.setText(bowler.getName());

        }
        alertDialogBuilderUserInput
                .setCancelable(false)
                .setPositiveButton(shouldUpdate ? "update" : "save", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialogBox, int id) {

                    }
                })
                .setNegativeButton("cancel",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialogBox, int id) {
                                dialogBox.cancel();
                            }
                        });

        final AlertDialog alertDialog = alertDialogBuilderUserInput.create();
        alertDialog.show();

        alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //Show Toast Message When No Text Is Entered
                if (TextUtils.isEmpty(inputBowlerName.getText().toString())) {
                    Toast.makeText(BowlerActivity.this, "Enter Bowler!", Toast.LENGTH_SHORT).show();
                    return;
                } else {
                    alertDialog.dismiss();
                }

                //Check If User Is Updating Bowler
                if (shouldUpdate && bowler != null) {

                    //Updating Bowler By Its Id
                    updateBowler(inputBowlerName.getText().toString(), position);

                } else {
                    //Creating New Bowler
                    createBowler(leagueId.getText().toString(), inputBowlerName.getText().toString());
                }
            }
        });
    }
}
  • 真正唯一的变化是使用onNotifyDatasetChanged(List&lt;Bowler&gt;) 方法而不是股票onNotifyDatabsetChanged()

BowlerAdapter

public class BowlerAdapter extends RecyclerView.Adapter<BowlerAdapter.MyViewHolder> {

    private Context context;
    private List<Bowler> bowlersList;

    public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView bowlerLeagueId;
        public TextView name;
        public TextView timestamp;


        public MyViewHolder(View view) {
            super(view);
            bowlerLeagueId = view.findViewById(R.id.tvLeagueId);
            name = view.findViewById(R.id.tvBowlerName);
            timestamp = view.findViewById(R.id.timestamp);
        }
    }


    public BowlerAdapter(Context context, List<Bowler> bowlersList) {
        this.context = context;
        this.bowlersList = bowlersList;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        int fakeid = android.R.layout.simple_list_item_1;
        int realid = R.layout.listview_boweler;

        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(realid, parent, false);

        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        Bowler bowler = bowlersList.get(position);

        holder.bowlerLeagueId.setText(bowler.getLeagueId());
        holder.name.setText(bowler.getName());

        //Formatting And Displaying Timestamp
        holder.timestamp.setText(formatDate(bowler.getTimestamp()));
    }

    @Override
    public int getItemCount() {
        return bowlersList.size();
    }

    //<<<<<<<<<< Added >>>>>>>>>>
    // This will get the actual bowler from the list
    public Bowler getItemAtPosition(int position) {
        return bowlersList.get(position);
    }

    //Formatting TimeStamp to 'EEE MMM dd yyyy (HH:mm:ss)'
    //Input  : 2018-05-23 9:59:01
    //Output : Wed May 23 2018 (9:59:01)
    private String formatDate(String dateStr) {
        try {
            SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = fmt.parse(dateStr);
            SimpleDateFormat fmtOut = new SimpleDateFormat("EEE MMM dd yyyy (HH:mm:ss)");
            return fmtOut.format(date);
        } catch (ParseException e) {
        }
        return "";
    }

    public void notifyDatasetChanged(List<Bowler> newbowlerlist) {
        bowlersList.clear();
        bowlersList.addAll(newbowlerlist);
        super.notifyDataSetChanged();
    }
}
  • 注意notifyDatasetChanged(List&lt;Bowler) 方法,它采用更改后的投球手列表并重建它使用的适配器副本,然后调用适配器的notfiydatasetChanged 方法。

  • 添加但未使用的是 getItemAtPosition 方法,该方法可用于从给定位置的适配器返回投球手 (这可用于规避更改活动的投球手列表副本).

数据库助手

这仅包括一些记录一些信息但其他方面未更改的更改(尽管添加了一些缺失的代码)。

public class DatabaseHelper extends SQLiteOpenHelper {

    public static final String DBNAME = "leagueapp.db";
    public static final int DBVERSION = 1;

    SQLiteDatabase mDB;

    public DatabaseHelper(Context context) {
        super(context, DBNAME, null, DBVERSION);
        mDB = this.getWritableDatabase();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(Bowler.CRTSQL);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    public long insertBowler(String leagueId, String bowlerName) {
        //Get Writable Database That We Want To Write Data Too
        SQLiteDatabase db = this.getWritableDatabase();

        Log.d("INSERTBOWLER","Number of bowlers in db = " + String.valueOf(DatabaseUtils.queryNumEntries(db,Bowler.TABLE_NAME)));

        ContentValues values = new ContentValues();
        //`id` and `timestamp` Will Be Inserted Automatically
        values.put(Bowler.COLUMN_LEAGUE_ID, leagueId);
        values.put(Bowler.COLUMN_NAME, bowlerName);

        //Insert Row
        long id = db.insertOrThrow( Bowler.TABLE_NAME, null, values );

        //Close Database Connection
        db.close();

        //Return Newly Inserted Row Id
        return id;
    }

    public Bowler getBowler(String leagueId) {
        //Get Readable Database If We Are Not Inserting Anything
        SQLiteDatabase db = this.getReadableDatabase();

        Cursor cursor = db.query(Bowler.TABLE_NAME,
                new String[]{Bowler.COLUMN_ID, Bowler.COLUMN_LEAGUE_ID, Bowler.COLUMN_NAME, Bowler.COLUMN_TIMESTAMP},
                Bowler.COLUMN_LEAGUE_ID + "=?",
                new String[]{String.valueOf(leagueId)}, null, null, null, null);

        if (cursor.moveToFirst()) {

            //Prepare Bowler Object
            Bowler bowler = new Bowler(
                    cursor.getLong(cursor.getColumnIndex(Bowler.COLUMN_ID)),
                    cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_LEAGUE_ID)),
                    cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_NAME)),
                    cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_TIMESTAMP)));

            //Close Database Connection
            cursor.close();
            return bowler;
        } else {return null;}
    }
    public List<Bowler> getAllBowlers(String leagueId) {
        List<Bowler> bowlers = new ArrayList<>();

        //Select All Query
        String selectQuery = "SELECT  * FROM " + Bowler.TABLE_NAME + " WHERE " + Bowler.COLUMN_LEAGUE_ID + " = '" + leagueId + "'" + " ORDER BY " +
                Bowler.COLUMN_TIMESTAMP + " DESC";

        Log.d("GETALLBOWLERS-SQL","SQL used = >>>>" +selectQuery + "<<<<");

        SQLiteDatabase db = this.getWritableDatabase();
        Cursor cursor = db.rawQuery(selectQuery, null);

        Log.d("GETALLBOWLERS-CNT","Number of rows retrieved = " + String.valueOf(cursor.getCount()));


        //Looping Through All Rows And Adding To The List
        if (cursor.moveToFirst()) {
            do {
                Bowler bowler = new Bowler();
                bowler.setId(cursor.getInt(cursor.getColumnIndex(Bowler.COLUMN_ID)));
                bowler.setLeagueId(cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_LEAGUE_ID)));
                bowler.setName(cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_NAME)));
                bowler.setTimestamp(cursor.getString(cursor.getColumnIndex(Bowler.COLUMN_TIMESTAMP)));
                bowlers.add(bowler);
            } while (cursor.moveToNext());
        }
        cursor.close();
        //Close Database Connection
        db.close();
        Log.d("GETALLBOWLERS-CNT","Number of elements in bowlerslist = " + String.valueOf(bowlers.size()));

        //Return Bowlers List
        return bowlers;
    }

    public int getBowlersCount() {
        String countQuery = "SELECT  * FROM " + Bowler.TABLE_NAME;
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.rawQuery(countQuery, null);

        int count = cursor.getCount();
        cursor.close();

        //Return The Count
        return count;
    }

    public int updateBowler(Bowler bowler) {
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(Bowler.COLUMN_LEAGUE_ID, bowler.getLeagueId());
        values.put(Bowler.COLUMN_NAME, bowler.getName());

        //Updating Row
        return db.update(Bowler.TABLE_NAME, values, Bowler.COLUMN_ID + " = ?",
                new String[]{String.valueOf(bowler.getId())});
    }

    public void deleteBowler(Bowler bowler) {
        SQLiteDatabase db = this.getWritableDatabase();
        db.delete( Bowler.TABLE_NAME, Bowler.COLUMN_ID + " = ?",
                new String[]{String.valueOf( bowler.getId())});
        db.close();
    }

    public int deleteBowlerChecked(Bowler bowler) {
        SQLiteDatabase db = this.getWritableDatabase();
        Log.d("DELETEBOWLER","Attempting to DELETE bowler " + bowler.getName());
        int rv = db.delete(Bowler.TABLE_NAME,Bowler.COLUMN_ID + "=?",
                new String[]{String.valueOf(bowler.getId())});
        if (rv < 1) {
            Log.d("DELETEBOWLER", "Bowler with an id of " + String.valueOf(bowler.getId()) + " was not deleted, as it didn't exist.");
        }
        return rv;
    }
}

RecyclerTouchListener

这个wad添加了,它可能和你的一样,也可能不一样。

public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener{

    private BowlerActivity.ClickListener clicklistener;
    private GestureDetector gestureDetector;

    public RecyclerTouchListener(Context context, final RecyclerView recycleView, final BowlerActivity.ClickListener clicklistener){

        this.clicklistener=clicklistener;
        gestureDetector=new GestureDetector(context,new GestureDetector.SimpleOnGestureListener(){
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return true;
            }

            @Override
            public void onLongPress(MotionEvent e) {
                View child=recycleView.findChildViewUnder(e.getX(),e.getY());
                if(child!=null && clicklistener!=null){
                    clicklistener.onLongClick(child,recycleView.getChildAdapterPosition(child));
                }
            }
        });
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        View child=rv.findChildViewUnder(e.getX(),e.getY());
        if(child!=null && clicklistener!=null && gestureDetector.onTouchEvent(e)){
            clicklistener.onClick(child,rv.getChildAdapterPosition(child));
        }

        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {

    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }

}

结果/测试

初始屏幕(空数据库):-

点击添加投球手按钮:-

Bowler B1 进入并点击保存:-

添加了更多投球手:-

Bowler B5 更新:-

Bowlers B1 和 B6 已删除:-

【讨论】:

  • 我已经修改了我上面显示的代码,但是我没有得到与你的截图相同的结果。当我单击保存按钮并返回 Bowler Listview 时,活动完全为空,我在上面添加了屏幕截图并修改了代码。
  • 我相信我已经在 .notifyDataSetChanged(bowlerList) 中隔离了这个问题,我正在调用 BowlersList.clear();。如果我对此发表评论,我将返回列表视图刷新并使用第一个投球手名称,直到刷新活动。当我取消注释时,活动会刷新,并且不会像我上面发布的屏幕截图那样显示任何内容。
  • 我想知道这是否是因为我只显示符​​合特定条件的记录。例如,如果 League Id =1,则 BowlersList 仅显示属于具有该 ID 的联盟的 Bowlers。我提到这一点的原因是,当我将新联赛添加到列表中时,此问题不存在。联盟没有按 ID 号过滤或显示。
  • @RobertVogl 尝试不使用过滤器(选择标准),如果可以解决它,然后检查过滤。也许使用断点,比如在 Bowlerlist.clear() 处运行调试,检查 newbowlerlist 包含的内容。交替添加 Log 语句并检查日志。
  • 我在 .clear() 处添加了一个断点,我可以清楚地看到新的投球手名称,但 Bowler n = B1(第一个投球手进入)。一旦到达.notifyDataSetChanged(),ArrayList size = 0。我确定这应该大于 0,否则它无法刷新列表,如果我没记错的话。日志在上面。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多