2013-03-17 13 views
14

Piszę aplikację, która używa NFC do odczytu niektórych danych na niej zapisanych. Moja aplikacja używa Fragmentów i Fragmentów, które nie pochodzą z metody onNewIntent(). Ponieważ dane, które czytam, są wykonywane za pomocą mojej oddzielnej klasy, która obsługuje operację związaną z NFC, jedyną rzeczą, którą muszę zrobić, to zaktualizować TextView wewnątrz Fragmentu. Jednak ta implementacja może być również wykorzystana do przekazania nowego zamiaru Fragmentowi.Obsługa nowego fragmentu

Oto moja obecna implementacja, która wykorzystuje interfejs. Dzwonię do słuchacza po otrzymaniu nowej intencji i sprawdzeniu związanym z NFC. To jest FragmentActivity, który obsługuje Fragment.

public class Main extends FragmentActivity implements 
    ActionBar.OnNavigationListener { 

private Bundle myBalanceBundle; 
private NFC nfcObj; 
private NewBalanceListener newBlanceListener; 

@Override 
public void onNewIntent(Intent intent) { 
    setIntent(intent); 
} 

@Override 
protected void onResume() { 
    getNFCState(); 
    super.onResume(); 
} 

private void getNFCState() { 
    //Other NFC related codes 
    else if (nfc_state == NFC.NFC_STATE_ENABLED){ 
     readNFCTag(); 
    } 
} 

private void readNFCTag() { 
    //Other NFC related codes 
    if (getIntent().getAction().equals(NfcAdapter.ACTION_TECH_DISCOVERED)) { 
     nfcObj.setTag((Tag) getIntent().getParcelableExtra(
       NfcAdapter.EXTRA_TAG)); 
     nfcObj.readQuickBalance(); 

     transitQuickReadFragment(nfcObj.getCurrentBalance()); 
    } 
} 

private void transitQuickReadFragment(String balance) { 
    // Creates a balance bundle and calls to select MyBalance Fragment if it 
    // is not visible. Calls listener is it is already visible. 
    if (actionBar.getSelectedNavigationIndex() != 1) { 
     if (myBalanceBundle == null) 
      myBalanceBundle = new Bundle(); 

     myBalanceBundle.putString(Keys.BALANCE.toString(), balance); 

     actionBar.setSelectedNavigationItem(1); 
    } else { 
     newBlanceListener.onNewBalanceRead(balance); 
    } 
} 

@Override 
public boolean onNavigationItemSelected(int position, long id) { 
    // Other fragment related codes 
    fragment = new MyBalance(); 
    fragment.setArguments(myBalanceBundle); 
    newBlanceListener = (NewBalanceListener) fragment; 
    // Other fragment related codes 
} 

// Interface callbacks. You can pass new Intent here if your application 
// requires it. 
public interface NewBalanceListener { 
    public void onNewBalanceRead(String newBalance); 

} 
} 

To MyBalance Fragment, który ma TextView że musi być aktualizowany, gdy NFC jest czytany:

public class MyBalance extends Fragment implements NewBalanceListener { 

private TextView mybalance_value; 

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
     Bundle savedInstanceState) { 
    //Other onCreateView related code 

    Bundle bundle = this.getArguments(); 
    if (bundle != null) 
     mybalance_value.setText(bundle.getString(Keys.BALANCE.toString(), 
       "0.00")); 
    else 
     mybalance_value.setText("0.00"); 

    //Other onCreateView related code 
} 

@Override 
public void onNewBalanceRead(String newBalance) { 
    mybalance_value.setText(newBalance); 
} 
} 

ten kod działa idealnie jak oczekiwano dla mojej aplikacji, ale chcę wiedzieć, czy jest lepszy sposób obsługi nowych intencji z fragmentów?

+0

Checkout ten link wygląda podobnie do Twojego wymagania http://stackoverflow.com/questions/17144512/pass-intent-to-my-fragment?noredirect=1&lq=1 –

Odpowiedz

-2

