Android getSupportFragmentManager().findFragmentById()返回null,即使片段存在

Android getSupportFragmentManager().findFragmentById()返回null,即使片段存在,android,android-fragments,Android,Android Fragments,我在活动\u main.xml中有一个片段\u main.xml 该片段添加在从Android Studio模板创建的选项卡式活动中 我想从活动中更改片段的视图。这就是为什么我创建了一个接口,当我知道片段的视图可以修改时,该接口允许片段在片段的启动过程中调用活动 如果我使用我的接口回调传递实际的片段实例,那么我确实实现了这一点。但我仍然感到沮丧,因为我不明白为什么这个函数返回null。这是否与在不同的屏幕方向上重用片段有关 我已经在这里查看了类似的问题,所以这个函数返回null。有人提到使用im

我在
活动\u main.xml
中有一个
片段\u main.xml

该片段添加在从Android Studio模板创建的选项卡式活动中

我想从活动中更改片段的视图。这就是为什么我创建了一个接口,当我知道片段的视图可以修改时,该接口允许片段在片段的启动过程中调用活动

如果我使用我的接口回调传递实际的片段实例,那么我确实实现了这一点。但我仍然感到沮丧,因为我不明白为什么这个函数返回null。这是否与在不同的屏幕方向上重用片段有关

我已经在这里查看了类似的问题,所以这个函数返回null。有人提到使用
import android.support.v4.app.Fragment可能有问题
而不是android.app.Fragment。我不认为这是我的情况,因为getsupportFragmentManager似乎返回了正确类型的片段(v4.app)。我不知道为什么会有v4.app,我对这一切都有点陌生

无论如何,这是代码,包括导入,因为它们可能是相关的

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;
        }
    }
}
我也在粘贴XML,尽管它们很好(正如我所说,如果我传递实际片段,它就可以工作)

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>

我会尝试以下方法,但我肯定这不是最好的解决方案

我将传递
section\u number
的值,而不是
占位符片段
,并从SectionPageAdapter获取片段。大概是这样的:

 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);
 }

首先,您使用了
findFragmentById
错误,将片段根布局的
id
作为参数传递,而它需要包含片段的布局的
id
(而不是片段内部的布局!)

FragmentPagerAdapter有点棘手,获取当前片段并不简单。检查以下答案:

替换您的:

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


我懂了!谢谢:)。这看起来有点。。。就像你说的,很棘手。我想通过函数调用将实例本身作为参数传递会更干净?有什么反对这样做的建议吗?为什么有人会使用这种方式而不是将片段实例传递回活动?一次性传递片段实例是可以的,但是将该实例保存在字段中是不可靠的,因为
FragmentManager
可能会在屏幕上重新创建片段旋转或其他
状态
更改。我发布的代码片段更适合您需要更新当前显示的片段,但您没有它的实例。谢谢:)。就命名约定(“android:switcher”…等)而言,findFragmentByTag是否“稳定”在各个版本中保持一致?是否有更好的方法获取/保存碎片?我想知道为什么我不能在片段中获得视图(TextView),比如说view\u id.fragment\u id.view\u id为什么我不能给片段附加一个id?
PlaceholderFragment page = (PlaceholderFragment) 
getSupportFragmentManager().findFragmentByTag("android:switcher:" + 
R.id.container + ":" + mViewPager.getCurrentItem());