【问题标题】:Error in getView() when I focus an EditText当我聚焦 EditText 时 getView() 出错
【发布时间】:2014-06-28 00:56:32
【问题描述】:

在我的 ListView 中有很多行,每行都有一个 TextView 和一个 Button。如果我单击 TextView,这两个视图将变为不可见(消失)并且我显示一个 EditText 和另一个按钮。最后一个 Button 允许返回到 TextView 和前一个 Button,隐藏 Edittext 和他自己。换句话说,我在这两个视图之间切换。 在 ListView 的页脚中,我有一个允许添加新行的按钮。当我单击最后一行的 TextView 时,一如既往地显示 EditText 和 Button。问题是当我点击 EditText 时,即 Edittext 获得焦点,大多数时候这个 EditText 和 relavive Button 是隐藏的,并显示 TextView 和另一个 Button。

当我调试代码时,程序从不切换任何元素的可见性(或者更好的是,在 UII 中它会切换,但程序不符合我为此目的编写的行)。

我找不到错误,我把代码留在这里:

包含 ListView 的类

    package fragments;

import [...]


/**
 * La classe FragmentModificaLinea è un Fragment che permette di prendere
 * una linea già presente nel database, e modificare le fermate che essa
 * percorre.
 */
public class FragmentModificaLinea extends Fragment {

    private Context context = null;


private Button btnConfermaModifica = null;
    private Button btnAggiungi = null;
    private Button btnCambiaLinea = null;
    private EditText edtCambiaNome = null;
private EditText edtCambiaCodice = null;
private ListView listViewModifica = null;
private ListView listViewMostra = null;

// Lista di tutte le linee.
private ArrayList<String> contenitoreLinee = null;

// Lista con le linee appartenenti alla fermata e relativo adapter.
private ArrayList<String> fermateDellaLinea = null;
private AdapterModificaLinea adapterFermateDellaLinea = null;

// Inflater per il footer della lista
private LayoutInflater li = null;

// Oggetto che contiene query al db locale.
private Query richiediAlDatabase = null;

// Tag usato nei log.
@SuppressWarnings("unused")
private static final String TAG = FragmentModificaLinea.class.getSimpleName();

// Salva il codice originale, serve per eliminare la linea.
private String codiceLinea = null;

// La posizione nella listviewmostra dell'elemento da modificare.
private int posizione = 0;

/**
 * Primo metodo che viene chiamato quando creo il fragment. Qui associo
 * il layout al fragment.
 * @param inflater Il layout da utilizzare in questo fragment.
 * @param container Il layout che contiene il fragment.
 * @param savedInstanceState Se si creasse un punto di ripristino dell'activity quando si chiude.
 * @return View
 */
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    // Inserisco il layout di questo fragment.
    // Inflate the layout for this fragment.
    return inflater.inflate(R.layout.fragment_modifica_linea, container, false);
}

