简体   繁体   中英

Android: Fragment is not attached to Activity error

So I'm working on an app and I had this part working for days, and out of no where it just stopped working for no reason...

I also had the same error when I was trying to use another headless fragment in my MainActivity, but ended up replacing the fragment with inner methods inside of the MainActivity and everything went back to working properly.

However, I can't rewrite every bit of code I have just to avoid using fragments. The fragment code is below.

public class IMEIFragment extends Fragment implements ActivityCompat.OnRequestPermissionsResultCallback{


    public static final String TAG_IMEI = "IMEILoader";
    protected Activity mActivity;

    private String RecordedIMEI;
    //public static final String CHECK_INTERNET = "network_connection";

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return null; //Do we need this at all?
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Activity activity = context instanceof Activity ? (Activity) context : null;
        mActivity = activity;
    }

    //Is this needed?
    @SuppressWarnings("deprecation")

    @Override
    public void onAttach(Activity activity) {
        activity = getActivity();
        if (isAdded() && activity != null) {
            super.onAttach(activity);
        }

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            mActivity = activity;
        }
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

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

    public String loadIMEI(Context context) {
        if (Build.VERSION.SDK_INT >= 23) {
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE)
                    != PackageManager.PERMISSION_GRANTED) {
                // READ_PHONE_STATE permission has not been granted.
                requestPermissions(context);
            } else {
                // READ_PHONE_STATE permission is already been granted.
                RecordedIMEI = permissionGrantedActions(context);
            }
            if (RecordedIMEI != null) {
                Log.i("loadIMEIService", "IMEI number returned!");
            }
        } else {
            // READ_PHONE_STATE permission is already been granted.
            RecordedIMEI = permissionGrantedActions(context);
        }
        if (RecordedIMEI != null) {
            Log.i("loadIMEIService", "IMEI number returned!");
        }
        return RecordedIMEI;
    }
    private void requestPermissions(Context context) {
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            Log.i("loadIMEIService", "READ_PHONE_STATE permission not granted, asking for it...");

            // TODO create proper notification content


            PermissionHelper.requestPermissions(((PriceActivity) getActivity()),
                    new String[]{Manifest.permission.READ_PHONE_STATE},
                    Constants.PERM_REQUEST_PHONE_STATE,
                    getString(R.string.notify_perm_title),
                    getString(R.string.notify_perm_body),
                    R.drawable.ic_security);
        }
    }

    // Callback received when a permissions request has been completed.
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        boolean isGranted = false;
        for (int i = 0; i < grantResults.length; i++)
            if (permissions[i].equals(Manifest.permission.READ_PHONE_STATE) && (grantResults[i] == PackageManager.PERMISSION_GRANTED))
                isGranted = true;
        if (isGranted) {
            Context context = getActivity().getApplicationContext();
            permissionGrantedActions(context);
        }
        else
            Log.w("loadIMEIService", "READ_PHONE_STATE permission not granted. loadIMEI will not be available.");
    }


    public String permissionGrantedActions(Context context) {
        //Have an  object of TelephonyManager
        TelephonyManager tm =(TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
        //Get IMEI Number of Phone
        String IMEINumber = tm.getDeviceId();

        if(IMEINumber != null) {
            Log.i("loadIMEIService", "IMEI number recorded!");
        }
        return IMEINumber;
    }
}

Error is below:

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.android.project1, PID: 5498
                  java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.project1/com.android.project1.main.MainActivity}: java.lang.IllegalStateException: Fragment IMEIFragment{3e80da7 IMEILoader} not attached to Activity
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
                      at android.app.ActivityThread.-wrap11(ActivityThread.java)
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
                      at android.os.Handler.dispatchMessage(Handler.java:102)
                      at android.os.Looper.loop(Looper.java:148)
                      at android.app.ActivityThread.main(ActivityThread.java:5417)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
                   Caused by: java.lang.IllegalStateException: Fragment IMEIFragment{3e80da7 IMEILoader} not attached to Activity
                      at android.app.Fragment.getResources(Fragment.java:805)
                      at android.app.Fragment.getString(Fragment.java:827)
                      at com.android.project1.fragments.IMEIFragment.requestPermissions(IMEIFragment.java:107)
                      at com.android.project1.fragments.IMEIFragment.loadIMEI(IMEIFragment.java:80)
                      at com.android.project1.main.MainActivity.onCreate(MainActivity.java:108)
                      at android.app.Activity.performCreate(Activity.java:6237)
                      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
                      at android.app.ActivityThread.-wrap11(ActivityThread.java) 
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
                      at android.os.Handler.dispatchMessage(Handler.java:102) 
                      at android.os.Looper.loop(Looper.java:148) 
                      at android.app.ActivityThread.main(ActivityThread.java:5417) 
                      at java.lang.reflect.Method.invoke(Native Method) 
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

And here's the relevant part of my MainActivity:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mDeviceCode = (TextView) findViewById(R.id.device_code);

        // Initializing headless fragment
        mFragment =
                (IMEIFragment) getFragmentManager()
                        .findFragmentByTag("IMEILoader");

        if (mFragment == null) {
            mFragment = new IMEIFragment();
            getFragmentManager().beginTransaction()
                    .add(mFragment, "IMEILoader").commit();
        }
        if (mFragment != null) {
            mNumber = mFragment.loadIMEI(MainActivity.this);
            mDeviceCode.setText(Html.fromHtml("<b>IMEI</b>: " + mNumber));
        }

I literally had the exact same code working for over a week. Anyone knows what could be the problem?

Edit 1: The error is pointing to requestPermissions inside my fragment

Fragments should be self contained as much as possible. You are calling directly into your IMEIFragment from the activity,

           Caused by: java.lang.IllegalStateException: Fragment IMEIFragment{3e80da7 IMEILoader} not attached to Activity
              at android.app.Fragment.getResources(Fragment.java:805)
              at android.app.Fragment.getString(Fragment.java:827)
              at com.android.project1.fragments.IMEIFragment.requestPermissions(IMEIFragment.java:107)
              at com.android.project1.fragments.IMEIFragment.loadIMEI(IMEIFragment.java:80)
              at com.android.project1.main.MainActivity.onCreate(MainActivity.java:108)

You can't do that. Adding the fragment via a transaction from the activity is an asynchronous operation. Eg, when the commit() method completes, the fragment is not initialized. Moreover, you have no way of knowing when it's initialized. That's why it should be self contained. The fragment decides when to call loadIMEI(), not the activity.

If you really need it to be initiated by the activity, you can add a callback from the fragment to the activity like,

void onFragmentReady(Fragment f);

Or something.

And yes, onCreateView() should return something. If your fragment really doesn't have any UI at all, you don't need it to be a fragment.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM