无法消除ListView中的视图

时间:2014-05-03 19:53:41

标签: android android-listview android-arrayadapter layout-inflater

我的ListView有几个问题。我将首先通过解释ListView的目标来解释我的问题,然后通过展示一些代码和图像来逐步解释。在页面的底部,我有与ListView相关的3个类的完整代码。

此ListView用于修改一系列公交车站。每行包含一个TextView,其中包含公交车站的名称和Button以消除它。如果用户点击TextView,则此视图将替换为新布局。在这个新布局中,有一个EditText用于插入一个新旧公交车站的名称,该公交车站将与旧公交车站交换。 EditText旁边有一个按钮,用于完成操作。

问题:

  • 第一个问题:如果我尝试从UI中删除原始TextView,我也会删除所选内容(来自UI)下的行。这里有几张图片。 在此之前,我点击:enter image description here

之后我点击TextView :(应该有最后一行,包含Crocetta,但它已被删除,我不知道它何时发生,原因是什么){ {0}}

更新:我忘了说当您点击确定按钮时,ListView变为第一张图片中的原样。即我可以看到似乎被淘汰的元素。

使用新布局管理视图替换的代码如下:

    ViewGroup parent = (ViewGroup) ((TextView)v).getParent();
    int index = parent.indexOfChild((TextView)v);   
    parent.removeView((TextView)v);

    final LinearLayout nuovoLiInserimento = (LinearLayout) li.inflate(R.layout.edit_text_modifica_fermata, parent, false);
    final AutoCompleteTextView nuovaFermata = (AutoCompleteTextView) nuovoLiInserimento.findViewById(R.id.edtModificaFermataInModificaLinea);
    Button confermaModificaFermata = (Button) nuovoLiInserimento.findViewById(R.id.btnModificaFermataInModificaLinea);
    nuovaFermata.setAdapter(new ArrayAdapter<String>(context,android.R.layout.simple_dropdown_item_1line, caricaFermate()));
    nuovaFermata.setText(fermataPrecedente);

    [...]

    parent.addView(nuovoLiInserimento, index);
  • 第二个问题:当我点击Elimina Button时会发生这种情况,其目的是删除它所在的行。我从fermateArrayList中删除了包含ListView数据的数据,然后调用notifyDataSetChanged。当程序稍后进入getView时,我收到以下错误:

    05-03 19:26:12.684: E/AndroidRuntime(1818): FATAL EXCEPTION: main 05-03 19:26:12.684: E/AndroidRuntime(1818): java.lang.IndexOutOfBoundsException: Invalid index 3, size is 3

因为getView被调用的时间比所需要的多一倍,所以它会搜索我删除的fermate中的元素。如何避免?

这是一段代码:

private void eliminaFermata(View v){
    Toast.makeText(context, "elimina", Toast.LENGTH_LONG).show();       
    LinearLayout parent = (LinearLayout)((Button) v).getParent();
    TextView busStop = (TextView)(parent).findViewById(textViewDaCompletare);
    fermate.remove(fermate.indexOf(busStop.getText().toString()));
    this.notifyDataSetChanged();
}

最后,我发布了3个类的代码:包含ListViewArrayAdapter的代码和实现OnClickListener的{​​{1}}的代码。此外,我发布了在这个类中膨胀的xml文件。

包含ListView的类

TextView

扩展ArrayAdapter的类

    package fragments;

import [...]

public class FragmentModificaLinea extends Fragment {

private Button btnModificaLinea = null;
private Button btnConfermaModifica = null;
private AutoCompleteTextView edtModificaLinea = null;
private ArrayList<String> contenitoreLinee;
private ListView listView;
@SuppressWarnings("unused")
private static final String TAG = FragmentModificaLinea.class.getSimpleName();


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_modifica_linea, container, false);
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    btnModificaLinea = (Button) getView().findViewById(R.id.btnModificaLinea);
    edtModificaLinea = (AutoCompleteTextView) getView().findViewById(R.id.edtModificaLinea);
    contenitoreLinee = new ArrayList<String>();
    caricaLinee();
    edtModificaLinea.setAdapter(new ArrayAdapter<String>(getActivity(),android.R.layout.simple_dropdown_item_1line, contenitoreLinee));
    listView = (ListView) getView().findViewById(R.id.listViewModificaLinea);
    btnConfermaModifica = (Button) getView().findViewById(R.id.btnConfermaModifica);

    btnModificaLinea.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            if(!edtModificaLinea.getText().toString().matches(""))
                if(contenitoreLinee.contains(edtModificaLinea.getText().toString())){
                    listView.setAdapter(new AdapterModificaLinea(getActivity(), R.layout.elemento_modifica_linea,
                            R.id.txtCambiaFermata, caricaFermate(edtModificaLinea.getText().toString().split(" Cod: ")[1])));
                    listView.setVisibility(ListView.VISIBLE);
                }else Toast.makeText(getActivity(), "Inserire una delle linee suggerite.", Toast.LENGTH_LONG).show();
            else Toast.makeText(getActivity(), "Inserire il nome della linea", Toast.LENGTH_LONG).show();
        }
    });
}

private void caricaLinee(){
    // I get the local database.
    DatabaseLocale db = new DatabaseLocale(getActivity());
    SQLiteDatabase dbLeggibile = db.getReadableDatabase();

    // Execute the query.
    Cursor cursore = dbLeggibile.rawQuery("SELECT " + DatabaseLocale.getTagNomeLinea() + " || ' Cod: ' || " + DatabaseLocale.getTagCodiceLinea()
            + " AS linea FROM " + DatabaseLocale.getTableNameLinea(), null);
    while(cursore.moveToNext()){
        contenitoreLinee.add(cursore.getString(0));
    }

    // Close connections.
    cursore.close();
    db.close();
}

private ArrayList<String> caricaFermate(String CodLinea){
    ArrayList<String> listaDelleFermate = new ArrayList<String>();

    // I get the local database.
    DatabaseLocale db = new DatabaseLocale(getActivity());
    SQLiteDatabase dbLeggibile = db.getReadableDatabase();

    Cursor fermate = dbLeggibile.rawQuery("SELECT f." + DatabaseLocale.getTagNomeFermata() + 
            " FROM " + DatabaseLocale.getTableNameTratta() + " t JOIN " + DatabaseLocale.getTableNameFermata() + " f "
            + "ON f." + DatabaseLocale.getTagCodiceFermata() + " = t." + DatabaseLocale.getTagCodiceFermata()
            + " WHERE " + DatabaseLocale.getTagCodiceLinea() + " = '" + CodLinea + "'", null);

    while(fermate.moveToNext()){
        // Successiva - NomeFermata
        listaDelleFermate.add(fermate.getString(0));        
    }
    fermate.close();
    db.close();

    return listaDelleFermate;
}

}

实现OnClickListener的类

    package listViewModificaLinea;

import [...]

public class AdapterModificaLinea extends ArrayAdapter<String> {

Context context;
int layoutResourceId;   
int textViewDaCompletare;   
ArrayList<String> fermate = null;
private LayoutInflater li = null;

public AdapterModificaLinea(Context context, int resource,
        int textViewResourceId, List<String> objects) {
    super(context, resource, textViewResourceId, objects);
    this.context = context;
    layoutResourceId = resource;
    textViewDaCompletare = textViewResourceId;
    fermate = new ArrayList<String>(objects);   
    li = ((LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE));
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    TextView text = null;
    Button btn = null;
    if(convertView == null){
        convertView = li.inflate(layoutResourceId, null);
    }
    text = (TextView) convertView.findViewById(textViewDaCompletare);
    // If I delete an element from fermate, it looks however for it and I get outofbound, why?
    String fermata = fermate.get(position);
    text.setText(fermata);
    // If I click on the textView, I exchange with the new layout
    text.setOnClickListener(new onClickListenerPerTextViewFermata(context, textViewDaCompletare));

    btn = (Button) convertView.findViewById(R.id.btnEliminaFermataModificaLinea);
    btn.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            eliminaFermata(v);
        }
    });

    return convertView;
}

private void eliminaFermata(View v){
    Toast.makeText(context, "elimina", Toast.LENGTH_LONG).show();       
    LinearLayout parent = (LinearLayout)((Button) v).getParent();
    TextView busStop = (TextView)(parent).findViewById(textViewDaCompletare);
    fermate.remove(fermate.indexOf(busStop.getText().toString()));
    this.notifyDataSetChanged();
}


}

elemento_modifica_linea.xml

    package listViewModificaLinea;

import [...]