/**
 * Metodo chiamato appena dopo che è stato istanziato il layout. Ottengo gli oggetti in esso presenti.
 * @param view Tutte le view nel layout.
 * @param savedInstanceState Se si creasse un punto di ripristino dell'activity quando si chiude.
 */
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    context = getActivity();        
    richiediAlDatabase = new Query(context);
    li = LayoutInflater.from(context);
    // Carico tutte le linee dal database locale.
    contenitoreLinee = richiediAlDatabase.caricaLinee();        
    // Imposto la listView che mostra le linee.
    listViewMostra = (ListView) getView().findViewById(R.id.listViewModificaLineaMostraLinee);
    listViewMostra.setAdapter(new ArrayAdapter<String>(context,android.R.layout.simple_list_item_1, contenitoreLinee));
    listViewMostra.setEmptyView(getView().findViewById(R.id.empty_list_item));
    // Imposto la ListView; ci aggiungo come footer i bottoni al fondo del layout:
    // aggiungi una fermata e conferma linea.
    listViewModifica = (ListView) getView().findViewById(R.id.listViewModificaLinea);
    LinearLayout footer = (LinearLayout) li.inflate(R.layout.footer_list_view, null);
    btnConfermaModifica = (Button) footer.findViewById(R.id.btnConfermaModifica);
    btnAggiungi = (Button) footer.findViewById(R.id.btnAggiungi);
    listViewModifica.addFooterView(footer);
    // Aggiungo come header ciò che mi permette di modifica nome, codice linea
    // e di cambiare linea che si sta modificando.
    LinearLayout header = (LinearLayout) li.inflate(R.layout.header_list_view, null);
    btnCambiaLinea = (Button) header.findViewById(R.id.btnCambiaLinea);
    edtCambiaCodice = (EditText) header.findViewById(R.id.edtCambiaCodice);
    edtCambiaNome = (EditText) header.findViewById(R.id.edtCambiaNome);
    listViewModifica.addHeaderView(header);

    listViewMostra.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                long id) {
            posizione = position;

            // Setto l'adapter alla ListView.
            fermateDellaLinea = richiediAlDatabase.caricaFermateDellaLinea(((String) listViewMostra.getItemAtPosition(posizione)).split(" Cod: ")[1]);
            adapterFermateDellaLinea = new AdapterModificaLinea(context, R.layout.elemento_modifica_linea, fermateDellaLinea);
            listViewModifica.setAdapter(adapterFermateDellaLinea);
            // Rendo visibile la ListView.
            listViewModifica.setVisibility(ListView.VISIBLE);
            // Inizializzo i valori nell'header: nome e codice.
            edtCambiaNome.setText(((String) listViewMostra.getItemAtPosition(posizione)).split(" - Cod: ")[0]);
            edtCambiaCodice.setText(((String) listViewMostra.getItemAtPosition(posizione)).split(" - Cod: ")[1]);
            // Salvo il codice della linea così posso poi eliminarla.
            codiceLinea = ((String) listViewMostra.getItemAtPosition(posizione)).split(" Cod: ")[1];
            // Disabiliti gli oggetti per la ricerca della linea.
            listViewMostra.setVisibility(ListView.GONE);

        }
    });


    // Aggiunge una fermata alla ListView.
    btnAggiungi.setOnClickListener(new OnClickListener() {          
        @Override
        public void onClick(View v) {

            // Controllo che non stia modificando già un'altra linea.
            if(!adapterFermateDellaLinea.isStoModificandoUnaFermata())
                // Se fermateDellaLinea fosse vuoto andrebbe in errore la prossima if,
                // quindi si aggiunge senza ulteriori controlli.
                if(!fermateDellaLinea.isEmpty())
                    // Se l'ultima riga è ancora da inserire.
                    if(!fermateDellaLinea.get(fermateDellaLinea.size() - 1).equals("Nuova fermata")){
                        // Codice uguale all'else sottostante.
                        fermateDellaLinea.add("Nuova fermata");
                        adapterFermateDellaLinea.notifyDataSetChanged();
                    }else Toast.makeText(context, "Inserire prima la fermata appena aggiunta.", Toast.LENGTH_LONG).show();
                else{
                    fermateDellaLinea.add("Nuova fermata");
                    adapterFermateDellaLinea.notifyDataSetChanged();                    
                }
            else Toast.makeText(context, "Confermare la fermata che si sta tentando di modificare.", Toast.LENGTH_LONG).show();
        }
    });


    // Bottone che permette di caricare la linea aggiornata.
    btnConfermaModifica.setOnClickListener(new OnClickListener() {          
        @Override
        public void onClick(View v) {

            // Se l'ultima fermata è già stata inserita.
            if(!fermateDellaLinea.get(fermateDellaLinea.size() - 1).equals("Nuova fermata")){
                // Se non si sta tentando di modificare una fermata.
                if(!adapterFermateDellaLinea.isStoModificandoUnaFermata())
                    // Permette di caricare la linea.
                    new UpdateLinea().execute();
                else Toast.makeText(context, "Confermare la fermata che si sta tentando di modificare.", Toast.LENGTH_LONG).show();
            }else Toast.makeText(context, "Inserire l'ultima fermata con un suggerimento.", Toast.LENGTH_LONG).show();

        }
    });


    // Questo bottone nasconde la listView e abilita la ricerca di una nuova linea da modificare.
    btnCambiaLinea.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

            // Rendo visibigli gli elementi per la ricerca.
            listViewMostra.setVisibility(ListView.VISIBLE);

            // Nascondo la ListView.
            listViewModifica.setVisibility(ListView.GONE);

            // Ripulisco le EditText.
            edtCambiaCodice.setText("");
            edtCambiaNome.setText("");
        }
    });
}


