2017-05-15 6 views
0

Ich habe eine fragment_main.xml innerhalb einer activity_main.xml.getSupportFragmentManager(). FindFragmentById() gibt null zurück, obwohl das Fragment existiert

Das Fragment wird in einer Tabbed-Aktivität hinzugefügt, die aus einer Android Studio-Vorlage erstellt wurde.

Ich möchte eine Änderung in der Ansicht des Fragments innerhalb der Aktivität vornehmen. Deshalb habe ich eine Schnittstelle erstellt, die es dem Fragment ermöglicht, die Aktivität während des Fragments onStart aufzurufen, wenn ich weiß, dass die Ansicht des Fragments für Änderungen verfügbar ist.

Ich habe habe dies zu arbeiten, wenn ich die tatsächliche Fragment-Instanz mit meiner Schnittstelle Callback übergeben. Aber ich bin immer noch frustriert, weil ich nicht verstehe, warum diese Funktion null zurückgibt. Hat das etwas mit der Wiederverwendung von Fragmenten in verschiedenen Bildschirmausrichtungen zu tun?

Ich habe über ähnliche Fragen hier auf SO berichtet mit dieser Funktion zurückgegeben Null zurückgegeben. Jemand erwähnte, dass es ein Problem mit der Verwendung von import android.support.v4.app.Fragment; im Gegensatz zu nur android.app.Fragment geben könnte. Ich glaube nicht, dass dies mein Fall ist, weil Unterstützung FragmentManager scheint den richtigen Typ von Fragment (v4.app) zurückgeben. Ich habe keine Ahnung, warum die v4.app da ist, ich bin irgendwie neu in all dem.

Wie auch immer, hier ist der Code, alles inklusive Importe, weil sie relevant sein könnten.

package org.axonnsd.musicnexus; 

import android.app.Activity; 
import android.content.Context; 
import android.media.MediaPlayer; 
import android.os.Environment; 
import android.os.Handler; 
import android.support.design.widget.FloatingActionButton; 
import android.support.design.widget.Snackbar; 
import android.support.v7.app.AppCompatActivity; 
import android.support.v7.widget.Toolbar; 

import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentManager; 
import android.support.v4.app.FragmentPagerAdapter; 
import android.support.v4.view.ViewPager; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.LayoutInflater; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.ViewGroup; 

import android.widget.MediaController; 
import android.widget.TextView; 

import java.io.FileInputStream; 
import java.io.IOException; 

public class MainActivity extends AppCompatActivity implements OnFragmentReadyListener { 

    /** 
    * The {@link android.support.v4.view.PagerAdapter} that will provide 
    * fragments for each of the sections. We use a 
    * {@link FragmentPagerAdapter} derivative, which will keep every 
    * loaded fragment in memory. If this becomes too memory intensive, it 
    * may be best to switch to a 
    * {@link android.support.v4.app.FragmentStatePagerAdapter}. 
    */ 
    private SectionsPagerAdapter mSectionsPagerAdapter; 

    private static final String TAG = "MyTabbedApplication"; 

    private Handler handler = new Handler(); 

    /** 
    * The {@link ViewPager} that will host the section contents. 
    */ 
    private ViewPager mViewPager; 

    @Override 
    protected void onStop() { 
     super.onStop(); 
     mediaController.hide(); 
     mediaPlayer.stop(); 
     mediaPlayer.release(); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     //the MediaController will hide after 3 seconds - tap the screen to make it appear again 
     mediaController.show(); 
     return false; 
    } 


    public void onFragmentReady(PlaceholderFragment fragment) 
    { 
     this.getIntent().putExtra(AUDIO_FILE_NAME,AUDIO_FILE_NAME); 
     audioFile = this.getIntent().getStringExtra(AUDIO_FILE_NAME); 

     PlaceholderFragment fragment = (PlaceholderFragment)(getSupportFragmentManager().findFragmentById(R.id.main_audio_view)); 
       //FRAGMENT IS NULL! 
     fragment.setNowPlayingText(audioFile); 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 
     setSupportActionBar(toolbar); 
     // Create the adapter that will return a fragment for each of the three 
     // primary sections of the activity. 
     mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); 

     // Set up the ViewPager with the sections adapter. 
     mViewPager = (ViewPager) findViewById(R.id.container); 
     mViewPager.setAdapter(mSectionsPagerAdapter); 

     FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 
     fab.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View view) { 
       Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) 
         .setAction("Action", null).show(); 
      } 
     }); 
    } 

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

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     // Handle action bar item clicks here. The action bar will 
     // automatically handle clicks on the Home/Up button, so long 
     // as you specify a parent activity in AndroidManifest.xml. 
     int id = item.getItemId(); 

     //noinspection SimplifiableIfStatement 
     if (id == R.id.action_settings) { 
      return true; 
     } 

     return super.onOptionsItemSelected(item); 
    } 

    /** 
    * A placeholder fragment containing a simple view. 
    */ 
    public static class PlaceholderFragment extends Fragment { 
     /** 
     * The fragment argument representing the section number for this 
     * fragment. 
     */ 
     private static final String ARG_SECTION_NUMBER = "section_number"; 
     private TextView _txtNowPlaying; 
     private MainActivity _parentActivity; 

     public PlaceholderFragment() { 
     } 

     /** 
     * Returns a new instance of this fragment for the given section 
     * number. 
     */ 
     public static PlaceholderFragment newInstance(int sectionNumber) { 
      PlaceholderFragment fragment = new PlaceholderFragment(); 
      Bundle args = new Bundle(); 
      args.putInt(ARG_SECTION_NUMBER, sectionNumber); 
      fragment.setArguments(args); 
      return fragment; 
     } 

     @Override 
     public View onCreateView(LayoutInflater inflater, ViewGroup container, 
           Bundle savedInstanceState) { 
      View rootView = inflater.inflate(R.layout.fragment_main, container, false); 
      TextView textView = (TextView) rootView.findViewById(R.id.section_label); 
      _txtNowPlaying = (TextView)rootView.findViewById(R.id.now_playing_text); 
      textView.setText(getString(R.string.section_format, getArguments().getInt(ARG_SECTION_NUMBER))); 
      //notifyActivity(_parentActivity); 
      return rootView; 
     } 

     @Override 
     public void onAttach(Activity activity) 
     { 
      super.onAttach(activity); 
      _parentActivity = (MainActivity)activity; 
     } 

     @Override 
     public void onAttach(Context context) 
     { 
      super.onAttach(context); 

      if (context instanceof Activity){ 
       _parentActivity = (MainActivity)context; 
      } 
     } 

     @Override 
     public void onStart() 
     { 
      super.onStart(); 
      notifyActivity(_parentActivity); 
     } 

     private void notifyActivity(MainActivity activity) 
     { 
      activity.onFragmentReady(this); 
     } 

     public void setNowPlayingText(String value) 
     { 
      _txtNowPlaying.setText(value); 
     } 
    } 

    /** 
    * A {@link FragmentPagerAdapter} that returns a fragment corresponding to 
    * one of the sections/tabs/pages. 
    */ 
    public class SectionsPagerAdapter extends FragmentPagerAdapter { 

     public SectionsPagerAdapter(FragmentManager fm) { 
      super(fm); 
     } 

     @Override 
     public Fragment getItem(int position) { 
      // getItem is called to instantiate the fragment for the given page. 
      // Return a PlaceholderFragment (defined as a static inner class below). 
      return PlaceholderFragment.newInstance(position + 1); 
     } 

     @Override 
     public int getCount() { 
      // Show 3 total pages. 
      return 3; 
     } 

     @Override 
     public CharSequence getPageTitle(int position) { 
      switch (position) { 
       case 0: 
        return "SECTION 1"; 
       case 1: 
        return "SECTION 2"; 
       case 2: 
        return "SECTION 3"; 
      } 
      return null; 
     } 
    } 
} 

Ich bin Einfügen der XMLs zu, auch wenn sie in Ordnung ist (wie gesagt, es funktioniert, wenn ich das eigentliche Fragment passieren).

activity_main.xml

