不推荐使用Android Fragment onAttach()


326

我已经更新了我的应用程序以使用最新的支持库(版本23.0.0),我发现它们不赞成使用Fragment类的onAttach()函数。

代替:

onAttach (Activity activity)

下雪了:

onAttach (Context context)

由于我的应用使用了弃用之前通过的活动,因此我认为可能的解决方案是:

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    activity = getActivity();
}

那是正确的方法吗?

更新:

如果我运行的设备的API低于23,则甚至不会调用新的onAttach()。我希望这不是他们的意图!

更新2:

SDK的最新更新已解决问题。

我已经在API 22设备上进行了测试,并且正在调用onAttach(Context)。

点击此处,查看我几周前打开的错误报告以及Google员工的回答。


如果您在传递的实例中使用特定的Activity方法,那么是否尝试过将上下文强制转换为Activity的上下文?请记住,活动是上下文的子类。也许进行铸造是可行的。
MarkSkayff 2015年

由于某些原因,甚至没有调用onAttach()!有任何想法吗?您是否尝试过更新到最新的支持库。
TareK Khoury

2
为什么将API移至Context?您是否不需要a Activity来附加和显示片段?您还将如何使用该Context参数?
肯尼·沃登

1
我已将其发布为错误,请参阅链接code.google.com/p/android/issues/detail?id=183358
TareK Khoury 2015年

6
对于新的onAttach(Context context)调用,您需要使用至少具有API 23的设备,或者使用android.support.v4.app.Fragment。看到这里
nevzo

Answers:


337

活动是上下文,因此,如果您可以简单地检查上下文是活动,并在必要时进行强制转换。

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

    Activity a;

    if (context instanceof Activity){
        a=(Activity) context;
    }

}

更新:有些人声称Context永远不会调用新的替代。我已经进行了一些测试,但是找不到符合真实情况的场景,根据源代码,它永远都不会真实。在所有情况下,我都测试了SDK23之前和之后的Activity以及Context版本onAttach。如果您发现情况并非如此,建议您创建一个示例项目来说明问题,并将其报告给Android团队

更新2:我只用过Android支持库片段,因为那里的错误得到了更快的修复。似乎只有当您使用框架片段时,才能正确调用覆盖的上述问题才得以发现。


5
并不是真正的解决方案,因为带有上下文的onAttach的调用方式与带有活动的onAttach的调用方式不同。如果您在onAttach中有一些初始化代码,并且以Activity作为参数,则此更改将无效。
好友2015年

2
不,至少在我看来,它不一样。我不在onAttach中使用活动或上下文,而是进行初始化。我尝试用活动将onAttach替换为具有上下文的活动,并且不会以相同的方式调用它。因此,它们并不是那么容易互换的。
好友

7
Buddy遇到的相同问题…… onAttach(Context)甚至没有被提及。
斯特凡2015年

2
我已经逐步完成了代码,可以验证是否有可能onAttach(context)不被调用。
乍得宾厄姆

2
在我的情况下,如果我们重新启动系统之前清除的活动,则不会调用onAttach()。但这并不总是这样。我在onAttach(Context上下文)中放置了WeakReference的初始化,refActivity = new WeakReference <>(((AppCompatActivity)context)。并且偶尔会在onCreateView()中抛出NullPointerException。
Kimi Chiu 2015年

45

这是Google的另一项重大改进。建议的修改:替换onAttach(Activity activity)onAttach(Context context)在较旧的API上崩溃的我的应用程序,因为onAttach(Context context)不会在本机片段上调用它。

我正在使用本机片段(android.app.Fragment),所以我必须执行以下操作才能使其在较旧的API(<23)上再次起作用。

这是我所做的:

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

    // Code here
}

@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        // Code here
    }
}

Yoan Hercouet先生,您能否在API 23以上解释如何执行此操作,请帮助我,在此先感谢E / AndroidRuntime:FATAL EXCEPTION:main,java.lang.ClassCastException:com.ual.SMS_Activity@afd5683,在android上。 support.v4.app.FragmentManagerImpl.moveToState,位于android.support.v4.app.FragmentManagerImpl.execSingleAction。我在这里张贴了必要的行,您将可以知道我的错误。
MohanRaj S

@MohanRajS在API 24(我使用的那个)上是相同的,根据您的代码片段,您的问题似乎不必与此相关。
Yoann Hercouet '16

@YoannHercouet,谢谢您的回复,让我检查并更新。
MohanRaj S 2016年

1
您对此不太满意,因为难以定位较旧的API。好吧,考虑一下可以针对较旧API的好处,例如,Apple只会极大地削弱您的利益,并迫使您仅支持最新的API。
斯坦

39

如果您使用框架片段,并且设备的SDK版本低于23,则OnAttach(Context context)不会调用。

我改用支持片段,因此弃用是固定的,onAttach(Context context)总是被调用。


11

当前从onAttachFragment代码开始,尚不清楚Context当前活动是否为:源代码

public void onAttach(Context context) {
    mCalled = true;
    final Activity hostActivity = mHost == null ? null : mHost.getActivity();
    if (hostActivity != null) {
        mCalled = false;
        onAttach(hostActivity);
    }
}

如果您来看看,getActivity您会看到相同的电话

/**
 * Return the Activity this fragment is currently associated with.
 */
final public Activity getActivity() {
    return mHost == null ? null : mHost.getActivity();
}

所以,如果你想确保你得到那么活动中使用 getActivity()(在onAttach你的Fragment),但不要忘记检查null,因为如果mHostnull你的活动将是null


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

    Activity activity = context instanceof Activity ? (Activity) context : null;
}

5

尽管似乎在大多数情况下已经足够了onAttach(Context),但是有些电话(即:小米Redme注2)没有被调用,因此会导致NullPointerExceptions。为了安全起见,我建议您也不要使用已弃用的方法:

// onAttach(Activity) is necessary in some Xiaomi phones
@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    _onAttach(activity);
}

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

private void _onAttach(Context context) {
    // do your real stuff here
}

3

使用sdk管理器下载最新的支持库,包括

compile 'com.android.support:appcompat-v7:23.1.1'

在gradle.app中并将编译版本设置为api 23


1

以下答案与Android开发者网站上的Fragments教程中发生的弃用警告有关,可能与以上帖子无关。

我在教程课上使用了这段代码,它确实起作用了。

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

    Activity activity = getActivity();

我担心活动可能像文档所述那样为空。

getActivity

FragmentActivity getActivity()返回此片段当前与之关联的FragmentActivity。如果片段与上下文关联,则可能返回null。

但是main_activity上的onCreate清楚地表明该片段已加载,因此在此方法之后,从该片段调用get activity将返回main_activity类。

getSupportFragmentManager()。beginTransaction().add(R.id.fragment_container,firstFragment).commit();

我希望我是对的。我绝对是新手。


1

您可能正在使用android.support.v4.app.Fragment。对于此onAttach方法(而不是方法),只需使用getActivity()即可获取FragmentActivity与片段关联的对象。否则您可以使用onAttach(Context context)方法。


0

当我具有用户定义的接口“ TopSectionListener”(其对象ActivityCommander)时,这对我有用:

  //This method gets called whenever we attach fragment to the activity
@Override
public void onAttach(Context context) {
    super.onAttach(context);
    Activity a=getActivity();
    try {
        if(context instanceof Activity)
           this.activitycommander=(TopSectionListener)a;
    }catch (ClassCastException e){
        throw new ClassCastException(a.toString());}

}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.