I have a ListView
with a CursorLoader
. The user can open ListView
items (open another Fragment
) or delete items. All database actions occur asynchronously and usually it takes a fraction of a second. But technically the user could delete an item and then open the item before the deletion callback and cause and error. What’s the best way to handle this? Here are the options I see.
- Just assume that the
AsyncTask
will always happen quickly enough to avoid a problem - Do the database operation on the UI thread
- Invalidate the
ListView
before theAsyncTask
(but this would cause a flash in the UI) - Block user input somehow during the
AsyncTask
Edit: I ended up using RecyclerView
but I can’t call adapter.notifyItemRemoved(itemPos)
until after I have deleted the item from the database.
Best option in your case will be using RecyclerView
. Because when you clicked delete you can call adapter.notifyItemRemoved(itemPos)
. So the list item will be removed with animation from your RecyclerView
and you will not worry about the delete operation result.
See the Android Developer tutorial on Creating Lists and Cards:
Use the
RecyclerView
widget when you have data collections whose
elements change at runtime based on user action or network events.
Here is an example:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> implements View.OnClickListener, View.OnLongClickListener {
private ArrayList<String> mDataset;
private static Context sContext;
public MyAdapter(Context context, ArrayList<String> myDataset) {
mDataset = myDataset;
sContext = context;
}
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_text_view, parent, false);
ViewHolder holder = new ViewHolder(v);
holder.mNameTextView.setOnClickListener(MyAdapter.this);
holder.mNameTextView.setTag(holder);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.mNameTextView.setText(mDataset.get(position));
}
@Override
public int getItemCount() {
return mDataset.size();
}
@Override
public void onClick(View view) {
ViewHolder holder = (ViewHolder) view.getTag();
if (view.getId() == holder.mNameTextView.getId()) {
**//Important !!!**
notifyItemRemoved(getPosition());
// Make your database operation also here
}
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView mNumberRowTextView;
public TextView mNameTextView;
public ViewHolder(View v) {
super(v);
mNameTextView = (TextView) v.findViewById(R.id.nameTextView);
}
}
Answer:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View itemView = convertView != null ? convertView : /* inflate view */;
itemView.findViewById(R.id.delete_button).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
itemView.setEnabled(false);
// OR view.setClickable(false);
}
});
return itemView;
}
Or use RecyclerView with removal animation.
build.gradle
compile 'com.android.support:recyclerview-v7:23.2.1'
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
</RelativeLayout>
my_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/value_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button
android:id="@+id/delete_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Delete"/>
</LinearLayout>
MainActivity.java
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<String> items = new ArrayList<>(
Arrays.asList("first", "second", "third"));
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView myRecyclerView = (RecyclerView)
findViewById(R.id.my_recycler_view);
myRecyclerView.setAdapter(new MyAdapter());
}
private class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new MyViewHolder(LayoutInflater.from(MainActivity.this)
.inflate(R.layout.my_item, parent, false));
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.bind(position);
}
@Override
public int getItemCount() {
return items.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
private TextView valueTextView;
private Button deleteButton;
public MyViewHolder(View itemView) {
super(itemView);
valueTextView = (TextView) itemView.findViewById(R.id.value_text);
deleteButton = (Button) itemView.findViewById(R.id.delete_button);
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = (int) v.getTag();
items.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, items.size());
}
});
}
public void bind(int position) {
valueTextView.setText(items.get(position));
deleteButton.setTag(position);
}
}
}
}
Answer:
if your database query is not returning lot of data then there is no issue to do database operations on UI thread.
Tags: androidandroid, asynchronous, list, listview, view