我一直在Android上开展个人项目,并遇到一个使用ListView的Activity的奇怪情况。问题的基础是我有一个项目列表,每个项目有2个按钮,编辑和删除。现在我正在实现删除按钮,它在功能上有效,但不能正确更新ListView。相反,它将刚刚删除的内容放在列表顶部。每当我重新开始那项活动时,它当然会刷新。
现在,在自定义BaseAdapter中检测到“删除”按钮,当我调用notifyDataSetChanged时,会发生上述情况,而不是删除现在删除的项目。如何正确更新适配器类中的列表?
我意识到对此有一些疑问,但我无法整合它们,我认为可行的解决方案并没有真正解释它们是如何工作的;我正在使用这个项目更多地了解Android应用程序开发,所以我更喜欢有一定程度解释的答案,尽管任何帮助当然都值得赞赏! 谢谢!
这是相关代码。请注意,这是一个未完成的项目,因此其中有一些未使用/不完整的内容。请忽略这些。
EditItemsActivity:
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();
Anup建议。
答案 0 :(得分:3)
在适配器的getView
方法中,您正在检查if (convertView == 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);
答案 1 :(得分: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();
}