8

我有ListViewCursorLoader。用戶可以打開ListView項目(打開另一個Fragment)或刪除項目。所有數據庫操作都是異步發生的,通常只需要幾分之一秒。但從技術上說,用戶可以刪除一個項目,然後在刪除回調和導致錯誤之前打開該項目。處理這個問題的最好方法是什麼?以下是我看到的選項。異步刪除ListView/RecyclerView項目的最佳做法

  1. 只是假設AsyncTask總是會發生的速度不夠快,以避免問題
  2. 執行UI線程上的數據庫操作
  3. 無效AsyncTaskListView(但是這會導致UI閃光所述AsyncTask

編輯期間)

  • 塊的用戶輸入以某種方式:我結束了使用RecyclerView,但直到我從數據庫中刪除項目後才能調用adapter.notifyItemRemoved(itemPos)

  • 回答

    3
    @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; 
        } 
    

    或使用RecyclerView刪除動畫。

    的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); 
          } 
         } 
        } 
    } 
    
    +0

    禁用該視圖會假定該項目不是也不會被綁定到另一個視圖,對嗎?你能指出我在RecyclerView中應該看到的關鍵方法嗎?這看起來像一個有趣的選擇,如果它不過度複雜。 – cambunctious

    +0

    這實際上超級簡單:)只需在我的答案中添加代碼即可。 – Andrew

    6

    你的情況最好的選擇將使用RecyclerView。因爲當你點擊刪除時,你可以撥打adapter.notifyItemRemoved(itemPos)。因此,您的RecyclerView中的動畫將刪除列表項,您不會擔心刪除操作結果。

    參見Creating Lists and Cards Android開發者教程:

    使用RecyclerView插件時,你有數據收集,其 元素在運行時改變基於用戶行爲或網絡事件。

    下面是一個例子:

    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); 
        } 
    } 
    
    +0

    不要忘記mDataset.remove(position)和notifyItemRangeChanged(position,mDataset.size())。如果沒有後者,刪除第一個項目直到列表爲空時會發生崩潰。 – Andrew

    +0

    如果我使用光標怎麼辦?我不能從數據集中刪除項目,直到我得到一個新的光標。 – cambunctious

    +0

    您不需要等待新的cusosr。請先從您的回收站查看項目。 NotifyItemRemoved正在接受作爲參數的位置。所以只需通過你點擊刪除按鈕的位置即可。我的意思是,在獲得新的遊標後,您不需要將notifyItemRemoved。當您點擊刪除按鈕時,首先更改優先級並調用notifyItemRemoved。 NotifyItemRemived不會查看您的數據,它只會從列表中刪除您的回收站視圖項目。然後你也可以從你的db中刪除你的數據@cambunctious –

    0

    如果您數據庫查詢沒有返回大量的數據的話就沒有問題做UI線程數據庫操作。

    +0

    在我的情況下,這恰好是*很可能是真實的,但我很猶豫要採用這種方法。數據量取決於用戶創建的項目數量。隨着應用程序的發展,數據量也會隨之增加。 – cambunctious

    相關問題