更新数据库sqlite使用内容提供程序时,为什么在recyclerview中的项位置会发生变化?

时间:2017-10-01 12:51:28

标签: android sqlite android-recyclerview android-contentprovider

我在recyclelerview中使用cursorloader更新我的sqlite数据库,我通过选中复选框来更新我的sqlite数据库,更新了值,但不知何故,视图变得一团糟。某些行也已检查但值仍为0,应该不检查。当我插入新行时也会发生这种情况。

这是我更新数据库的主要活动

public class MainActivity extends AppCompatActivity implements
    TaskAdapter.OnItemClickListener, LoaderManager.LoaderCallbacks<Cursor>{

private TaskAdapter mAdapter;
private FloatingActionButton floatingActionButton;

private ArrayList<Task> task = new ArrayList<>();

private static final int TASKS_LOADER_ID = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    mAdapter = new TaskAdapter(this);
    mAdapter.setOnItemClickListener(this);

    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    recyclerView.setHasFixedSize(true);
    recyclerView.setAdapter(mAdapter);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));

    floatingActionButton = (FloatingActionButton) findViewById(R.id.fab);


    /* Click events in floating action button */
    floatingActionButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent = new Intent(getApplicationContext(), AddTaskActivity.class);
            startActivity(intent);
        }
    });

    //initialize the loader
    getSupportLoaderManager().initLoader(TASKS_LOADER_ID, null, this);
}

