72

I've updated the SDK to the latest version (API 23) and the onAttach(Activity) method for fragment is deprecated. So instead of using that method, now I'm using onAttach(Context) but this one is not called during the lifecycle. The activity is an instance of AppCompatActivity from v7 and the fragment is an instance of class Fragment (android.app.Fragment).

Any ideas how to get the onAttach working in API 23?

Solution

I found some answers that can help you to understand and fix this problem:

  • As I mentioned before I’m using the activity from support v7 (AppCompatActivity) and the fragment from android.app.

  • For showing fragments I get the fragment manager using the method getFragmentManager on the activity, so the fragment manager is an instance of FragmentManager from android.app -> and here is the problem

  • If you run the application on a device with API 23 (I’ve run it on the AS Emulator), you’ll see that the onAttach(Context) method will be called. During the process for showing a fragment by the FragmentManager, at a specific moment the onAttach(..) method is called. Using the getFragmentManager() you’ll get an instance of the fragment manager available for the Android version which is running on that device (for example API 22, 23). In case the application is running on a device with API < 23 the onAttach(Context) method is not available, the fragment manager doesn’t know that in API 23 there is a method onAttach(Context), so that’s why it is not called for the API < 23 -> the solution for this kind of problems is using the FragmentManager from support libraries.

  • Solutions:

    1. Using getSupportFragmentManager() will force you to use a Fragment from the support lib. So the first solution is to replace all fragments with the fragment from support lib and using getSupportFragmentManager().

    2. Solution that I've already implemented is to handle 2 possibilities (1. the app is running on a device with API < 23, the app is running on a device with API >= 23).

    Shortly, in my implementation I have a base class for all fragments from the project and I added this code there:

    /*
     * onAttach(Context) is not called on pre API 23 versions of Android and onAttach(Activity) is deprecated
     * Use onAttachToContext instead
     */
    @TargetApi(23)
    @Override
    public final void onAttach(Context context) {
        super.onAttach(context);
        onAttachToContext(context);
    }
    
    /*
     * Deprecated on API 23
     * Use onAttachToContext instead
     */
    @SuppressWarnings("deprecation")
    @Override
    public final void onAttach(Activity activity) {
        super.onAttach(activity);
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            onAttachToContext(activity);
        }
    }
    
    /*
     * Called when the fragment attaches to the context
     */
    protected void onAttachToContext(Context context) {
    }
    

    Now I simply override the onAttachToContext(Context) method on all fragments where I need this.

    David Rauca
    • 1,583
    • 1
    • 14
    • 17
    • 1
      Do you have `@Override` on your `onAttach(Context)`? If not, add it. If you then get a compiler error complaining that there is no `onAttach(Context)`, make sure that you are on v23 of `appcompat-v7`. – CommonsWare Aug 18 '15 at 15:56
    • 1
      Yes. I have @Override on onAttach(Context). Also the version for v7 is 23.0.0. – David Rauca Aug 18 '15 at 15:58
    • 1
      Just tested that. My activity extends `AppCompatActivity` too. I've overriden `onAttach(Activity)` and `onAttach(Context)` and both were called for me. Tested with Nexus 5 (MPA44G), minSdk = 16, targetSdk = 23. – Mygod Aug 19 '15 at 01:19
    • Did you use the android.app.Fragment or the fragment from support lib. How did you replace/add the fragment.. Did you use "getFragmentManager()" or "getSupportFragmentManager()"? Tested with fragment from support lib and it works for me also. No result using fragment from android.app and getFragmentManager(). – David Rauca Aug 19 '15 at 07:07
    • I`m having the same problem after upgrading to the latest support library. Did you manage to find a solution? – TareK Khoury Aug 20 '15 at 19:44
    • 2
      Not yet. I've tried with support v4 and it works. You could try using support v4. – David Rauca Aug 21 '15 at 08:49
    • I have exactly the same problem. AppCompatActivity from v7 and the fragment from android.app.Fragment. The method onAttach(Context context) is not called. It seems I have to use v4 or keep deprecated method onAttach(Activity activity). – xXx_CodeMonkey_xXx Aug 26 '15 at 14:44
    • Despite using the Base class Fragment doesn't fit my approach because I don't use it, this is the right solution. I used a Singleton to handle the fragments "onAttach" in order to avoid duplicated code. Thank you – Alberto Méndez Dec 29 '15 at 10:25
    • Why are you checking `(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) `? It is not a redundancy? – Wédney Yuri Jan 13 '16 at 12:18
    • 2
      @WédneyYuri according to [this answer](http://stackoverflow.com/a/32096272/1214974), both onAttach(Context) AND onAttach(Activity) are called on a device running API level 23. As a result, you need the above check to make sure that the work you do as part of onAttach is not carried out twice on a device that is running API level 23. – Janus Varmarken Jan 25 '16 at 18:22
    • onAttach(Context) is called **only** on API 23 and inside super method the framework calls onAttach(Activity) but for this case I did a check on onAttach(Activity), so onAttachToContext won't be called twice. – David Rauca Jan 26 '16 at 09:21
    • @DavidRauca, please accept an answer for the sake of other people that end up here. IMO ghostFaceCoder answer is correct. If you want to use a new API on a platform that doesn't support it, you use the Support library. – Ben Mar 02 '16 at 18:48
    • I've already added the solution below the question and I added it before other answers. – David Rauca Mar 03 '16 at 11:23
    • Awesome solution, David! Very useful! I cannot use the v4 `Fragment` (support lib) because of some app constraints and yet my app needs to run on phones with as low as API 17. Your solution is the perfect answer to my dilemma! – Ishita Sinha Jul 28 '16 at 08:00

    7 Answers7

    28

    I solved the problem in this way:

    @TargetApi(23)
    @Override public void onAttach(Context context) {
        //This method avoid to call super.onAttach(context) if I'm not using api 23 or more
        //if (Build.VERSION.SDK_INT >= 23) {
            super.onAttach(context);
            onAttachToContext(context);
        //}
    }
    
    /*
     * Deprecated on API 23
     * Use onAttachToContext instead
     */
    @SuppressWarnings("deprecation")
    @Override public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (Build.VERSION.SDK_INT < 23) {
            onAttachToContext(activity);
        }
    }
    
    /*
     * This method will be called from one of the two previous method
     */
    protected void onAttachToContext(Context context) {}
    
    Francesco Florio
    • 1,184
    • 14
    • 16
    • 3
      Regarding onAttach(Context).. the method won't be called for API < 23, so you don't need that check the version inside. – David Rauca Jan 26 '16 at 09:31
    • onDetach() also not called. How to do if I want to set `this.context = null`? – Honghe.Wu Aug 03 '16 at 09:19
    • E/AndroidRuntime: FATAL EXCEPTION: main, java.lang.ClassCastException:, at com.fragment.fragment_home_new.onAttachToContext, at com.fragment.fragment_home_new.onAttach, at android.support.v4.app.FragmentManagerImpl.moveToState, Here i added some necessary lines of my bug. Plz help me resolve this issue. thanks in advance. – MohanRaj S Aug 06 '16 at 06:42
    18

    You should try using the Support library version of Fragment.

    You need to switch to import android.support.v4.app.Fragment; instead of import android.app.Fragment;. You'll also need to make sure you're using getSupportFragmentManager() instead of getFragmentManager().

    • I think this is the right answer. I assumed I could use the built in Fragment because I'm targeting SDK version 18, but the Fragment API has differences across various SDK versions. The Support library Fragment is consistent across versions and as such, it calls onAttach(Activity activity). – Ben Mar 02 '16 at 18:41
    • Say you want to use the PreferenceFragment which doesn't come in the support library, And you wish to add that as one of the fragment in a navigation drawer your solution to switch to support fragment wont work – Jayshil Dave May 23 '16 at 15:57
    6

    pleas post about this BUG here

    ISSUE OPPENED ON GOOGLE AOSP PROJECT HOMESITE:

    https://code.google.com/p/android/issues/detail?id=185465

    ps. this is not your job to search for solution to this problem & to find any kind of workarounds .. but to force google to fix its broken API! to do this u need to complain as i said.

    related issue - getContext() from fragment:

    https://code.google.com/p/android/issues/detail?id=185848

    ceph3us
    • 7,326
    • 3
    • 36
    • 43
    5

    I came up with the same issue. I have a minSdkVersion of 19 and a targetSdkVersion of 23 and I am using fragmentManager in an AppCompatActivity.

    onAttach(Activity activity) is marked as deprecated but I ran into app crashes when I replaced it with onAttach(Context context).

    So instead, I now have both versions present and when I run my app on API22, onAttach(Activity activity) is fired, even though it is marked as deprecated.

    I have not tested it on an Android Marshmallow device, but my understanding is that it would run the onAttach(Context context) version, ignoring the other one.

    Update to take into account @skaar's observation in the comments below: I could now test on API23 and can confirm that running on platform 23 causes both methods (with Activity and Context) to be called. Thanks for the heads up!

    0x4e84
    • 66
    • 1
    • 5
    • can anybody confirm this? – Martin Mlostek Sep 09 '15 at 16:43
    • This behavior is what I see, except the last statement. Assuming you are using android.app.Fragment and not the support library version. If your compile/target version is 23, the Fragment.onAttach(Activity) method is deprecated. However you still to use onAttach(Activity) if you are targeting platforms < 23, since they will not have the onAttach(Context) method. Also, *both* methods will be called if you run on device with platform version 23. – vman Sep 14 '15 at 23:22
    4

    After I read your answer @David Rauca I think the second one can solve my problem. But when I look into the source code. I found that actually, onAttach(Context context) do nothing on Android M, just called the old method.

    As a solution:

    @SuppressWarnings("deprecation")
    

    Just add it into the old method is the best solution.

    Tony Zhang
    • 61
    • 4
    3

    I have encountered the same problem. What I have done to resolve it:

    1. Change the argument type of onAttach callback from Activity to Context. For unknown reason, this modification results in the fact that the method onAttach(Context) is not called anymore during the fragment lifecycle. As a consequence, my app was crashing since the code that was in onAttach method has never been executed.

    2. Move the code that was in onAttach method to onCreate one since it gets still executed.

    With this modification, the app turns to functionate as before. No additional import statements were required.

    Andrew
    • 2,148
    • 5
    • 23
    • 34
    1
    @Override
    public void onAttach(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            super.onAttach(context);
            onAttachToContext(context);
        } else {
            Activity activity = getActivity();
            super.onAttach(activity);
            onAttachToContext(activity);
        }
    }
    
    Hayk Mkrtchyan
    • 2,835
    • 3
    • 19
    • 61