使用更改的数据集删除了错误的列表视图属性

时间:2014-07-18 01:42:51

标签: android android-listview

我刚刚实现了此滑动删除solution

我从Rails API(我自己的)中显示ListView中的数据,并使用滑动从ListView中删除项目,并进行网络调用从数据库中删除项目。我将listview中每个项目的ID放在隐藏的TextView中,并在发送请求时拉出该ID,以便服务器端知道要删除的项目:

// all in onCreate()
SwipeDismissListViewTouchListener touchListener = 
                new SwipeDismissListViewTouchListener(
                        listView,
                        new SwipeDismissListViewTouchListener.DismissCallbacks() {
                            @Override
                            public boolean canDismiss(int position) {
                                return true;
                            }

                            @Override
                            public void onDismiss(ListView listView, int[] reverseSortedPositions) {
                                for (int position : reverseSortedPositions) {

                                    TextView listItemId = (TextView) findViewById(R.id.list_item_id);

                                    String deleteId = listItemId.getText().toString();

                                    //volley delete call
                                    deleteListItem(deleteId);

                                    shoppingListItems.remove(listAdapter.getItem(position));

                                }

                                listAdapter.notifyDataSetChanged();
                            }
                        });

        listView.setOnTouchListener(touchListener);

以下是截击:

public void deleteListItem(String item_id) {

        String deleteUrl = "http://polar-beach-6028.herokuapp.com/api/v1/list_items/" + item_id;

        JsonObjectRequest deleteRequest = new JsonObjectRequest(Request.Method.DELETE, deleteUrl, null,
                new Response.Listener<JSONObject>() {
                    @Override public void onResponse(JSONObject response) {
                        try {
                            if (response.getBoolean("success")) {
                                Toast.makeText(getApplicationContext(), "List item deleted.", Toast.LENGTH_SHORT).show();
                            }
                        } catch (Exception e) {
                            Log.d("Error.Response", e.toString());
                            Toast.makeText(getApplicationContext(), "Could not delete list item.", Toast.LENGTH_LONG).show();
                        }
                    }
                },
                new Response.ErrorListener() {
                    @Override public void onErrorResponse(VolleyError error) {
                        Log.d("Error.response", error.toString());
                        Toast.makeText(getApplicationContext(), "Could not delete list item.", Toast.LENGTH_LONG).show();
                    }
                }) {
                @Override
                public Map<String, String> getHeaders() throws AuthFailureError {
                    HashMap<String, String> headers = new HashMap<String, String>();
                    headers.put("Content-Type",  "application/json");
                    headers.put("auth_token", mPreferences.getString("AuthToken", "") );
                    return headers;
                }
        };

        AppController.getInstance().addToRequestQueue(deleteRequest);
    }

列表视图中项目的布局:

<?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="match_parent"
    android:background="@color/feed_bg"
    android:orientation="vertical" >

        <TextView
        android:id="@+id/list_item_id"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:visibility="gone" />

   <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"

        android:layout_marginLeft="@dimen/feed_item_margin"
        android:layout_marginRight="@dimen/feed_item_margin"
        android:layout_marginTop="@dimen/feed_item_margin"
        android:background="@drawable/bg_parent_rounded_corner"
        android:orientation="vertical"
        android:paddingBottom="@dimen/feed_item_padding_top_bottom"
        android:paddingTop="@dimen/feed_item_padding_top_bottom" >

       <TextView
            android:id="@+id/product"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="5dp"
            android:paddingLeft="@dimen/feed_item_status_pad_left_right"
            android:paddingRight="@dimen/feed_item_status_pad_left_right"
            android:paddingTop="@dimen/feed_item_status_pad_top" />

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:paddingLeft="@dimen/feed_item_padding_left_right"
            android:paddingRight="@dimen/feed_item_padding_left_right" >

            <com.android.volley.toolbox.NetworkImageView
                android:id="@+id/itemImg"
                android:layout_width="@dimen/feed_item_vendor_pic_width"
                android:layout_height="@dimen/feed_item_vendor_pic_height"
                android:scaleType="fitCenter" >
            </com.android.volley.toolbox.NetworkImageView>


        </LinearLayout>

        <TextView
            android:id="@+id/store_name"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="5dp"
            android:paddingLeft="@dimen/feed_item_status_pad_left_right"
            android:paddingRight="@dimen/feed_item_status_pad_left_right"
            android:paddingTop="@dimen/feed_item_status_pad_top" />

    </LinearLayout>

