2013-08-01 1 views
10

Sto seguendo lo contacts provider lesson on retrieving contacts e li visualizzo utilizzando i frammenti. Come riferimento, ho impostato il livello API su 16 (Android 4.1).getActivity(). FindViewById restituisce null, chiamato dal frammento onActivityCreated

Ho seguito per lo più questo tutorial alla lettera, con alcune eccezioni degne di nota. Ad esempio, importare da mypackage.R anziché da android.R.

Il mio problema è nel mio onActivityCreated gestore nel mio ListContactsFragment:

public void onActivityCreated(Bundle savedInstanceState) { 
    super.onActivityCreated(savedInstanceState); 
    // Initializes the loader 
    getLoaderManager().initLoader(0, null, this); 
    // Gets the ListView from the View list of the parent activity 

    View mContactsListView = 
        getActivity().findViewById(R.layout.contacts_list_view); 
    mContactsList = (ListView) mContactsListView; 

    // Gets a CursorAdapter 
    mCursorAdapter = new SimpleCursorAdapter(
      getActivity(), 
      R.layout.contacts_list_item, 
      null, 
      FROM_COLUMNS, TO_IDS, 
      0); 
    // Sets the adapter for the ListView 
    mContactsList.setAdapter(mCursorAdapter); 

    // Set the item click listener to be the current fragment. 
    mContactsList.setOnItemClickListener(this); 
} 

View mContactsListView è nullo, il che significa findViewById non ha funzionato.

L'attività padre è una predefinita creata da eclipse. Per questo, ho fatto due cose:

  1. sostituito import android.app.Activity con android.support.v4.app.FragmentActivity per evitare che il ClasscastException che succede se non lo fai.
  2. Importato il mio frammento nell'XML.

mio activity_list_contacts.xml assomiglia a questo:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:paddingBottom="@dimen/activity_vertical_margin" 
    android:paddingLeft="@dimen/activity_horizontal_margin" 
    android:paddingRight="@dimen/activity_horizontal_margin" 
    android:paddingTop="@dimen/activity_vertical_margin" 
    tools:context=".ListContactsActivity" > 

    <fragment android:name="mypackage.ListContactsFragment" 
       android:id="@+id/contacts_list_view" 
       android:layout_width="match_parent" 
       android:layout_height="match_parent" /> 

</RelativeLayout> 

l'attività di corrispondenza, nel caso in cui:

public class ListContactsActivity extends FragmentActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_list_contacts); 
    } 

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

e contacts_list_view.xml:

<?xml version="1.0" encoding="utf-8"?> 
<ListView xmlns:android="http://schemas.android.com/apk/res/android" 
      android:id="@android:id/list" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent"/> 

Quindi la mia domanda è, cosa sto sbagliando per findViewById non trovare la mia vista?

Le cose che ho provato (la maggior parte di questi sono accettati risposte alle domande che quasi sembrano un duplicato a questo):

  • lettura del documento ho copiato e incollato dalla parola per parola.
  • Provare a getView().findViewById() come suggerito in this question. Anche questo restituisce null.
  • utilizzando findViewById(R.id.contacts_list_view); come suggerito da this answer. Questo non restituisce nulla; invece provoca uno ClassCastException in cui android.support.v4.app.NoSaveStateFrameLayout non può essere trasmesso a android.widget.ListView.
  • Ho letto che a volte il callback del frammento per la creazione si verifica prima di essere collegato all'attività. Così, ho aggiunto il gestore per il metodo onAttach in questo modo:

    @Override 
    public void onAttach(Activity activity) { 
        super.onAttach(activity); 
    
        View mContactsListView = activity.findViewById(R.id.contacts_list_view); 
        mContactsList = (ListView) mContactsListView; 
    
        // Gets a CursorAdapter 
        mCursorAdapter = new SimpleCursorAdapter(
          getActivity(), 
          R.layout.contacts_list_item, 
          null, 
          FROM_COLUMNS, TO_IDS, 
          0); 
        // Sets the adapter for the ListView 
        mContactsList.setAdapter(mCursorAdapter); 
    
        // Set the item click listener to be the current fragment. 
        mContactsList.setOnItemClickListener(this); 
    } 
    

    avete indovinato - ancora nulla.