/**
 * Il compito di questa classe è quello di aggiornare la linea. Per far
 * ciò prima la cancella dai database e poi la ricarica con i nuovi dati.
 * Non si usano due AsyncTask diversi per evitare il caso in cui, non essendo
 * sincronizzati, si inseriscano dei record prima che vengano eliminati.
 */
class UpdateLinea extends AsyncTask<Void, Void, Void>{

    private ProgressDialog pDialog;

    // Tag usato nei log.
    private final String TAG = UpdateLinea.class.getSimpleName();

    private String ELIMINA_LINEA = GlobalClass.getDominio() + "Upload/eliminaLinea.php";
    private String CARICA_LINEA = GlobalClass.getDominio() + "Upload/caricaLinea.php";

    private String nomeLineaScelta = edtCambiaNome.getText().toString();
    private String codiceLineaScelta = edtCambiaCodice.getText().toString();

    JSONObject jsonElimina = null;
    JSONObject jsonCarica = null;
    List<NameValuePair> paramsCarica = null;

    /**
     * Metodo che viene eseguito prima di doInBackground.
     * Avvio il ProgressDialog.
     */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        // Creo e mostro il ProgressDialog.
        pDialog = new ProgressDialog(context);
        pDialog.setMessage("Aggiornamento Fermata...");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(true);
        pDialog.show();
    }

    /**
     * Questo metodo esegue il download.
     * @param voids
     * @return
     */
    @Override
    protected Void doInBackground(Void... params) {

        JSONParser jsonParser = new JSONParser();
        String codLinea = codiceLinea;
        // Creazione dei parametri.
        List<NameValuePair> paramsElimina = new ArrayList<NameValuePair>();
        paramsElimina.add(new BasicNameValuePair("CodLinea", codLinea));

        // Richiesta della pagina .php.
        jsonElimina = jsonParser.makeHttpRequest(
                ELIMINA_LINEA, "POST", paramsElimina);


        jsonParser = new JSONParser();
        // Creazione dei parametri.
        // A differenza della classe FragmentAggiungiLinea, i parametri
        // li creo dentro all'AsyncTask perchè i controlli li faccio
        // già durante l'inserimento, e non quando si conferma l'invio
        // dei dati.
        paramsCarica = new ArrayList<NameValuePair>();
        paramsCarica.add(new BasicNameValuePair("NomeLinea", nomeLineaScelta));
        paramsCarica.add(new BasicNameValuePair("CodLinea", codiceLineaScelta));
        for (String fermata : fermateDellaLinea) {
            paramsCarica.add(new BasicNameValuePair("Fermate[]", fermata.split(" - Cod: ")[1]));
        }

        // Richiesta della pagina .php.
        jsonCarica = jsonParser.makeHttpRequest(
                CARICA_LINEA, "POST", paramsCarica);

        return null;
    }

    /**
     * Metodo eseguito dopo doInBackground. Chiudo il ProgressDialog.
     * @param risultato E' il risultato del .php.
     */
    @Override
    protected void onPostExecute(Void result) {
        super.onPostExecute(result);

        // Chiudo il ProgressDialog.
        pDialog.dismiss();

        // Aggiorno il database locale.
        try {

            // Se la linea è sia stata eliminata che aggiunta con successo.
            if(jsonElimina.getInt(GlobalClass.getTagSuccess()) != 0)
                if(jsonCarica.getInt(GlobalClass.getTagSuccess()) != 0){


                // Ottengo il database locale.
                DatabaseLocale db = new DatabaseLocale(context);
                SQLiteDatabase dbScrivibile = db.getWritableDatabase();

                // Cancello da linea e tratta.
                dbScrivibile.delete(DatabaseLocale.getTableNameLinea(), 
                        DatabaseLocale.getTagCodiceLinea() + " = '" + codiceLineaScelta + "'", null);                    
                dbScrivibile.delete(DatabaseLocale.getTableNameTratta(), 
                        DatabaseLocale.getTagCodiceLinea() + " = '" + codiceLineaScelta + "'", null);

                /// AGGIUNGO LA LINEA
                ContentValues valori = new ContentValues();
                valori.put(DatabaseLocale.getTagCodiceLinea(), codiceLineaScelta);
                valori.put(DatabaseLocale.getTagNomeLinea(), nomeLineaScelta);
                valori.put(DatabaseLocale.getTagCodiceCapolinea(), fermateDellaLinea.get(0));
                dbScrivibile.insert(DatabaseLocale.getTableNameLinea(), null, valori);

                for (int i = 0; i < paramsCarica.size(); i++) {
                    BasicNameValuePair valore = ((BasicNameValuePair) paramsCarica.get(i));
                    if(valore.getName() == "Fermate[]" && i != (paramsCarica.size() - 1)){                          
                        valori = new ContentValues();
                        valori.put(DatabaseLocale.getTagCodiceLinea(), codiceLineaScelta);
                        valori.put(DatabaseLocale.getTagCodiceFermata(), valore.getValue());
                        valori.put(DatabaseLocale.getTagSuccessiva(), ((BasicNameValuePair) paramsCarica.get(i + 1)).getValue());
                        dbScrivibile.insert(DatabaseLocale.getTableNameTratta(), null, valori);
                    }else if(i == (paramsCarica.size() - 1)){                           
                        valori = new ContentValues();
                        valori.put(DatabaseLocale.getTagCodiceLinea(), codiceLineaScelta.toString());
                        valori.put(DatabaseLocale.getTagCodiceFermata(), valore.getValue());
                        valori.put(DatabaseLocale.getTagSuccessiva(), 0);
                        dbScrivibile.insert(DatabaseLocale.getTableNameTratta(), null, valori);
                    }
                }

                // Chiudo le connessioni.
                dbScrivibile.close();
                db.close();

                Toast.makeText(context, "Linea modificata con successo.", Toast.LENGTH_LONG).show();
                }else Toast.makeText(context, "Errore nel caricamento della linea", Toast.LENGTH_LONG).show();
            else Toast.makeText(context, "Errore eliminando la linea", Toast.LENGTH_LONG).show();
        } catch (JSONException e) {
            Log.e(TAG, "Error " + e.toString());
            Toast.makeText(context, "Errore durante l'aggiornamento della linea nel database locale.", Toast.LENGTH_LONG).show();
        }
    }


    }

}

