Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Saturday, March 5, 2016

Android. Fragment getActivity() sometime returns null

Android. Fragment getActivity() sometime returns null


In developer console error reports sometime I see reports with NPE issue. I do not understand what is wrong with my code. On emulator and my device application works good without forcecloses, however some users get NullPointerException in fragment class when the getActivity() method is called.

Activity

pulic class MyActivity extends FragmentActivity{        private ViewPager pager;       private TitlePageIndicator indicator;      private TabsAdapter adapter;        @Override      public void onCreate(Bundle savedInstanceState) {          pager = (ViewPager) findViewById(R.id.pager);          indicator = (TitlePageIndicator) findViewById(R.id.indicator);          adapter = new TabsAdapter(getSupportFragmentManager(), false);            adapter.addFragment(new FirstFragment());          adapter.addFragment(new SecondFragment());          indicator.notifyDataSetChanged();          adapter.notifyDataSetChanged();            // push first task          FirstTask firstTask = new FirstTask(MyActivity.this);          // set first fragment as listener          firstTask.setTaskListener((TaskListener) adapter.getItem(0));          firstTask.execute();      }        indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener()  {          @Override          public void onPageSelected(int position) {              Fragment currentFragment = adapter.getItem(position);              ((Taskable) currentFragment).executeTask();          }            @Override          public void onPageScrolled(int i, float v, int i1) {}            @Override          public void onPageScrollStateChanged(int i) {}      });  }  

AsyncTask class

public class FirstTask extends AsyncTask{        private TaskListener taskListener;        ...        @Override      protected void onPostExecute(T result) {          ...           taskListener.onTaskComplete(result);      }     }  

Fragment class

public class FirstFragment extends Fragment immplements Taskable, TaskListener{        public FirstFragment() {      }        @Override      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {          return inflater.inflate(R.layout.first_view, container, false);      }        @Override      public void executeTask() {          FirstTask firstTask = new FirstTask(MyActivity.this);          firstTask.setTaskListener(this);          firstTask.execute();      }        @Override      public void onTaskComplete(T result) {          // NPE is here           Resources res = getActivity().getResources();          ...      }  }  

Maybe this error happens when applications resumed from background. In this case how I should handle this situation properly?

Answer by Georgy Gobozov for Android. Fragment getActivity() sometime returns null


It seems that I found a solution to my problem. Very good explanations are given here and here. Here is my example:

pulic class MyActivity extends FragmentActivity{    private ViewPager pager;   private TitlePageIndicator indicator;  private TabsAdapter adapter;  private Bundle savedInstanceState;     @Override  public void onCreate(Bundle savedInstanceState) {        ....       this.savedInstanceState = savedInstanceState;      pager = (ViewPager) findViewById(R.id.pager);;      indicator = (TitlePageIndicator) findViewById(R.id.indicator);      adapter = new TabsAdapter(getSupportFragmentManager(), false);        if (savedInstanceState == null){              adapter.addFragment(new FirstFragment());          adapter.addFragment(new SecondFragment());      }else{          Integer  count  = savedInstanceState.getInt("tabsCount");          String[] titles = savedInstanceState.getStringArray("titles");          for (int i = 0; i < count; i++){              adapter.addFragment(getFragment(i), titles[i]);          }      }          indicator.notifyDataSetChanged();      adapter.notifyDataSetChanged();        // push first task      FirstTask firstTask = new FirstTask(MyActivity.this);      // set first fragment as listener      firstTask.setTaskListener((TaskListener) getFragment(0));      firstTask.execute();    }    private Fragment getFragment(int position){       return savedInstanceState == null ? adapter.getItem(position) : getSupportFragmentManager().findFragmentByTag(getFragmentTag(position));  }    private String getFragmentTag(int position) {      return "android:switcher:" + R.id.pager + ":" + position;  }     @Override  protected void onSaveInstanceState(Bundle outState) {      super.onSaveInstanceState(outState);      outState.putInt("tabsCount",      adapter.getCount());      outState.putStringArray("titles", adapter.getTitles().toArray(new String[0]));  }     indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {          @Override          public void onPageSelected(int position) {              Fragment currentFragment = adapter.getItem(position);              ((Taskable) currentFragment).executeTask();          }            @Override          public void onPageScrolled(int i, float v, int i1) {}            @Override          public void onPageScrollStateChanged(int i) {}   });  

The main idea in this code is that, while running your application normally, you create new fragments and pass them to the adapter. When you are resuming your application fragment manager already has this fragment's instance and you need to get it from fragment manager and pass it to the adapter.

UPDATE

Also, it is a good practice when using fragments to check isAdded before getActivity() is called. This helps avoid a null pointer exception when the fragment is detached from the activity. For example, an activity could contain a fragment that pushes an async task. When the task is finished, the onTaskComplete listener is called.

@Override  public void onTaskComplete(List result) {        progress.setVisibility(View.GONE);      progress.setIndeterminate(false);      list.setVisibility(View.VISIBLE);        if (isAdded()) {            adapter = new FeedAdapter(getActivity(), R.layout.feed_item, result);          list.setAdapter(adapter);          adapter.notifyDataSetChanged();      }    }  

If we open the fragment, push a task, and then quickly press back to return to a previous activity, when the task is finished, it will try to access the activity in onPostExecute() by calling the getActivity() method. If the activity is already detached and this check is not there:

if (isAdded())   

then the application crashes.

Answer by Pawan M for Android. Fragment getActivity() sometime returns null


The best to get rid of this is to keep activity reference when onAttach is called and use the activity reference wherever needed, for e.g.

@Override      public void onAttach(Activity activity) {          super.onAttach(activity);          mActivity = activity;      }  

Answer by blackvibes for Android. Fragment getActivity() sometime returns null


Don't call methods within the Fragment that require getActivity() until onStart in the parent Activity.

private MyFragment myFragment;      public void onCreate(Bundle savedInstanceState)  {      super.onCreate(savedInstanceState);        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();      myFragment = new MyFragment();        ft.add(android.R.id.content, youtubeListFragment).commit();        //Other init calls      //...  }      @Override  public void onStart()  {      super.onStart();        //Call your Fragment functions that uses getActivity()      myFragment.onPageSelected();  }  

Answer by Paul Freez for Android. Fragment getActivity() sometime returns null


Ok, I know that this question is actually solved but I decided to share my solution for this. I've created abstract parent class for my Fragment:

public abstract class ABaseFragment extends Fragment{        protected IActivityEnabledListener aeListener;        protected interface IActivityEnabledListener{          void onActivityEnabled(FragmentActivity activity);      }        protected void getAvailableActivity(IActivityEnabledListener listener){          if (getActivity() == null){              aeListener = listener;            } else {              listener.onActivityEnabled(getActivity());          }      }        @Override      public void onAttach(Activity activity) {          super.onAttach(activity);            if (aeListener != null){              aeListener.onActivityEnabled((FragmentActivity) activity);              aeListener = null;          }      }        @Override      public void onAttach(Context context) {          super.onAttach(context);            if (aeListener != null){              aeListener.onActivityEnabled((FragmentActivity) context);              aeListener = null;          }      }  }  

As you can see, I've added a listener so, whenever I'll need to get Fragments Activity instead of standard getActivity(), I'll need to call

 getAvailableActivity(new IActivityEnabledListener() {          @Override          public void onActivityEnabled(FragmentActivity activity) {              // Do manipulations with your activity          }      });  

Answer by user1868713 for Android. Fragment getActivity() sometime returns null


Since Android API level 23, onAttach(Activity activity) has been deprecated by onAttach(Context context). http://developer.android.com/reference/android/app/Fragment.html#onAttach(android.app.Activity)


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.