In developer console error reports sometimes 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?
Don't call methods within the Fragment that require getActivity() until onStart in the parent Activity.
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.Edited, since
onAttach(Activity)
is depreciated & nowonAttach(Context)
is being usedOk, 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
:As you can see, I've added a listener so, whenever I'll need to get
Fragments
Activity
instead of standardgetActivity()
, I'll need to callI know this is a old question but i think i must provide my answer to it because my problem was not solved by others.
first of all : i was dynamically adding fragments using fragmentTransactions. Second: my fragments were modified using AsyncTasks (DB queries on a server). Third: my fragment was not instantiated at activity start Fourth: i used a custom fragment instantiation "create or load it" in order to get the fragment variable. Fourth: activity was recreated because of orientation change
The problem was that i wanted to "remove" the fragment because of the query answer, but the fragment was incorrectly created just before. I don't know why, probably because of the "commit" be done later, the fragment was not added yet when it was time to remove it. Therefore getActivity() was returning null.
Solution : 1)I had to check that i was correctly trying to find the first instance of the fragment before creating a new one 2)I had to put serRetainInstance(true) on that fragment in order to keep it through orientation change (no backstack needed therefore no problem) 3)Instead of "recreating or getting old fragment" just before "remove it", I directly put the fragment at activity start. Instantiating it at activity start instead of "loading" (or instantiating) the fragment variable before removing it prevented getActivity problems.
I've been battling this kind of problem for a while, and I think I've come up with a reliable solution.
It's pretty difficult to know for sure that
this.getActivity()
isn't going to returnnull
for aFragment
, especially if you're dealing with any kind of network behaviour which gives your code ample time to withdrawActivity
references.In the solution below, I declare a small management class called the
ActivityBuffer
. Essentially, thisclass
deals with maintaining a reliable reference to an owningActivity
, and promising to executeRunnable
s within a validActivity
context whenever there's a valid reference available. TheRunnable
s are scheduled for execution on the UI Thread immediately if theContext
is available, otherwise execution is deferred until thatContext
is ready.In terms of its implementation, we must take care to apply the life cycle methods to coincide with the behaviour described above by Pawan M:
Finally, in any areas within your
Fragment
that extendsBaseFragment
that you're untrustworthy about a call togetActivity()
, simply make a call tothis.getActivityBuffer().safely(...)
and declare anActivityBuffer.IRunnable
for the task!The contents of your
void run(final Activity pActivity)
are then guaranteed to execute along the UI Thread.