Quindi a questo punto sono un po 'perso. Ho due domande:

  1. Che cosa sto facendo di sbagliato (si prega di richiedere ulteriori informazioni nei commenti se non ho fornito abbastanza)?
  2. È preferibile lasciare la configurazione dell'adattatore in onAttach o dove dice il tutorial.
+0

Se si utilizza un ID dal framework Android, dovrebbe essere utilizzato come 'android.R.id. *'. 'TO_IDS' è definito come' private final static int [] TO_IDS = {android.R.id.text1} '? – Vikram

+0

@vikram sì, è un membro della classe dei frammenti. –

risposta

11

seguo la tutorial a developer.android.com e ha riscontrato lo stesso problema.

Infine ho notato che in questa parte:

// Gets the ListView from the View list of the parent activity 
    mContactsList = (ListView) getActivity().findViewById(R.layout.contact_list_view); 

sembra cercando di trovare un View, ma passando un Layout id come argomento.

Il View | android reference dice:

Visualizza gli ID non deve essere unico in tutto l'albero, ma è buona pratica per garantire che essi siano almeno unico all'interno della parte dell'albero che si sta cercando.

Così, ho cambiato il ListView id nella contacts_list_view.xml ad un unico uno:

<?xml version="1.0" encoding="utf-8"?> 
<ListView ... 
android:id="@+id/contacts_listview_a_unique_id_here" 
... /> 

poi cerca di trovare con:

 mContactsList = (ListView) getActivity().findViewById(R.id.contacts_listview_a_unique_id_here); 

e funziona (nel onActivityCreated callback) .

  • Circa l'eccezione Cast: Come hierarchyviewer spettacoli, l'albero è in questo modo: hierarchyviewer sc quindi se findViewById elemento passaggio radice della vista, come in that post, tornerà NoSaveStateFrameLayout, che non è il bambino ListView che vuoi.
+0

Grazie, ti faccio un salto e ti faccio sapere come mi metto :) –

+0

Ok ha funzionato :) Eccellente! Grazie mille! –

1

Nota che ListFragment ha un metodo getListView() per restituire il widget ListView istanza.

docs Sviluppatore: ListFragment.getListView

2

getActivity().findViewById() guarda per l'id che fornisci come parametro nella gerarchia di vista della Activity. Probabilmente il ListView viene restituito dal numero onCreateView del tuo frammento. Se si desidera eseguire un findViewById nella gerarchia delle viste frammento, è necessario chiamare getView().findViewById(). In questo caso, dal momento che si sta estendendo ListFragment, per recuperare il ListView, come per il ListActivity, è necessario utilizzare getListView(); un'altra analogia con il ListActivity è l'id del ListView all'interno del file XML (android:id="@android:id/list")

0

@theme proporre una soluzione, ma per utilizzare la listview interna di Android qui è un altro modo. Perché nel tuo file "contacts_list_view.xml" stai usando listview interno di Android con id = @ android: id/list. E nel codice è possibile fare riferimento alla vista elenco con findViewById (android.R.id.list), così il vostro onActivityCreated sarà simile a questo:

public void onActivityCreated(Bundle savedInstanceState) { 
    super.onActivityCreated(savedInstanceState); 
    mContactsList = (ListView) getActivity().findViewById(android.R.id.list);//(R.layout.fragment_contact_list); 
    mCursorAdapter = new SimpleCursorAdapter(getActivity(), R.layout.contact_item_list,null, FROM_COLUMNS, TO_IDS, 0); 
    mContactsList.setAdapter(mCursorAdapter); 
    mContactsList.setOnItemClickListener(this); 
    getLoaderManager().initLoader(0,null,this); 
} 

Speranza che aiuta, va bene la guida per gli sviluppatori Android contiene tale "bug" in modo che possiamo avere familiarità con l'API.