【问题标题】:onAttach(Activity) deprecated: where I can check if the activity implements callback interfaceonAttach(Activity) 已弃用:我可以在其中检查活动是否实现回调接口
【发布时间】:2017-11-11 23:32:02
【问题描述】:

在 API 23 之前,我使用 Fragment 的 onAttach 方法来获取我的侦听器实例,然后在 onDetach 中清除引用。例如:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    mListener = null;
    try {
        mListener = (SellFragmentListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement SellFragmentListener");
    }
}

@Override
public void onDetach() {
    super.onDetach();
    mListener = null;
}

在 onAttach(Context context) 中做同样的检查是否安全,或者有没有更好的方法来获取持有者活动实例?

【问题讨论】:

  • onActivityCreated ?
  • 我通常在onResume()/onPause() 上做这种事情,特别是如果听众会做任何影响 UI 的事情。
  • @tibo 我认为 onActivityCreated 在将片段添加到现有活动时不会调用它。
  • @KevinKrumwiede 这也是一个选择!
  • 是的,这是个好问题。这意味着文档 developer.android.com/training/basics/fragments/… 错误或不实际

标签: android android-fragments


【解决方案1】:

查看源代码:

/**
 * Called when a fragment is first attached to its context.
 * {@link #onCreate(Bundle)} will be called after this.
 */
public void onAttach(Context context) {
    mCalled = true;
    final Activity hostActivity = mHost == null ? null : mHost.getActivity();
    if (hostActivity != null) {
        mCalled = false;
        onAttach(hostActivity);
    }
}

/**
 * @deprecated Use {@link #onAttach(Context)} instead.
 */
@Deprecated
public void onAttach(Activity activity) {
    mCalled = true;
}

因此,如果有主机活动,onAttach(Context context) 将调用 onAttach(Activity activity)。您可以安全地使用onAttach(Activity activity)。

【讨论】:

  • mHost 无法从包外部访问...那怎么办?
【解决方案2】:

如 Zsolt Mester 的回答所示,onAttach(Activity activity) 已弃用,取而代之的是 onAttach(Context context)。因此,您需要做的就是检查以确保上下文是一个活动。

在 Android Studio 中,如果您转到 File > New > Fragment,您可以获得包含正确语法的自动生成代码。

import android.support.v4.app.Fragment;
...

public class MyFragment extends Fragment {

    private OnFragmentInteractionListener mListener;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // inflate fragment layout
        return inflater.inflate(R.layout.fragment_myfragment, container, false);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        void onFragmentInteraction(Uri uri);
    }
}

备注

  • 由于父 Activity 必须实现我们的 OnFragmentInteractionListener(任意命名的接口),因此检查 (context instanceof OnFragmentInteractionListener) 可确保上下文实际上是 Activity。

  • 请注意,我们正在使用支持库。否则,onAttach(Context context) 不会被 Android 的 API 23 之前的版本调用。

另请参阅

【讨论】:

    【解决方案3】:

    好吧,不推荐使用的是onAttach(Activity activity); 方法,但整个流程仍然存在。所以你可能什么都不做,因为onAttach(Activity activity); 仍然会得到足够长的支持。

    【讨论】:

      【解决方案4】:

      我从来没有使用过onAttach(Context context),但我认为你的代码基本上很好。所以这是我的建议,使用您的代码:

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

      主要区别在于我可以对context 进行类型转换以获取活动。这是因为 Context 可以传播到作为活动的子类。

      另一个问题,API 23 离现在还很远,让我们担心。如果您确实担心,使用构建编译指示(静态构建)可能是一个不错的选择。

      【讨论】:

      • 你应该直接转换上下文。或者,如果您希望上下文成为活动的实例。首先使用 if(context instanceof Activity) { ... } 检查
      • @Daverix,有趣的评论“你应该直接投射上下文”。请更具体。您是说对象上下文可以/应该直接转换为 mListener 吗?这会将代码从 2 行减少到只有 1 行。如果是这样,那只是编码风格的差异。
      • 是的,这可能是编码风格的差异,但 imo 仍然是不必要的行。否则最好使用“instanceof”而不是捕获 ClassCastExceptions。但最终可能只会为您节省更多的行数并获得最低的性能。
      【解决方案5】:

      我也遇到过同样的情况。我浏览了各种帖子,最后在片段的 onCreate() 块中实现了我的代码。到目前为止,我还没有遇到任何问题,我认为这不会是问题,因为 onCreate 在生命周期中的 onAttach 之后立即被调用。

       @Override
          public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
      
              try {
                  listnener = (TilesOnClickListnener)getActivity();
              } catch (ClassCastException e) {
                  throw new ClassCastException(getActivity().toString() + " must implement OnArticleSelectedListener");
              }
          }
      

      【讨论】:

      • 另外,我忘了提到将上下文投射到 Activity 对我来说效果不佳。
      • 为什么 Activity 投射效果不佳?如果您在 try / catch 块之外声明活动,对我来说效果很好 --- public void onAttach (Context context) { super.onAttach(context);活动活动=(活动)上下文;尝试 { mListener = (SellFragmentListener) 活动; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " 必须实现 SellFragmentListener"); } }
      • 太棒了!如果它正在工作。我没试过。谢谢你的信息。
      【解决方案6】:

      我使用原生的Fragment 而不是one from the Support Library。我将两个onAttach() 方法都放在我的代码中,并在运行不同SDK 版本的设备上进行了一些调试。我发现:

      SDK 22 及以下版本 - 仅调用 onAttach(Activity)。这并不奇怪,因为 onAttach(Context) 仅在 SDK 23 中引入。

      SDK 23 及更高版本 - 首先调用onAttach(Context)然后调用onAttach(Activity)。 (这与@Zsolt Mester 在这篇文章的另一个答案中关于源代码的说法一致。)

      由于我的应用程序的 minSdkVersion 低于 23,所以我决定完全省略 onAttach(Context),只需将 @SuppressWarnings("deprecation") 注释添加到我现有的 onAttach(Activity) 方法中。

      【讨论】:

        【解决方案7】:
         public class MainActivity extends AppCompatActivity implements  topsection.TopSectionListener {
        
         @Override
         protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
             setContentView(R.layout.activity_main);
         }
        
        
        
         public void createMeme(String top, String bottom){
            bottomsection fragmentbottom = (bottomsection) getSupportFragmentManager().findFragmentById(R.id.fragment2);
            fragmentbottom.setMemeText(top, bottom);
          }
         }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-01-10
          • 2013-05-21
          • 1970-01-01
          • 2015-11-12
          • 2021-12-01
          • 1970-01-01
          • 2021-09-30
          相关资源
          最近更新 更多