listView的适配器,这里我切换可见性:

package fragments;

import [...]

/**
 * Questa classe ha il compito di gestire tutte le linee
 * della ListView, e quindi il loro comportamento. Ogni linea 
 * ha 4 Views, di cui ne mostra solo 2 per volta.
 * All'inizio mostra il nome della fermata ed il bottone per 
 * eliminarla. Se si clicca sul nome della linea queste due
 * Views vengono nascoste e viene mostrata una EditText
 * per inserire la nuova fermata ed un bottone per confermare.
 * @author giacomotb
 *
 */
public class AdapterModificaLinea extends ArrayAdapter<String> {

    private Context context = null;
    private LayoutInflater li = null;
private ArrayList<String> fermateDellaLinea = null;

// Variabile che indica se in almeno una riga
// si sta modificando la fermata(è mostrata 
// l'EditText.
private boolean stoModificandoUnaFermata = false;

// Il layout che viene usato per ogni riga.
private int layoutResourceId = 0; 

// Oggetto che contiene query al db locale.
private Query richiediAlDatabase = null;


/**
 * Classe statica che permette di evitare ripetuti
 * findViewById(), e risparmia il 15% del tempo.
 * http://www.vogella.com/tutorials/AndroidListView/article.html#adapterperformance
 * http://developer.android.com/training/improving-layouts/smooth-scrolling.html#ViewHolder
 *
 */
static class ViewHolder {
    TextView txtCambiaFermata;
    AutoCompleteTextView actModificaFermata;
    Button btnEliminaFermataModificaLinea;
    Button btnModificaFermataInModificaLinea;
}

/**
 * Costruttore.
 * @param context
 * @param resource
 * @param fermate
 */
public AdapterModificaLinea(Context context, int resource, ArrayList<String> fermate) {
    super(context, resource, fermate);
    this.context = context;
    layoutResourceId = resource;
    this.fermateDellaLinea = fermate;   
    li = LayoutInflater.from(context);
}

/**
 * Metodo che crea la row quando si disegna la ListView.
 * Assegna anche i listener ai suoi elementi.
 */
@Override
public View getView(final int position, View convertView, ViewGroup parent) {

    richiediAlDatabase = new Query(context);

    // Tutte le fermare nel database locale.
    final ArrayList<String> tutteLeFermate = richiediAlDatabase.caricaFermate();

    // Permette di riutilizzare le View che sono fuori dallo schermo
    // per risparmiare tempo.
    // http://www.vogella.com/tutorials/AndroidListView/article.html#adapterperformance
    if(convertView == null){
        convertView = li.inflate(layoutResourceId, null);

        // configure view holder
        ViewHolder viewHolder = new ViewHolder();
        viewHolder.txtCambiaFermata = (TextView) convertView.findViewById(R.id.txtCambiaFermata);
        viewHolder.actModificaFermata = (AutoCompleteTextView) convertView.findViewById(R.id.actModificaFermata);
        viewHolder.btnEliminaFermataModificaLinea = (Button) convertView.findViewById(R.id.btnEliminaFermataModificaLinea);
        viewHolder.btnModificaFermataInModificaLinea = (Button) convertView.findViewById(R.id.btnModificaFermataInModificaLinea);         
        convertView.setTag(viewHolder);
    }

    final ViewHolder holder = (ViewHolder) convertView.getTag();

    if(!stoModificandoUnaFermata){
        // Setto la visibilità di default.
        holder.btnModificaFermataInModificaLinea.setVisibility(Button.GONE);
        holder.actModificaFermata.setVisibility(AutoCompleteTextView.GONE);
        holder.btnEliminaFermataModificaLinea.setVisibility(Button.VISIBLE);
        holder.txtCambiaFermata.setVisibility(TextView.VISIBLE);
        // Aggiungo il testo alla TextView
        holder.txtCambiaFermata.setText(fermateDellaLinea.get(position));
        // Aggiungo l'adapter all'AutoCompleteTextView.
        holder.actModificaFermata.setAdapter(new ArrayAdapter<String>(context,android.R.layout.simple_dropdown_item_1line, tutteLeFermate));            
    }

    // Se si preme sulla textview la scambio con una all'AutoCompleteTextView per cambiare fermata.
    holder.txtCambiaFermata.setOnClickListener(new OnClickListener() {          
        @Override
        public void onClick(View v) {               

            // Se non sto già modificando un'altra fermata.
            if(!stoModificandoUnaFermata){
                // Dichiaro che sto modificando una fermata.
                stoModificandoUnaFermata = true;

                // Assegno all'AutoComplete.. il testo della TextView nascosta.
                holder.actModificaFermata.setText(holder.txtCambiaFermata.getText().toString());
                // Cambio visibilità agli elementi.
                holder.txtCambiaFermata.setVisibility(TextView.GONE);
                holder.btnEliminaFermataModificaLinea.setVisibility(Button.GONE);
                holder.actModificaFermata.setVisibility(AutoCompleteTextView.VISIBLE);
                holder.btnModificaFermataInModificaLinea.setVisibility(Button.VISIBLE);


                // Listener al bottone che conferma la modifica della fermata.
                holder.btnModificaFermataInModificaLinea.setOnClickListener(new View.OnClickListener() {                        
                    @Override
                    public void onClick(View v) {

                        // Non sto più modificando alcuna riga.
                        stoModificandoUnaFermata = false;

                        // Se la fermata è una di quelle consigliate.
                        if(tutteLeFermate.contains(holder.actModificaFermata.getText().toString()))
                            // Se non è presente tra quelle già inserite
                            if(!fermateDellaLinea.contains(holder.actModificaFermata.getText().toString())
                                    // Ma la posizione non è la stessa di quella che si sta modificando,
                                    // nel caso in cui si reinserisca la fermata che si voleva modificare.
                                    || fermateDellaLinea.indexOf(holder.actModificaFermata.getText().toString()) == position){

                                // Cambio la fermata nella lista a cui fa riferimento la ListView.
                                fermateDellaLinea.set(position, holder.actModificaFermata.getText().toString());
                                // Notifico i cambiamenti.
                                AdapterModificaLinea.this.notifyDataSetChanged();

                                // Cambio le visibilità.
                                holder.btnModificaFermataInModificaLinea.setVisibility(Button.GONE);
                                holder.actModificaFermata.setVisibility(AutoCompleteTextView.GONE);
                                holder.btnEliminaFermataModificaLinea.setVisibility(Button.VISIBLE);
                                holder.txtCambiaFermata.setVisibility(TextView.VISIBLE);

                            }else Toast.makeText(context, "Fermata già presente: prima di inserirla eliminare la medesima fermata dalla lista"
                                        , Toast.LENGTH_LONG).show();
                        else Toast.makeText(context, "La fermata deve assumere uno dei valori suggeriti."
                                    , Toast.LENGTH_LONG).show();
                    }
                });             
            }else Toast.makeText(context, "Confermate la fermata che si sta modificando."
                    , Toast.LENGTH_LONG).show();
        }
    });


    // Bottone che permette di eliminare una data riga e la sua fermata.
    holder.btnEliminaFermataModificaLinea.setOnClickListener(new OnClickListener() {            
        @Override
        public void onClick(View v) {
            fermateDellaLinea.remove(position);
            AdapterModificaLinea.this.notifyDataSetChanged();
        }
    });

    return convertView;
}

public boolean isStoModificandoUnaFermata() {
    return stoModificandoUnaFermata;
    }


}

