2

我一直在做一个 Android 的个人项目,但遇到了一个关于使用 ListView 的 Activity 的奇怪情况。问题的基础是我有一个项目列表,每个项目都有 2 个按钮,编辑和删除。现在我正在实现删除按钮,该按钮可以正常工作,但不能正确更新 ListView。相反,它将刚刚删除的内容放在列表顶部。每当我重新导航到该活动时,它当然会刷新。

现在在自定义 BaseAdapter 中检测到删除按钮,当我调用 notifyDataSetChanged 时,会发生上述情况,而不是删除现在删除的项目。如何正确更新适配器类中的列表?

我意识到对此存在一些问题,但我无法整合它们,我认为可能有效的解决方案并不能真正解释它们是如何工作的;我正在使用这个项目来更多地了解 Android 应用程序开发,所以我更希望得到一些解释的答案,尽管当然感谢任何帮助!谢谢!

这是相关的代码。请注意,这是一个未完成的项目,因此其中有一些未使用/不完整的东西。请忽略这些。

编辑项目活动:

package com.example.mybudget;

import java.util.List;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;

public class EditItemsActivity extends Activity implements OnGestureListener{

    private DatabaseHandler db;
    private List<DataPoint> dpList;
    private EditItemsAdapter adapter;
    private ListView lv;
    private GestureDetector gestureDetector;

    @SuppressLint("NewApi")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_edit_items);
        // Show the Up button in the action bar.
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) 
            getActionBar().setDisplayHomeAsUpEnabled(true);
        db = new DatabaseHandler(this);
        dpList = db.allDataThisMonth();
        lv = (ListView) findViewById(R.id.edititems);
        adapter = new EditItemsAdapter(this, R.id.edititems, dpList);
        lv.setAdapter(adapter);
        gestureDetector = new GestureDetector(getBaseContext(), this);

//      buttonDelete.setVisibility(View.GONE);
    }

    public void refreshList()
    {
        adapter.notifyDataSetChanged();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_edit_items, menu);
        return true;
    }


    @Override
    public boolean onDown(MotionEvent e) {
        // TODO Auto-generated method stub
        return false;
    }

    public void onDelete()
    {

    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
            float velocityY) 
    {
//      Log.d("Swipe", "" + velocityX + ", " + velocityY);
//      if(velocityX > 200 && velocityY < 50 && velocityY > -50)
//      {
//          buttonEdit.setVisibility(View.GONE);
//          buttonDelete.setVisibility(View.VISIBLE);
//      }
//      else if(velocityX < -200 && velocityY < 50 && velocityY > -50)
//      {
//          buttonDelete.setVisibility(View.GONE);
//          buttonEdit.setVisibility(View.VISIBLE);
//      }
        return false;
    }


    @Override
    public void onLongPress(MotionEvent e) {
        // TODO Auto-generated method stub

    }


    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
            float distanceY) {
        // TODO Auto-generated method stub
        return false;
    }


    @Override
    public void onShowPress(MotionEvent e) {
        // TODO Auto-generated method stub

    }


    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        // TODO Auto-generated method stub
        return false;
    }

}

这是适配器类:

package com.example.mybudget;

import java.text.NumberFormat;
import java.util.List;

import android.app.Activity;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.TextView;

public class EditItemsAdapter extends BaseAdapter implements OnClickListener{
    private List<DataPoint> dpList;
    private Activity activity;
    private DatabaseHandler db;

    public EditItemsAdapter(Activity a)
    {
        activity = a;
    }

    public EditItemsAdapter(Activity a, int textViewResourceId, List<DataPoint> dpList)
    {
        super();
        this.dpList = dpList;
        activity = a;
        db = new DatabaseHandler(activity);
    }

    public static class ViewHolder
    {
        public TextView item1;
        public TextView item2;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
        View v = convertView;
        //ViewHolder holder;
        NumberFormat format = NumberFormat.getCurrencyInstance();

        if (v == null)
        {
//          LayoutInflater vi = 
//                  (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            LayoutInflater vi = activity.getLayoutInflater();
            v = vi.inflate(R.layout.edit_grid_items, null);
//          holder = new ViewHolder();
//          holder.item1 = (TextView) v.findViewById(R.id.edit_item_name);
//          holder.item2 = (TextView) v.findViewById(R.id.edit_item_cost);
//          v.setTag(holder);
            TextView tv1 = (TextView)v.findViewById(R.id.edit_item_name);
            TextView tv2 = (TextView)v.findViewById(R.id.edit_item_cost);
            Button edit = (Button)v.findViewById(R.id.edit_item_button);
            Button delete = (Button)v.findViewById(R.id.delete_item_button);
            final DataPoint dp = dpList.get(position);
            tv1.setText(dp.getName());
            tv2.setText(Float.toString(dp.getCost()));
            delete.setOnClickListener(new OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    db.deleteRowByKey(dp);
                    ((EditItemsActivity) activity).refreshList();
                }
            });
        }
//      else
//          holder = (ViewHolder)v.getTag();
//      if(dp != null)
//      {
//          holder.item1.setText(dp.getName());
//          holder.item2.setText(format.format(dp.getCost()));
//      }
        return v;
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return dpList.size();
    }

    @Override
    public DataPoint getItem(int position) {
        // TODO Auto-generated method stub
        return dpList.get(position);
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return dpList.size();
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub

    }
}

编辑:解决方案涉及 Adam 提供的通货膨胀解释,但需要完全重新填充 dpList,即

dpList = db.allDataThisMonth();

阿努普建议的。

4

2 回答 2

3

在您getView的适配器方法中,您正在检查if (convertView == null),如果它为空,您正在膨胀一个新视图。如果它为 null,则您只是返回提供的非 null 视图。

convertView提供给该方法getView的是已经显示的缓存视图。你应该重复使用它(如果它是一个有效的视图 - 你的列表中可能有多个不同的视图),而不是夸大一个新的视图。您忘记更新相应位置的内容。

那么,如何解决呢?只需关闭您的if (v == null)充气后:

if (v == null)
{
    LayoutInflater vi = activity.getLayoutInflater();
    v = vi.inflate(R.layout.edit_grid_items, null);
}

编辑:正如 Anup 指出的那样,您还需要更新dpList变量,否则它将继续为给定位置返回相同的值。您可以在点击侦听器中执行此操作:

delete.setOnClickListener(new OnClickListener()
{
    @Override
    public void onClick(View v)
    {
        db.deleteRowByKey(dp);
        dpList.remove((Integer)v.getTag());
        ((EditItemsActivity) activity).refreshList();

    }
});
// Required so we know which index to remove from our dpList.
delete.setTag(position);
于 2013-05-31T04:58:04.027 回答
2

从您的代码中,我可以看到您的适配器由dplist. 当您使用删除一行时,db.deleteRowByKey(dp);您正在更新数据库,但您没有更新dplist.

您需要重新填充dplist以匹配数据库,然后才能notifyDataSetChanged()按预期工作。

一种简单的方法是将您的refreshList()功能更改为:

public void refreshList()
{
    //reload dpList so that it can sync up with the database
    dpList = db.allDataThisMonth();

    //now notify adapter that the data set has changed so that it can update itself.
    adapter.notifyDataSetChanged();
}
于 2013-05-31T04:57:38.097 回答