Как удалить строку из ListView с помощью CursorAdapter
Я запустил небольшой проект для Android, чтобы заново изучить Android-разработку, и я уже застрял...
Я не знаю, как реализовать удаление элемента моего ListView
!
Вот проект: https://github.com/gdurelle/Listify
Прямо сейчас это стремится показать список списков элементов.
Я использую кастом CursorAdapter
чтобы показать мой список элементов, и у меня уже есть (некрасивая) кнопка уничтожения, но я не знаю, как заставить его удалить фактический элемент из списка (и базы данных).
Я использую ActiveAndroid для управления базой данных способом ActiveRecord.
Плюс: я не уверен, что использовать или не использовать getView()
, bindView()
и / или newView()
...
Я создал проблему, чтобы запомнить это и сослаться на этот вопрос здесь: https://github.com/gdurelle/Listify/issues/1
public class ListifyCursorAdapter extends CursorAdapter {
public String content;
public ListifyCursorAdapter(Context context, Cursor cursor) {
super(context, cursor, 0);
}
// The newView method is used to inflate a new view and return it, you don't bind any data to the view at this point.
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.element_line, parent, false);
}
// The bindView method is used to bind all data to a given view such as setting the text on a TextView.
@Override
public void bindView(View view, Context context, Cursor cursor) {
// Find fields to populate in inflated template
TextView tvBody = (TextView) view.findViewById(R.id.element_content);
// Extract properties from cursor
content = cursor.getString(cursor.getColumnIndexOrThrow("content"));
// Populate fields with extracted properties
tvBody.setText(content);
}
}
И в моей основной деятельности:
Cursor cursor = ListifyElement.fetchResultCursor();
adapter = new ListifyCursorAdapter(this, cursor);
listView.setAdapter(adapter);
Я думал, может быть, о:
Button delete_button = (Button) listView.findViewById(R.id.delete_button);
с чем-то вроде ListifyElement.load(ListifyElement.class, the_id_of_the_element).delete();
где the_id_of_the_element будет идентификатором БД элемента, полученного каким-либо образом из нажатия на кнопку delete_button в пользовательском интерфейсе...
ОБНОВЛЕНИЕ:
@Override
public void bindView(View view, Context context, final Cursor cursor) {
// Find fields to populate in inflated template
TextView tvBody = (TextView) view.findViewById(R.id.element_content);
// Extract properties from cursor
content = cursor.getString(cursor.getColumnIndexOrThrow("content"));
// Populate fields with extracted properties
tvBody.setText(content);
Button delete_button = (Button) view.findViewById(R.id.delete_button);
delete_button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
System.out.println(cursor.getColumnName(0)); // Id
System.out.println(cursor.getColumnName(1)); // ListifyContainer
System.out.println(cursor.getColumnName(2)); // content
System.out.println(cursor.getColumnIndexOrThrow("Id")); // 0
ListifyElement.load(ListifyElement.class, cursor.getColumnIndexOrThrow("Id")).delete();
notifyDataSetChanged();
}
});
Я получаю эту ошибку, когда нажимаю кнопку удаления:
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.gdurelle.listify.models.ListifyElement.delete()' on a null object reference
5 ответов
Контекстное меню относительно просто реализовать в виде списка. Оно (контекстное меню) активируется при длительном нажатии пункта. Мой совет заключается в том, чтобы добавить намерение к пункту меню, чтобы вы могли сохранить идентификатор элемента из своего пользовательского адаптера и использовать его для выполнения чего угодно.
public class MainActionBarTabListFragment extends ListFragment {
@Override
public void onActivityCreated(Bundle savedState) {
super.onActivityCreated(savedState);
registerForContextMenu(getListView());
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
String name = adapter2.getItem(info.position).get_name();
menu.setHeaderTitle(name);
MenuInflater inflater = this.getActivity().getMenuInflater();
inflater.inflate(R.menu.menulistitem, menu);
MenuItem mi = menu.findItem(R.id.action_context_delete);
Intent i = new Intent();
i.putExtra("id", adapter2.getItem(info.position).get_id());
mi.setIntent(i);
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_context_delete:
Intent i = item.getIntent();
if (i != null) {
Bundle b = i.getExtras();
if (b != null) {
int id = b.getInt("id");
Uri deleteIdUri = ContentUris.withAppendedId(
RidesDatabaseProvider.CONTENT_URI, id);
context.getContentResolver()
.delete(deleteIdUri, null, null);
return true;
}
}
}
return super.onContextItemSelected(item);
}
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:yourapp="http://schemas.android.com/apk/res-auto" >
<item
android:id="@+id/action_context_delete"
android:icon="@drawable/action_about"
android:orderInCategory="100"
android:showAsAction="ifRoom"
android:title="delete"
yourapp:showAsAction="ifRoom"/>
</menu>
Давайте начнем с самого начала, зачем вам нужен ActiveAndroid? Я предлагаю избегать таких вещей, ИМХО. Вы перепутали свою логику, адаптер не должен изменять вашу базу данных. Установите прослушиватель для адаптера (т. Е. IDeleteListener с одним методом onDeleteRequested(long rowId)). Далее вам нужно передать rowId, что-то вроде:
delete_button.setTag(cursor.getLong(0));
delete_button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
listener.onDeleteRequested((Long)v.getTag());
}
});
В вашем классе фрагмента / деятельности вы должны настроить слушателя на адаптер и работать с вашей базой данных. Я предлагаю вам использовать LoaderManager, он автоматически повторно запросит вашу базу данных при удалении и обработает жизненный цикл активности. Надеюсь, это поможет!
Я бы предложил вам использовать ArrayAdapter
вместо. Тогда вы просто используете ArrayList
(или любой другой массив) и отредактируйте его, и вызовите adapter.notifyDataSetChanged();
и содержание ListView
будет обновлять.
Объявить ArrayAdapter
как это:
ArrayAdapter<String> adapter = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_list_item_1, yourStringArray);
где переменная называется yourStringArray
это просто ArrayList
из String
s.
Затем добавьте адаптер к ListView
, как это:
yourListView.setAdapter(adapter);
Затем вы можете изменить содержимое списка, отредактировав yourStringArray
список и вызов adapter.notifyDataSetChanged();
, Вот простой пример:
list.add("Hello!");
adapter.notifyDataSetChanged();
Наконец, чтобы удалить выбранный элемент при нажатии кнопки, вы можете сделать что-то вроде этого:
int selectedItemIndex = 0;
yourArrayList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectedItemIndex = position;
}
});
yourDestroyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
yourStringArray.remove(selectedItemIndex);
adapter.notifyDataSetChanged();
}
});
Целый onCreate
Метод будет выглядеть примерно так:
// Called when the activity is created
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<String> yourStringArray = new ArrayList<>();
ArrayAdapter<String> adapter = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_list_item_1, yourStringArray);
int selectedItemIndex = 0;
ListView yourListView = (ListView) findViewById(R.layout.yourListViewID);
yourListView.setAdapter(adapter);
yourListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectedItemIndex = position;
}
});
yourDestroyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
yourStringArray.remove(selectedItemIndex);
adapter.notifyDataSetChanged();
}
});
}
Если вы хотите Button
в каждом ряду, вы должны добавить его в свой xml
который вы раздувать в newView()
, После этого вы должны установить OnClickListener
на ваш Button
внутри bindView()
, Что-то вроде того:
public void bindView(View view, Context context, Cursor cursor) {
// Find fields to populate in inflated template
TextView tvBody = (TextView) view.findViewById(R.id.element_content);
Button delete_button = (Button) view.findViewById(R.id.delete_button);
delete_button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v){
//As you're using ActiveAndroid
new Delete().from(ListfyElement.class).where("yourCondition=?",yourCondition).execute();
notifyDataSetChanged();
}
});
// Extract properties from cursor
content = cursor.getString(cursor.getColumnIndexOrThrow("content"));
// Populate fields with extracted properties
tvBody.setText(content);
}
Используйте код ниже, чтобы выполнить это:
ListView lv;
ArrayList<String> arr = new ArrayList<String>();
ArrayAdapter adapter;
int position;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.extra);
for(int i=0;i<5;i++)arr.add("Hi @ "+i);
lv = (ListView) findViewById(R.id.listViewBirthday);
lv.setOnItemLongClickListener(this);
adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1, arr);
lv.setAdapter(adapter);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo) {
// TODO Auto-generated method stub
super.onCreateContextMenu(menu, v, menuInfo);
MenuItem it1=menu.add("Delete");
}
@Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int p, long arg3)
{
position = p;
registerForContextMenu(lv);
return false;
}
@Override
public boolean onContextItemSelected(MenuItem item) {
// TODO Auto-generated method stub
if(item.getTitle().equals("Delete"))
{
arr.remove(position);
adapter.notifyDataSetChanged();
Toast.makeText(getBaseContext(), "deleted", Toast.LENGTH_SHORT).show();
}
return true;
}