谢谢你的帮助!!!

【问题讨论】:

    标签: android listview android-edittext runtime-error visibility


    【解决方案1】:
    Try to replace this pieace of code
     if(convertView == null){
            convertView = li.inflate(layoutResourceId, null);
    
            // configure view holder
            ViewHolder viewHolder = new ViewHolder();
            viewHolder.txtCambiaFermata = (TextView) convertView.findViewById(R.id.txtCambiaFermata);
            viewHolder.actModificaFermata = (AutoCompleteTextView) convertView.findViewById(R.id.actModificaFermata);
            viewHolder.btnEliminaFermataModificaLinea = (Button) convertView.findViewById(R.id.btnEliminaFermataModificaLinea);
            viewHolder.btnModificaFermataInModificaLinea = (Button) convertView.findViewById(R.id.btnModificaFermataInModificaLinea);         
            convertView.setTag(viewHolder);
        }
    
        final ViewHolder holder = (ViewHolder) convertView.getTag();
    

    有了这个

    ViewHolder viewHolder;
     if(convertView == null){
                convertView = li.inflate(layoutResourceId, null);
    
            // configure view holder
            viewHolder = new ViewHolder();
            viewHolder.txtCambiaFermata = (TextView) convertView.findViewById(R.id.txtCambiaFermata);
            viewHolder.actModificaFermata = (AutoCompleteTextView) convertView.findViewById(R.id.actModificaFermata);
            viewHolder.btnEliminaFermataModificaLinea = (Button) convertView.findViewById(R.id.btnEliminaFermataModificaLinea);
            viewHolder.btnModificaFermataInModificaLinea = (Button) convertView.findViewById(R.id.btnModificaFermataInModificaLinea);         
            convertView.setTag(viewHolder);
        }else{
            holder = (ViewHolder) convertView.getTag();
        }
    

    【讨论】:

    • 在第二段代码中,进入else clausole,你的意思是viewHolder?还是持有人?如果你的意思是持有人,如果 convertView == null,什么时候会分配持有人?我改变了第一个假设的代码,它仍然不起作用。视图不会切换。
    猜你喜欢
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 2014-06-18
    • 2019-10-23
    • 2012-01-09
    • 1970-01-01
    • 2013-08-20
    • 1970-01-01
    相关资源
    最近更新 更多