android - getView returning null when fragment has been created from an activity

android - getView returning null when fragment has been created from an activity

Lenuța Robert Author: Lenuța Robert Date: 2022-08-19
android - getView returning null when fragment has been created from an activity

All you need to know about android - getView returning null when fragment has been created from an activity , in addintion to android - Java solution for "startActivityForResult(Intent,int) in Fragment has been deprecated" when opening external URL? , android - getActivity() return null after returning from a dialogFragment , android - IllegalStateException: Activity has been destroyed - when app is trying to show DialogFragment once more time , android - Very simple code, but got error "Activity has been destroyed" when use Fragment

  1. android - getView returning null when fragment has been created from an activity
  2. Question:

    I have a working tablet application which I am now trying to make work on phones too. On a table there is two fragments on the screen a list fragment and a details fragment. When on a phone the list fragment appears and creates a new activity when a list item is pressed. This activity simply creates the fragment in the onCreate() method and commits it to the screen as follows.

    // Place an DeallDetailsFragment as our content pane
    DealDetailsFragment f = new DealDetailsFragment();
    getFragmentManager().beginTransaction().add(android.R.id.content, f).commit();
    getFragmentManager().executePendingTransactions();
    

    This is working as expected however from within this activity I need to tell the fragment what details to load and display. In my DealDetailsFragment class I have a updateDeal() method which updates the content as follows.

    if (deal==null) { // could be null if user presses the loading deals list item before it loads
        return;
    }
    this.deal=deal;
    if (dealTitle==null) { // get the view objects only once
        holder = new ViewHolder();  
        holder.dealHeat=(TextView) getView().findViewById(R.id.dealDetails_heat_textView);
        holder.dealPrice=(TextView) getView().findViewById(R.id.dealDetails_price_textView);
        holder.dealRetailer=(TextView) getView().findViewById(R.id.dealDetails_retailer_textView);
        holder.dealTitle=(TextView) getView().findViewById(R.id.dealDetails_title_textView);
        holder.dealDesc=(TextView) getView().findViewById(R.id.dealDetails_desc_textView);
        holder.goToButton= (LinearLayout) getView().findViewById(R.id.dealDetails_goToDeal);
        holder.dealImage=(ImageView) getView().findViewById(R.id.dealDetails_imageView);
        holder.postedBy=(TextView) getView().findViewById(R.id.dealDetails_poster_textView);
        holder.datePosted=(TextView) getView().findViewById(R.id.dealDetails_date_textView);
    

    getView() is returning null when the application is ran on a phone where there is only a single fragment shown.

    Any ideas? Unfortunately, there is not many fragment examples available online.


    Solution 1:

    Move your method call to be executed during onCreateView, and use the view you are inflating for reference instead of getView(). See the fragment lifecycle for more information: https://developer.android.com/guide/components/fragments.html#Creating

    and the documentation of getView() that explains why it returns null before onCreateView(LayoutInflater, ViewGroup, Bundle) returns:

    getView() Get the root view for the fragment's layout (the one returned by onCreateView(LayoutInflater, ViewGroup, Bundle)), if provided.

    https://developer.android.com/reference/android/app/Fragment.html#getView()

    Solution 2:

    Moving the method to onCreateView() did not help me.so... Create a global variable mView

    protected View mView;
    

    and in onCreateView()

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
      Log.d(TAG, "oncreateView");
      super.onCreateView(inflater, container, savedInstanceState);
    
      View view = inflater.inflate(R.layout.activity_secure_cloud_drive_folder, container, false);
      this.mView = view;
      return view;
    }
    

    and the replace all your getView() with mView

    Solution 3:

    You can fix that by putting your code inside the onViewCreated()-method, which you should override. Don't forget to call super() on it.

  3. android - Java solution for "startActivityForResult(Intent,int) in Fragment has been deprecated" when opening external URL?
  4. Question:

    My app contains a simple Fragment that is used to open external web pages, with:

    Intent intent = new Intent(Intent.ACTION_VIEW, externalUrl); // Uri
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    Intent chooserIntent = Intent.createChooser(intent, "Open URL...");
    startActivityForResult(chooserIntent, RC_OPEN_URL);
    

    And, when the result is returned (in my Fragment's onActivityResult(...)), the Fragment is popped off the backstack.

    But, I'm now getting the new deprecation warning:

    startActivityForResult(Intent,int) in Fragment has been deprecated

    I've read the corresponding Getting a result from an activity documentation, but I'm not sure how to adapt the example they provide for my particular case.

    I have discovered the ActivityResultContracts.StartActivityForResult class, but can't figure out how to pass my chooserIntent to it.

    All the online examples for the class seem to be in Kotlin and I've not had any joy trying to decompile them to Java. So a Java example of how to use the new registerForActivityResult() method to open an external URL would be much appreciated.


    Solution 1:

    There's no reason to use startActivityForResult() at all for createChooser() - you can use startActivity and run your code from onActivityResult() immediately after you call to startActivity:

    Intent intent = new Intent(Intent.ACTION_VIEW, externalUrl); // Uri
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    Intent chooserIntent = Intent.createChooser(intent, "Open URL...");
    startActivity(chooserIntent);
    // Do your code from onActivityResult() here
    

    However, if you really want to use the Activity Result API, then you can directly adapt the examples in the documentation, replacing the example GetContent contract with the StartActivityForResult contract:

    // Create this as a variable in your Fragment class
    ActivityResultLauncher<Intent> mLauncher = registerForActivityResult(
        new StartActivityForResult(),
        new ActivityResultCallback<ActivityResult>() {
            @Override
            public void onActivityResult(ActivityResult result) {
                // Do your code from onActivityResult
            }
    });
    
    private void triggerChooser(Uri externalUri) {
        Intent intent = new Intent(Intent.ACTION_VIEW, externalUrl); // Uri
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        Intent chooserIntent = Intent.createChooser(intent, "Open URL...");
        mLauncher.launch(chooserIntent);
    }
    

    Solution 2:

    Below answer may help to someone.... But this is not readymade solution to above question.

    I have faced lot of issue when I try to get result from activity to fragment. Finally I found below solution.

    In side the fragment, I created ActivityResultLauncher.

    var myActivityResultLauncher: ActivityResultLauncher<Intent> = registerForActivityResult<Intent, ActivityResult>(
            ActivityResultContracts.StartActivityForResult(),
            ActivityResultCallback<ActivityResult> {
                // ToDO: 
                if (it.resultCode == AppCompatActivity.RESULT_OK) {
    
                }
            }
    ) as ActivityResultLauncher<Intent>
    

    And when I start the activity I used below code.

    myActivityResultLauncher.launch(myIntent)
    

  5. android - getActivity() return null after returning from a dialogFragment
  6. Question:

    I'm currently experiencing some troubles with DialogFragment.

    My application look like this :

    A MainActivity using ActionBarSherlock to display 6 tabs ( wich all contains a fragment ) On one of those tabs, I show a DialogFragment when the user click a button. This dialog contains some EditText and a button wich save the user input (A postal address) and call a listener in the MainActivity for computing.

    My problem is when I turn screen with the dialog up, I managed to make him stay on the screen without losing data but when I call for the listener and then dismiss the dialog, a method is called in the fragment to add the new postal address to a list which is then mapped on a ListView and in this method getActivity() returns null.

    I guess the fragment is not yet attached and/or created since my breakpoint in onResume() never break the execution. But i can't see a way to make sure my fragment is created when the listener call for the list update.

    I'll be happy to provide further informations if you have any idea that can help me here, Google didn't helped much this time :(


    Solution 1:

    Hey I had the same problem yesterday. Check out this thread for two fixes :

    DialogFragment causing nullpointer crash

  7. android - IllegalStateException: Activity has been destroyed - when app is trying to show DialogFragment once more time
  8. Question:

    I have found a lot of similar questions on the stackoverflow but their solutions don't work in my case. They are connected with onSaveInstanceState method and the Support Library especially.

    I have Activity which runs on one event this code:

    MyDialogFragment.showMyDialog(name, this, this);
    

    name parameter is the String object. Second parameter (this) is the just Activity class object and the third one (also this) is the simple interface. This my Activity implements this interface. showMyDialog() is of course static method. This is it body:

    MyDialogFragment fragment = new MyDialogFragment(listener, "Hello " + name);
    fragment.show(activity.getFragmentManager(), "myDialog");
    

    This is working good at the first try. But at the second I am getting this exception:

    E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.example.myapp, PID: 20759
    java.lang.IllegalStateException: Activity has been destroyed
            at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1345)
            at android.app.BackStackRecord.commitInternal(BackStackRecord.java:597)
            at android.app.BackStackRecord.commit(BackStackRecord.java:575)
            at android.app.DialogFragment.show(DialogFragment.java:230)
            at com.example.myapp.view.dialog.MyDialogFragment.showMyDialog(MyDialogFragment.java:41)
            at com.example.myapp.MyActivity.showMyDialog(MyActivity.java:208)
            at com.example.myapp.MyActivity.onEvent(MyActivity.java:232)
            at com.example.myapp.MyActivity.handleMessage(MyActivity.java:89)
            at android.os.Handler.dispatchMessage(Handler.java:98)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5017)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
            at dalvik.system.NativeStart.main(Native Method)
    

    In general this is the steps to reproduce my exception:

    1. Enter Activity - event is received so MyDialogFragment is shown.
    2. Dismiss dialog by negative button.
    3. Enter Activity once more time - MyDialogFragment is shown again.
    4. Type some code to the EditText.
    5. At this moment validation take some time. Connecting with server etc. And the negative result is returned. So it is need to show MyDialogFragment once more. But at this moment I am getting exception.

    However, when I skip the second point and start to typing wrong code for validation, MyDialogFragment will be shown without any issue. Strange behaviour.

    I have tried with non-static method, setRetainInstance(true) and also commitAllowingStateLoss. But there was no difference.


    Solution 1:

    It is a bit odd - or maybe just a bug in this Android functionality. I have added block try catch to catch throwing exception in this way:

    MyDialogFragment fragment = new MyDialogFragment(listener, "Hello " + name);
    try {
        fragment.show(activity.getFragmentManager(), "myDialog");
    } catch (Exception e) {
        e.printStackTrace();
    }
    

    And of course exception is still throwing (and catching at this moment) and what is interesting my dialog fragment is recreating in correct way and user can interact with it.

    Solution 2:

    In the method showMyDialog() first try :

    MyDialogFragment fragment = activity.findFragmentByTag("myDialog");
    

    if (fragment == null), then initialize :

    MyDialogFragment fragment = new MyDialogFragment(listener, "Hello " + name);
    

    else show it :

    fragment.show(activity.getFragmentManager(), "myDialog");
    

    UPDATE :

    void showMyDialog() {
        MyDialogFragment fragment = activity.getFragmentManager().findFragmentByTag("myDialog");
        if (fragment == null) {
            fragment = new MyDialogFragment(listener, "Hello " + name);
        }
        fragment.show(activity.getFragmentManager(), "myDialog");
    }
    

    Solution 3:

    (For API 17 and up)

    In case anyone is still having this problem (or even related with a transaction's commit() method) I just added a check before it:

    private showFragment() {
        if (isDestroyed()) {
            return;
        }
    
        // Else do whatever transaction...
    }
    

  9. android - Very simple code, but got error "Activity has been destroyed" when use Fragment
  10. Question:

    I made a very simple Activity which shows a simple ListFragment like below:

    My Activity:

    public class MyActivity extends FragmentActivity {
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
              FragmentManager fragMgr = getSupportFragmentManager();
    
              FirstFragment list = new FirstFragment();
              fragMgr.beginTransaction().add(android.R.id.content, list).commit();
        }
    
    }
    

    My ListFragment:

    public class FirstFragment extends ListFragment{
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            inflater.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
            View view = inflater.inflate(R.layout.main, null);
            return view;
        }
    
    
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
    
            String listContent[] = {"Larry", "Moe", "Curly"}; 
            setListAdapter(new ArrayAdapter<String>(getActivity(), R.layout.list_item, listContent));
        }
       ...
    }
    

    When I start my app, I got error message:

     java.lang.IllegalStateException: Activity has been destroyed
    E/AndroidRuntime(  947):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2496)
    E/AndroidRuntime(  947):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512)
    E/AndroidRuntime(  947):    at android.app.ActivityThread.access$2200(ActivityThread.java:119)
    E/AndroidRuntime(  947):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863)
    E/AndroidRuntime(  947):    at android.os.Handler.dispatchMessage(Handler.java:99)
    E/AndroidRuntime(  947):    at android.os.Looper.loop(Looper.java:123)
    E/AndroidRuntime(  947):    at android.app.ActivityThread.main(ActivityThread.java:4363)
    E/AndroidRuntime(  947):    at java.lang.reflect.Method.invokeNative(Native Method)
    ...
    

    It complains that Activity has been destroyed, Why???

    P.S. main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="vertical"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:paddingLeft="8dp"
      android:paddingRight="8dp">
    
      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="next" />
    
      <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#00FF00"
        android:layout_weight="1"
        android:drawSelectorOnTop="false" />
    
      <TextView
        android:id="@android:id/empty"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#FF0000"
        android:text="No data" />
    </LinearLayout>
    


    Solution 1:

    I also faced a similar problem.
    I realized that this happened because the activity was being destroyed while the FragmentTransaction was about to get .commit().

    A solution to this was to check whether the Activity.isFinishing() is true or not.

    if (!isFinishing()) {
      FragmentTransaction ft = getSupportFragmentManager()
         .beginTransaction();
      ft.replace(SOME_RES_ID, myFragmentInstance);
      ft.commit();
    }
    

    Solution 2:

    I figured out myself, It is because I missed the super.onCreate(savedInstanceState); in my Activity onCreate() method . After added this, things are fine.

    Solution 3:

    I faced the same issue and unable to fix it. Event I added isFinishing() check as well. but no luck.

    then I added one more check isDestroyed() and its working fine now.

    if (!isFinishing() && !isDestroyed()) {
      FragmentTransaction ft = getSupportFragmentManager()
         .beginTransaction();
      ft.replace(LAYOUT_ID, myFragmentInstance);
      ft.commit();
    }