@Override
protected void onResume() {
    super.onResume();
    Log.v("dipanggil", "dipanggil jka");
    // re-queries for all tasks
    getSupportLoaderManager().restartLoader(TASKS_LOADER_ID, null, this);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        Intent intent = new Intent(this, SettingsActivity.class);
        startActivity(intent);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

/* Click events in RecyclerView items */
@Override
public void onItemClick(View v, int position) {
    //TODO: Handle list item click event
    Intent intent = new Intent(this, TaskDetailActivity.class);
    /*b.putLong("ID", task.get(position).getId());
    b.putString("DESCRIPTION", task.get(position).getDescription());
    b.putInt("PRIORITY", task.get(position).getPriority());
    b.putInt("COMPLETE", task.get(position).getComplete());
    b.putLong("DUEDATE", task.get(position).getDueDateMillis());*/
    intent.putExtra("ID", String.valueOf(task.get(position).getId()));

    startActivity(intent);
    Log.v("testti", ""+v.getTag()+" apakah sama "+task.get(position).getId());
}

/* Click events on RecyclerView item checkboxes */
@Override
public void onItemToggled(boolean active, int position) {
    //TODO: Handle task item checkbox event
    ContentValues values = new ContentValues();

    String stringId = String.valueOf(task.get(position).getId());
    Log.v("test = ", ""+task.get(position).getId());

    Uri uri = DatabaseContract.CONTENT_URI;
    uri = uri.buildUpon().appendPath(stringId).build();

    if(active) {
        Log.v("test","tersentuh");
        //values.put(DatabaseContract.TaskColumns.IS_COMPLETE, 1);
        values.put(DatabaseContract.TaskColumns._ID, task.get(position).getId());
        values.put(DatabaseContract.TaskColumns.DESCRIPTION, task.get(position).getDescription());
        values.put(DatabaseContract.TaskColumns.IS_PRIORITY, task.get(position).getPriority());
        values.put(DatabaseContract.TaskColumns.IS_COMPLETE, 1);
        values.put(DatabaseContract.TaskColumns.DUE_DATE, task.get(position).getDueDateMillis());
        getContentResolver().update(uri,
                values,
                null,
                null);
    }else{
        Log.v("test","tidak tersentuh");
        values.put(DatabaseContract.TaskColumns._ID, task.get(position).getId());
        values.put(DatabaseContract.TaskColumns.DESCRIPTION, task.get(position).getDescription());
        values.put(DatabaseContract.TaskColumns.IS_PRIORITY, task.get(position).getPriority());
        values.put(DatabaseContract.TaskColumns.IS_COMPLETE, 0);
        values.put(DatabaseContract.TaskColumns.DUE_DATE, task.get(position).getDueDateMillis());
        getContentResolver().update(uri,
                values,
                null,
                null);
    }
    // re-queries for all tasks
    //mAdapter.notifyDataSetChanged();
    getSupportLoaderManager().restartLoader(TASKS_LOADER_ID, null, this);
}

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {

    return new AsyncTaskLoader<Cursor>(this) {

        // Initialize a Cursor, this will hold all the task data
        Cursor mTaskData = null;

        // onStartLoading() is called when a loader first starts loading data
        @Override
        protected void onStartLoading() {
            if (mTaskData != null) {
                // Delivers any previously loaded data immediately
                deliverResult(mTaskData);
            } else {
                // Force a new load
                forceLoad();
            }
        }

        @Override
        public Cursor loadInBackground() {
            try {
                return getContentResolver().query(DatabaseContract.CONTENT_URI,
                        null,
                        null,
                        null,
                        DatabaseContract.DEFAULT_SORT);

            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        public void deliverResult(Cursor data) {
            mTaskData = data;
            super.deliverResult(data);
        }
    };

}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {

    while(data.moveToNext()){
        long id = data.getLong(data.getColumnIndex(DatabaseContract.TaskColumns._ID));
        String description = data.getString(data.getColumnIndex(DatabaseContract.TaskColumns.DESCRIPTION));
        long date = data.getLong(data.getColumnIndex(DatabaseContract.TaskColumns.DUE_DATE));
        int priority = data.getInt(data.getColumnIndex(DatabaseContract.TaskColumns.IS_PRIORITY));
        int complete = data.getInt(data.getColumnIndex(DatabaseContract.TaskColumns.IS_COMPLETE));

        try{
            Task tasks = new Task(data);
            task.add(tasks);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    mAdapter.swapCursor(data);
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
    mAdapter.swapCursor(null);
}

}

这是recyclerview适配器

public class TaskAdapter extends RecyclerView.Adapter<TaskAdapter.TaskHolder> {

/* Callback for list item click events */
public interface OnItemClickListener {
    void onItemClick(View v, int position);

    void onItemToggled(boolean active, int position);
}

/* ViewHolder for each task item */
public class TaskHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    public TaskTitleView nameView;
    public TextView dateView;
    public ImageView priorityView;
    public CheckBox checkBox;

    public TaskHolder(View itemView) {
        super(itemView);

        nameView = (TaskTitleView) itemView.findViewById(R.id.text_description);
        dateView = (TextView) itemView.findViewById(R.id.text_date);
        priorityView = (ImageView) itemView.findViewById(R.id.priority);
        checkBox = (CheckBox) itemView.findViewById(R.id.checkbox);

        itemView.setOnClickListener(this);
        checkBox.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (v == checkBox) {
            completionToggled(this);
        } else {
            postItemClick(this);
        }
    }
}

private Cursor mCursor;
private OnItemClickListener mOnItemClickListener;
private Context mContext;

public TaskAdapter(Context mContext) {
    this.mContext = mContext;
}

public void setOnItemClickListener(OnItemClickListener listener) {
    mOnItemClickListener = listener;
}

private void completionToggled(TaskHolder holder) {
    if (mOnItemClickListener != null) {
        mOnItemClickListener.onItemToggled(holder.checkBox.isChecked(), holder.getAdapterPosition());
    }
}

private void postItemClick(TaskHolder holder) {
    if (mOnItemClickListener != null) {
        mOnItemClickListener.onItemClick(holder.itemView, holder.getAdapterPosition());
    }
}

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

    return new TaskHolder(itemView);
}

@Override
public void onBindViewHolder(TaskHolder holder, int position) {

    //TODO: Bind the task data to the views
    // Indices for the _id, description, and priority columns
    int idIndex = mCursor.getColumnIndex(DatabaseContract.TaskColumns._ID);
    int descriptionIndex = mCursor.getColumnIndex(DatabaseContract.TaskColumns.DESCRIPTION);
    int isCompleteIndex = mCursor.getColumnIndex(DatabaseContract.TaskColumns.IS_COMPLETE);
    int isPriorityIndex = mCursor.getColumnIndex(DatabaseContract.TaskColumns.IS_PRIORITY);
    int dueDateIndex = mCursor.getColumnIndex(DatabaseContract.TaskColumns.DUE_DATE);

    //move cursor to wanted data
    mCursor.moveToPosition(position);

    // Determine the values of the wanted data
    final int id = mCursor.getInt(idIndex);
    String description = mCursor.getString(descriptionIndex);
    int isComplete = mCursor.getInt(isCompleteIndex);
    int isPrior = mCursor.getInt(isPriorityIndex);
    long dueDate = mCursor.getLong(dueDateIndex);
    Log.v("adapter", " "+DateUtils.getRelativeTimeSpanString(mContext, dueDate)+" "+dueDate);
    CharSequence date = DateUtils.getRelativeTimeSpanString(mContext, dueDate);

    holder.itemView.setTag(id);

    //determine whether to show date or not
    if(dueDate != Long.MAX_VALUE){
        holder.dateView.setVisibility(View.VISIBLE);
        holder.dateView.setText(date);
    }else{
        holder.dateView.setVisibility(View.GONE);
    }
    //determine the priority icon
    if(isPrior == 0){
        holder.priorityView.setImageResource(R.drawable.ic_not_priority);
    }else{
        holder.priorityView.setImageResource(R.drawable.ic_priority);
    }
    //determine the text color and description
    holder.nameView.setText(description);
    holder.nameView.setState(isComplete);

    if(isComplete == 1){
        holder.checkBox.setChecked(true);
        holder.nameView.setState(isComplete);
    }

    //to chek if due date has passed or not
    Calendar now = Calendar.getInstance();
    Calendar tasksDate = Calendar.getInstance();
    tasksDate.setTimeInMillis(dueDate);
    int result = now.compareTo(tasksDate);

    if(result >= 0){
        holder.nameView.setState(2);
    }
    else if(result < 0){
        holder.nameView.setState(0);
    }


}

@Override
public int getItemCount() {
    return (mCursor != null) ? mCursor.getCount() : 0;
}

/**
 * Retrieve a {@link Task} for the data at the given position.
 *
 * @param position Adapter item position.
 *
 * @return A new {@link Task} filled with the position's attributes.
 */
public Task getItem(int position) {
    if (!mCursor.moveToPosition(position)) {
        throw new IllegalStateException("Invalid item position requested");
    }

    return new Task(mCursor);
}

@Override
public long getItemId(int position) {
    return getItem(position).id;
}

public Cursor swapCursor(Cursor cursor) {
    if (mCursor == cursor) {
        return null; // bc nothing has changed
    }
    Cursor temp = mCursor;
    this.mCursor = cursor; // new cursor value assigned

    //check if this is a valid cursor, then update the cursor
    if (cursor != null) {
        this.notifyDataSetChanged();
    }
    return temp;
}

}

如何解决这个问题?谢谢!

1 个答案:

答案 0 :(得分:0)

在您的代码的以下部分中,您还没有提供其他条件。

if (isComplete == 1){
    holder.checkBox.setChecked(true);
    holder.nameView.setState(isComplete);
}

您应该处理其他条件以取消选中该复选框,因为RecyclerView使用旧视图。

holder.checkBox.setChecked(isComplete == 1);
holder.nameView.setState(isComplete);

此外,您应该在重新填充列表之前清除旧项目。