<?xml version="1.0" encoding="utf-8"?> 
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/main_content" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:fitsSystemWindows="true" 
    tools:context="org.axonnsd.musicnexus.MainActivity"> 

    <android.support.design.widget.AppBarLayout 
     android:id="@+id/appbar" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:paddingTop="@dimen/appbar_padding_top" 
     android:theme="@style/AppTheme.AppBarOverlay"> 

     <android.support.v7.widget.Toolbar 
      android:id="@+id/toolbar" 
      android:layout_width="match_parent" 
      android:layout_height="?attr/actionBarSize" 
      android:background="?attr/colorPrimary" 
      app:layout_scrollFlags="scroll|enterAlways" 
      app:popupTheme="@style/AppTheme.PopupOverlay"> 

     </android.support.v7.widget.Toolbar> 

    </android.support.design.widget.AppBarLayout> 

    <android.support.v4.view.ViewPager 
     android:id="@+id/container" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     app:layout_behavior="@string/appbar_scrolling_view_behavior" /> 

    <android.support.design.widget.FloatingActionButton 
     android:id="@+id/fab" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="end|bottom" 
     android:layout_margin="@dimen/fab_margin" 
     app:srcCompat="@android:drawable/ic_dialog_email" /> 

</android.support.design.widget.CoordinatorLayout> 

fragment_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:id="@+id/main_audio_view" 
    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="org.axonnsd.musicnexus.MainActivity$PlaceholderFragment"> 

    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="center" 
     android:text="Now playing:" 
     android:textSize="25sp" 
     android:textStyle="bold" 
     /> 
    <TextView 
     android:id="@+id/now_playing_text" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_marginTop="20dip" 
     android:layout_marginLeft="10dip" 
     android:layout_marginRight="10dip" 
     android:layout_gravity="center" 
     android:text="Now playing.." 
     android:textSize="16sp" 
     android:textStyle="italic" 
     /> 

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

</RelativeLayout> 

Antwort

1

Zunächst einmal sind Sie findFragmentById falsch verwenden, vorbei id von Wurzel Layout Ihres Fragments als Parameter, wenn es eine id eines Layouts erwartet, dass Ihr Fragment enthält (nicht im Layout ein Fragment!)

FragmentPagerAdapter ist ein bisschen schwierig und immer aktuelle Fragment ist nicht einfach. Überprüfen Sie diese Antwort: Getting the current Fragment instance in the viewpager

Ersetzen Sie:

PlaceholderFragment fragment = (PlaceholderFragment)(getSupportFragmentManager().findFragmentById(R.id.main_audio_view)); 
      //FRAGMENT IS NULL! 

mit

PlaceholderFragment page = (PlaceholderFragment) 
getSupportFragmentManager().findFragmentByTag("android:switcher:" + 
R.id.container + ":" + mViewPager.getCurrentItem()); 
+0

ich sehen! Vielen Dank :). Das sieht ein bisschen ... knifflig aus, wie du gesagt hast. Ich denke, es wäre sauberer, die Instanz selbst als Argument über einen Funktionsaufruf zu übergeben. Irgendwelche Ratschläge dagegen?Warum sollte jemand diesen Weg benutzen, anstatt eine Instanz des Fragments an die Aktivität zurückzugeben? – Axonn

+1

Es ist in Ordnung, die Fragment-Instanz für die einmalige Verwendung zu übergeben, das Speichern dieser Instanz in einem Feld ist jedoch unzuverlässig, da 'FragmentManager' Fragment-auf-Bildschirm-Rotation oder andere 'Status'-Änderungen wiederherstellen kann. Der Ausschnitt, den ich gepostet habe, war mehr für den Fall, dass Sie das aktuell angezeigte Fragment aktualisieren müssen, aber Sie haben keine Instanz davon. –

+0

Danke :). Ist der findFragmentByTag in Bezug auf die Benennungskonvention ("android: switcher" ... usw.) "stable", was über die Releases hinweg konsistent ist? Gibt es einen besseren Weg Fragmente zu erhalten/zu behalten? Ich frage mich, warum ich keine Sicht (TextView) innerhalb des Fragments bekommen kann, indem ich sowas wie view_id.fragment_id.view_id sage. Warum kann ich keine ID an ein Fragment anhängen? – Axonn

0

würde ich folgendes versuchen, aber ich bin sicher, dass es nicht die schönste Lösung ist.

Ich würde den Wert section_number anstelle der PlaceholderFragment übergeben und das Fragment aus dem SectionPageAdapter erhalten. Etwas wie folgt aus:

public void onFragmentReady(int position) 
{ 
    this.getIntent().putExtra(AUDIO_FILE_NAME,AUDIO_FILE_NAME); 
    audioFile = this.getIntent().getStringExtra(AUDIO_FILE_NAME); 

    PlaceholderFragment fragment = (PlaceholderFragment)mSectionsPagerAdapter.getItem(position); 

    fragment.setNowPlayingText(audioFile); 
} 
Verwandte Themen