Android: 如何在Fragment视图准备就绪时通知Activity?

30

我在一个带有下拉导航的活动中使用Google Maps API V2,其中地图位于第二个位置。

我正在通过编程方式添加地图,如下:

mMapFragment = supportMapFragment.newInstance();
getSupportFragmentManager()
        .beginTransaction()
        .replace(R.id.placeHolder, mMapFragment, TAG_MAP)
        .commit(); 

我想获取GoogleMap对象,根据文档https://developers.google.com/maps/documentation/android/map,应该使用mMapFragment.getMap(),但是它返回null。

根据http://developer.android.com/reference/com/google/android/gms/maps/SupportMapFragment.html,如果片段没有经历onCreateView生命周期事件,则返回null。

如何知道片段何时准备好?

编辑:我发现这个How do I know the map is ready to get used when using the SupportMapFragment?

覆盖onActivityCreated似乎是一种解决方案,但是那样我就必须通过构造函数实例化片段,而不是使用newInstance(),这有任何区别吗?

4个回答

50
我推荐的方法是使用回调从 Fragment 获取信号。此外,这也是Android在与Activity通信中提出的推荐方法。
对于您的示例,在您的Fragment中,添加一个接口并进行注册。
public static interface OnCompleteListener {
    public abstract void onComplete();
}

private OnCompleteListener mListener;

public void onAttach(Context context) {
    super.onAttach(context);
    try {
        this.mListener = (OnCompleteListener)context;
    }
    catch (final ClassCastException e) {
        throw new ClassCastException(context.toString() + " must implement OnCompleteListener");
    }
}

现在在你的Activity中实现这个接口
public class MyActivity extends FragmentActivity implements MyFragment.OnCompleteListener {
    //...

    public void onComplete() {
        // After the fragment completes, it calls this callback.
        // setup the rest of your layout now
        mMapFragment.getMap()
    }
}

现在,无论你的Fragment中有什么表示它已经加载完毕,请通知你的Activity它已经准备好了。
@Override
protected void onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    // create your fragment
    //...

    // signal that you're done and tell the Actvity to call getMap()
    mListener.onComplete();
}

编辑于2017年12月5日 onAttach(Activity activity)已经被弃用, 请使用onAttach(Context context)代替。上面的代码已经调整。


1
只是一条注释,onAttach(Activity activity)已经被弃用。 - Ewoks
1
伊沃克斯,那么应该使用哪种方法代替呢? - Siwei

2

除了Kirk的回答之外:由于public void onAttach(Activity activity)已被弃用,现在你可以直接使用:

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

    Activity activity;

    if (context instanceof Activity){

        activity=(Activity) context;

        try {
            this.mListener = (OnCompleteListener)activity;
        } catch (final ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnCompleteListener");
        }
    }
}

其余部分保持不变... 但是可以使用 (Fragment sender) 作为参数,并始终传递 this

1
如果您想不使用任何监听器来完成,可以通过TAG添加片段。
 supportFragmentManager
                .beginTransaction()
                .add(R.id.pagerContainer, UniversalWebViewFragment.newInstance(UniversalWebViewFragment.YOUTUBE_SERACH_URL+"HD trailers"), 
                "UniversalWebView")
                .disallowAddToBackStack()
                .commit()

在您希望在片段加载后调用的Hosting Activity类中创建一个公共方法。这里我举例回调我的片段中的一个方法。
public fun loadURL() {
        val webViewFragment = supportFragmentManager
                              .findFragmentByTag("UniversalWebView") 
                               as UniversalWebViewFragment

        webViewFragment.searchOnYoutube("Crysis Warhead")
    }

现在,在您的片段的onViewCreated方法内,您可以像这样简单地调用主机活动的公共方法:
    (activity as HomeActivity ).loadURL()

0

我不确定我完全理解你的问题,但我有一个类似的设置,我正在使用导航下拉菜单。这是对我有用的:

1.) 从xml文件加载片段并调用setupMapIfNeeded()

SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.basicMap);

setUpMapIfNeeded();

这是参考的 XML 文件:

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/basicMap"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  class="com.google.android.gms.maps.SupportMapFragment" />

2.) 然后设置地图(有关isGoogleMapsInstalled()的详细信息,请参见this question

    private void setUpMapIfNeeded() 
    {
    // Do a null check to confirm that we have not already instantiated the map.
    if (mMap == null) 
    {
        // Try to obtain the map from the SupportMapFragment.
        mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.basicMap)).getMap();
        // Check if we were successful in obtaining the map.
        if(isGoogleMapsInstalled())
        {
            if (mMap != null) 
            {
                mMap.setOnCameraChangeListener(getCameraChangeListener());
                mMap.setInfoWindowAdapter(new MyCustomInfoWindowAdapter(this));
            }
        }
        else
        {
            MapConstants.showDialogWithTextAndButton(this, R.string.installGoogleMaps, R.string.install, false, getGoogleMapsListener());
        }
    }
    }

3.) 确保你也在 onResume() 中调用 setUpMapIfNeeded():

public void onResume()
{
    super.onResume();

    setUpMapIfNeeded();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接