</LinearLayout>

它在第一次删除时效果很好,但是在数据集更改后,网络调用(使用Volley)开始发送错误listItemId的请求。结果是错误的列表项被删除,并且当列表被删除时,我最终在服务器端出现错误,因为Volley正在发送已经被错误删除的项的删除请求。我不确定为什么会这样,有什么帮助吗?如果它有帮助,我很乐意发布其他代码,但为了简洁,我会将其留在此处。

更新

这是我的父xml布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:background="#ffffff">

    <ListView
        android:id="@+id/shopping_list_show"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:divider="@null"
        android:dividerHeight="1dp"
        android:cacheColorHint="#00000000"/>

</LinearLayout>

1 个答案:

答案 0 :(得分:2)

以下电话可能是罪魁祸首:

TextView listItemId = (TextView) findViewById(R.id.list_item_id);

如果没有指定应该查找R.id.list_item_id的位置,您可以尝试在活动的布局中找到它 - 而不是在listview项目的布局中找到它。

根据您的描述,执行时您应该面对NullPointerException

String deleteId = listItemId.getText().toString();

但是,由于您没有报告NPE,我怀疑您的活动布局中有一个ID为R.id.list_item_id的TextView。


您需要访问“走了多少”&#39; textview(保持项目ID)是列表项视图。因此,让我们尝试定制您从中获得的代码 - here

您正在使用的回调接口是:

public interface DismissCallbacks {

    // Called to determine whether the given position can be dismissed.
    boolean canDismiss(int position);

    // Called when the user has indicated they she would like to dismiss 
    // one or more list item positions.
    void onDismiss(ListView listView, int[] reverseSortedPositions);
}

正如您所看到的,它并不能为您提供所需的一切。让我们解决此问题以返回所有相关信息。编辑将进入SwipeDismissListViewTouchListener.java(第104行):

public interface DismissCallbacks {

    // Called to determine whether the given position can be dismissed.
    boolean canDismiss(int position);

    // Called when the user has indicated they she would like to dismiss 
    // one or more list item positions.
    // Item ids are also returned.
    void onDismiss(ListView listView, int[] reverseSortedPositions, String[] itemIds);
}

PendingDismissData包含要解除的列表项的View和列表position。我们可以像这样提取item id

修改performDismiss(View, int)中的方法SwipeDismissListViewTouchListener

public void onAnimationEnd(Animator animation) {
    --mDismissAnimationRefCount;
    if (mDismissAnimationRefCount == 0) {
         // No active animations, process all pending dismisses.
         // Sort by descending position
         Collections.sort(mPendingDismisses);

         int[] dismissPositions = new int[mPendingDismisses.size()];
---->>>  String[] itemIds = new String[mPendingDismisses.size()];

         for (int i = mPendingDismisses.size() - 1; i >= 0; i--) {
             dismissPositions[i] = mPendingDismisses.get(i).position;

             // The view that holds the textview
             View dView = mPendingDismisses.get(i).view;

             // Find the textview in `dView`
             TextView listItemId = (TextView) dView.findViewById(R.id.list_item_id);

             // Add id to the array
---->>>      itemIds[i] = listItemId.getText().toString();
         }

         // Include the ids in the callback
         mCallbacks.onDismiss(mListView, dismissPositions, itemIds);

         ......
         ......

您的实施也会发生变化:

@Override
public void onDismiss(ListView listView, int[] reverseSortedPositions, String[] itemIds) {
    for (int i = 0; i < reverseSortedPositions.length; i++) {
        //volley delete call
        deleteListItem(itemIds[i]);

        shoppingListItems.remove(listAdapter.getItem(reverseSortedPositions[i]));
    }

    listAdapter.notifyDataSetChanged();
}

如果这仍然无法解决您的问题,请发布您的适配器代码。您如何为隐藏的textview分配/更新值可能存在问题。

注意:最好以另一种方式包含项目ID - 这并不需要您使用额外的textview。也许,您可以将商品ID设置为convertView的标签,并在SwipeDismissListViewTouchListener中访问它?