Nie, nie ma lepszego sposobu. Fragmenty mogą żyć dłużej niż Działania i niekoniecznie są z nimi powiązane, więc zapewnienie nowych intencji nie ma sensu.

Btw, masz kilka błędów w kodzie :)

if (actionBar.getSelectedNavigationIndex() != 1) { 

Magiczne Liczby są złe! użyj stałej.

if (myBalanceBundle == null) 
     myBalanceBundle = new Bundle(); 

    myBalanceBundle.putString(Keys.BALANCE.toString(), balance); 
    actionBar.setSelectedNavigationItem(1); 

już wiemy, że navigationitem jest ustawiony na 1

} else { 
    newBlanceListener.onNewBalanceRead(balance); 

Dodaj null czek. Użytkownik mógł nigdy nie wybrać elementu nawigacyjnego.

+0

To nie odpowiada na oryginalne pytanie! o tym, jak używać onNewIntent w Fragment – developer1011

2

To jest stare pytanie, ale pozwól mi odpowiedzieć na wypadek, gdyby ktoś wpadł na to.

Przede wszystkim masz błąd w kodzie:

nie można zarejestrować Fragments jako słuchaczy wewnątrz Activity sposób to zrobić. Powodem jest to, że Activity i Fragments mogą zostać zniszczone przez system i odtworzone później ze stanu zapisanego (patrz dokumentacja na stronie Recreating an Activity). Gdy tak się stanie, zostaną utworzone nowe instancje zarówno Activity, jak i Fragment, ale kod, który ustawia Fragment jako detektor, nie zostanie uruchomiony, dlatego onNewBalanceRead() nigdy nie zostanie wywołany. Jest to bardzo częsty błąd w aplikacjach na Androida.

W celu komunikowania zdarzeń z Activity do Fragment widzę co najmniej dwa możliwe podejścia:

Interfejs oparty:

Jest an officially recommended approach for communication between Fragments. To podejście jest podobne do tego, co teraz robisz, ponieważ używa interfejsów wywołań zwrotnych zaimplementowanych przez Fragment lub Activity, ale jego wadą jest ścisłe sprzężenie i mnóstwo brzydkiego kodu.autobus

zdarzeń na podstawie:

lepszym rozwiązaniem (IMHO) jest skorzystać z autobusu Event - "komponentu nadrzędnego" (Activity w Twoim przypadku) stanowisk "update" zdarzenia do autobusu konferencyjnego, natomiast „slave składnik "(Fragment w twoim przypadku) rejestruje się do magistrali zdarzeń w onStart() (wyrejestrowuje w onStop()) w celu odebrania tych zdarzeń. Jest to czystsze podejście, które nie powoduje żadnego sprzężenia między łączącymi się komponentami.

Wszystkie moje projekty używają Green Robot's EventBus i nie mogę tego wystarczająco polecić.

0

Istnieje co najmniej jedna alternatywa: Od Activity.onNewIntent documentation:

Działalność zawsze będą wstrzymane przed otrzymaniem nowego zamiarów, więc można liczyć na onResume() jest wywoływana po tej metodzie.

Należy zauważyć, że funkcja getIntent() nadal zwraca pierwotny zamiar. Możesz użyć setIntent (Intent), aby zaktualizować ten nowy zamiar.

FragmentActivity.onNewIntent documentation jest inny, ale nie sądzę, że jest to sprzeczne z powyższymi stwierdzeniami. Przyjmuję również założenie, że Fragment.onResume będzie wywoływane po FragmentActivity.onResume, mimo że dokumentacja wydaje mi się nieco kłopotliwa, chociaż moje testy potwierdzają to przypuszczenie. Na podstawie tego zaktualizowałem Intent aktywności jak SO (przykłady w Kotlin)

override fun onNewIntent(intent: Intent?) { 
    setIntent(intent) 
    super.onNewIntent(intent) 
} 

I Fragment.onResume mogę poradzić sobie z nową intencję Podobnie jak

override fun onResume() { 
    super.onResume() 
    doStuff(activity.intent) 
} 

ten sposób aktywność don” t musi wiedzieć o tym, jakie fragmenty posiada.

Powiązane problemy