public class onClickListenerPerTextViewFermata implements View.OnClickListener{

private Context context = null;
private LayoutInflater li = null;
private int textViewDaCompletare = 0;

public onClickListenerPerTextViewFermata(Context context, int textViewResourceId){
    this.context = context;
    li = ((LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE));
    this.textViewDaCompletare = textViewResourceId;
}

@Override
public void onClick(View v) {

    String fermataPrecedente = ((TextView)v).getText().toString();  
    ViewGroup parent = (ViewGroup) ((TextView)v).getParent(); // parent
    int index = parent.indexOfChild((TextView)v);       
    parent.removeView((TextView)v);  // I remove it

        // new layout
    final LinearLayout nuovoLiInserimento = (LinearLayout) li.inflate(R.layout.edit_text_modifica_fermata, parent, false);
    // AutoCompleteTextView and Button, I put the adapter for the AutoCompleteTextView
    final AutoCompleteTextView nuovaFermata = (AutoCompleteTextView) nuovoLiInserimento.findViewById(R.id.edtModificaFermataInModificaLinea);
    Button confermaModificaFermata = (Button) nuovoLiInserimento.findViewById(R.id.btnModificaFermataInModificaLinea);
    nuovaFermata.setAdapter(new ArrayAdapter<String>(context,android.R.layout.simple_dropdown_item_1line, caricaFermate()));
    nuovaFermata.setText(fermataPrecedente);

    // click listener al bottone
    confermaModificaFermata.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {

            // text of AutoCompleteTextView
            String fermata = nuovaFermata.getText().toString();
            // layout edit_text_modifica_fermata, later layout inside the listview              ViewGroup parent = (ViewGroup)(((Button)v).getParent()).getParent();
            int index = parent.indexOfChild(nuovoLiInserimento);
            parent.removeView(nuovoLiInserimento);
            TextView fermataCambiata = new TextView(context);
            fermataCambiata.setText(fermata);
            fermataCambiata.setId(textViewDaCompletare);
                        // i  add this OnClickListener
            fermataCambiata.setOnClickListener(new onClickListenerPerTextViewFermata(context,  textViewDaCompletare));
            parent.addView(fermataCambiata, index);
        }
    });

    // aggiungo il nuovo layout al parent
    parent.addView(nuovoLiInserimento, index);
}

private ArrayList<String> caricaFermate(){
    ArrayList<String> listaDelleFermate = new ArrayList<String>();

    DatabaseLocale db = new DatabaseLocale(context);
    SQLiteDatabase dbLeggibile = db.getReadableDatabase();

    // Tutte le fermate
    Cursor fermate = dbLeggibile.rawQuery("SELECT " + DatabaseLocale.getTagNomeFermata() + 
            " FROM " + DatabaseLocale.getTableNameFermata(), null);

    while(fermate.moveToNext()){
        listaDelleFermate.add(fermate.getString(0));        
    }
    fermate.close();
    db.close();

    return listaDelleFermate;
}

}

<?xml version="1.0" encoding="utf-8"?>

edit_text_modifica_fermata.xml

<TextView
    android:id="@+id/txtCambiaFermata"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="" />

<Button
    android:id="@+id/btnEliminaFermataModificaLinea"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/eliminaFermataInModificaLinea" />

我不知道我的问题是什么原因,你能帮帮我吗? 非常感谢你!

3 个答案:

答案 0 :(得分:0)

关于问题2

您最好从BaseAdapter而不是ArrayAdapter延伸。有一个名为getCount()的方法可以返回项目数,您必须实现它才能返回fermate.size()

我认为ArrayAdapter假定您最初传递的数组的计数,当您从数组中删除条目时,计数大于数组中的项目数,从而导致OutOfBoundsException

答案 1 :(得分:0)

好的,让我们从你的第二个问题开始吧。尝试覆盖适配器中的getCount()方法。 ListView在您的适配器中调用getCount方法,然后在调用getView()之后返回getCount()。尝试在适配器中添加这样的东西:

@Override
public int getCount() {
    return fermate.size();
}

第二个问题怎么样?我认为在listView中删除和添加视图并不是一个好主意。更好的方法是在创建布局时添加EditText和TextView,并将EditText的可见性设置为GONE。然后单击简单更改TextView和EditText的可见性。它会更快,更轻松。

答案 2 :(得分:0)

要删除行,我建议您将适配器中的广播发送到活动中,并将行索引作为“额外”传递。然后,您可以正常从列表适配器中删除它并重置列表视图。在适配器内部进行操作可能会导致问题。