In activity in Toolbar I got a button which need to call method from fragment and update list in that fragment. Now it is an error.
Calling in activity
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.menu_sort:
ListFragment listFragment = new ListFragment();
listFragment.sortByPopularity();
break;
}
return super.onOptionsItemSelected(item);
}
Fragment code. I have found an error when Activity not attached. But nothing with context
public class ListFragment extends Fragment implements ListAdapter.ItemClickListener {
/**
* Needed
*/
RecyclerView recyclerView;
View view;
List<BasePojo.Result> list;
ListAdapter listAdapter;
public ListFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
/**
* Main Initialization
*/
view = inflater.inflate(R.layout.fragment_list, container, false);
recyclerView = view.findViewById(R.id.recycler_list_detailed);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 2));
list = new ArrayList<>();
listAdapter = new ListAdapter(list, setOnItemClickCallback());
recyclerView.setAdapter(listAdapter);
RetrofitClient.getApiService().getPhotosList(getString(R.string.api_key)).enqueue(new Callback<BasePojo>() {
#Override
public void onResponse(Call<BasePojo> call, Response<BasePojo> response) {
BasePojo basePojo = response.body();
list.addAll(basePojo.getResults());
recyclerView.getAdapter().notifyDataSetChanged();
}
#Override
public void onFailure(Call<BasePojo> call, Throwable t) {
Log.d("tag", "Response failed" + t.toString());
}
});
return view;
}
#Override
public void onItemClick(View view, int position) {
Log.v("in on click", "value " + position);
}
private OnItemClickListener.OnItemClickCallback setOnItemClickCallback() {
OnItemClickListener.OnItemClickCallback onItemClickCallback = new OnItemClickListener.OnItemClickCallback() {
#Override
public void onItemClicked(View view, int position) {
BasePojo.Result itemClicked = list.get(position);
Bundle bundle = new Bundle();
bundle.putString("title", itemClicked.getOriginalTitle());
bundle.putString("overview", itemClicked.getOverview());
bundle.putString("release_date", itemClicked.getReleaseDate());
bundle.putString("vote_average", itemClicked.getVoteAverage().toString());
bundle.putString("poster_path", itemClicked.getPosterPath());
DetailedFragment detailedFragment = new DetailedFragment();
detailedFragment.setArguments(bundle);
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.main_frame_list, detailedFragment);
Log.d("tag", "title is 111 " + bundle.get("title"));
transaction.commit();
}
};
return onItemClickCallback;
}
#Override
public void onAttachFragment(Fragment childFragment) {
super.onAttachFragment(childFragment);
}
public void sortByPopularity() {
RetrofitClient.getApiService().getPopularList(getString(R.string.api_key)).enqueue(new Callback<BasePojo>() {
#Override
public void onResponse(Call<BasePojo> call, Response<BasePojo> response) {
BasePojo basePojo = response.body();
list.addAll(basePojo.getResults());
recyclerView.getAdapter().notifyDataSetChanged();
}
#Override
public void onFailure(Call<BasePojo> call, Throwable t) {
Log.d("tag", "Response failed" + t.toString());
}
}); }
}
And here is an error
05-09 12:48:26.915 5775-5775/com.borisruzanov.popularmovies E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.borisruzanov.popularmovies, PID: 5775
java.lang.IllegalStateException: Fragment ListFragment{6dbd6de} not attached to a context.
at android.support.v4.app.Fragment.requireContext(Fragment.java:614)
at android.support.v4.app.Fragment.getResources(Fragment.java:678)
at android.support.v4.app.Fragment.getString(Fragment.java:700)
at com.borisruzanov.popularmovies.ListFragment.sortByPopularity(ListFragment.java:110)
at com.borisruzanov.popularmovies.MainActivity.onOptionsItemSelected(MainActivity.java:47)
at android.app.Activity.onMenuItemSelected(Activity.java:3204)
at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:407)
at android.support.v7.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:195)
at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:108)
at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:108)
at android.support.v7.app.ToolbarActionBar$2.onMenuItemClick(ToolbarActionBar.java:63)
at android.support.v7.widget.Toolbar$1.onMenuItemClick(Toolbar.java:203)
at android.support.v7.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:780)
at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:822)
at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:171)
at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:973)
at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:963)
at android.support.v7.widget.ActionMenuView.invokeItem(ActionMenuView.java:624)
at android.support.v7.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:150)
at android.view.View.performClick(View.java:5610)
at android.view.View$PerformClick.run(View.java:22265)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
Thank you very much for your time and help. If my question looks not well please make a note and I will teach how to ask questions better
In my case, this problem occurred when I was calling getString()
changing this calls to getActivity().getString() solved the problem.
Using commit() can not solve the problem, we should try to find the solution in the source code of Fragment.
So, consider from the error stack you provided, the requireContext() in Fragment was:
public final Context requireContext() {
Context context = getContext();
if (context == null) {
throw new IllegalStateException("Fragment " + this + " not attached to a context.");
}
return context;
}
This means the system will check the Context from getContext(), if it's null, the exception will be thrown.
So, to avoid this problem, we can check the result of getContext() before do our business.
Create a fragment instance is not enough. It needs to be attached to Activity through a transaction:
getFragmentManager()
.beginTransaction()
.replace(R.id.container_layout, fragment)
.commit();
After a successful commit, onAttach method in the fragment is called, the view is created and then you can interact with its views.
In your case, create the fragment instance and attach it in activity onCreate, then call sortByPopularity later in a click event.
Read more about fragment life cycle: https://developer.android.com/guide/components/fragments
Kotlin:
My problem happened with getString()
Changing it to context.getString() solved it
If you are using CountDownTimer, you may get that error cause of detaching the fragment before finishing the timer. If you are performing ui changes in onFinish callback, you should check the context that it is null or not like below;
timer = object : CountDownTimer(startTimeInMillis, 1000) {
override fun onTick(millisUntilFinished: Long) {
}
override fun onFinish() {
context?.let {
//perform ui changes here
}
}
}
timer?.start()
or you should cancel the timer before detaching fragment like below;
override fun onDestroy() {
super.onDestroy()
timer?.cancel()
}
If a fragment is not shown (not added) or is removed, it's context == null. In this case getting resources will lead to this exception. getString(R.string.some_string) requires context and crashes.
You can check whether the fragment exists so:
if (isAdded) {
// Print getString(R.string.some_string).
}
But you might need to print the string even when the fragment was released, for instance, in LogCat, analytics or send a request to a server. In this case you need an application context to obtain a string resource.
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
instance = this
}
companion object {
lateinit var instance: MyApplication private set
}
}
object Strings {
fun get(#StringRes stringRes: Int, vararg formatArgs: Any = emptyArray()): String {
return instance.getString(stringRes, *formatArgs)
}
}
Then set MyApplication in AndroidManifest and use: Strings.get(R.string.some_string).
For kotlin developers
lifecycleScope.launchWhenResumed {
// do your work here
}
Kotlin : Use Lazy Initialisation
override val contentMessage by lazy {
getString(R.string.message)
}
For everybody who still have this error:
private Context mContext;
#Override
public void onAttach(Context context) {
super.onAttach(activity);
mContext = context;
}
And do not add mContext = null in onDetach method 'cause you will still get this error.
I know this is an old post, but I just figured out what you could do. It is true that creating a fragment instance is not enough, It needs to be attached to Activity through a transaction. However, you can initially add both fragments and detach them from fragment manager. That way, they are both 'alive' in fragmentManager and you can call attach and detach on those fragments later as you wish.
i.e
.add(container, fragment1).detach(fragment1).add(container, fragment2).commit();
.
.
.
.
.
ft.detach(fragment2)
ft.attach(fragment1
This assertion can occur anywhere you have a requireContext() call to get access to the Android context from your Fragment. Review the call site carefully, before you use requireContext(). I only use requireContext() when I'm certain that the fragment is going to be attached to the Activity at the time or the use case is so essential that it is better to crash with this assertion than any other course of action.
If for any reason the fragment could happen to be unattached and you can handle it yourself at the call site by avoiding or early returning, then the better idea is to null check the return from getContext() and only then proceed forward.
Typical Kotlin code for the null check looks like this:
fun myFragmentFunction(){
val context = getContext() ?: return // early return using Elvis operator
context.whatever() // guaranteed non-null context at this point
}
As Tam Huynh said, this crash happens when we our fragment is not attached. I had the same problem that your (but with a bottomSheet) and now it works fine.
We can receive this kind of error from two reasons:
requireContext() can crash directly if the context is null
Calling getString(R.string.xxx_xxx_xxx) from fragment will crash if the fragment is detached (because we will need the context and the context is null).
For me, with that piece of code we can check if our fragment is attached or not, and with that I solve the crash.
fun checkIfFragmentAttached(operation: Context.() -> Unit) {
if (isAdded && context != null) {
operation(requireContext())
}
}
More info => https://weidianhuang.medium.com/android-fragment-not-attached-to-a-context-24d00fac4f3d
In this scenario validate if you don't have any class level properties which are dependent on context as the fragment is not committed it won't have the context and we might end up with this exception.
Related
I have an activity that has 3 fragments on it with Tabs, one of them is called "TaskFragment".
In my main Activity i only load the fragments.
In TaskFragment i have a RecyclerView that is working fine and is showing the items as intended.
The problem comes, when i insert data using a DialogFragment, because it does insert data (i am using DbFlow ORM), but it does not (of course) refresh the adapter since it is in the TaskFragment fragment inside the DetailMainActivity activity as i said.
I have tried to use onResume() and onPause() in order to refresh the adapter, but they are never called since the activity does not get paused or in onresume for a DialogFragment.
I have tried aswell to use an interface, but it does not work and i have searched all over stackoverflow and google with no luck.
I leave here some of my code for you to understand better:
DetailMainActivity.java
Here in the onClick interface i show the DialogFragment to the user to input the information.
FragmentManager fm = getSupportFragmentManager();
AddSimpleTask sptask = new AddSimpleTask();
sptask.show(fm, "tag");
TaskFragment.java
In this fragment i have my RecyclerView
private void setupRecyclerView() {
mRecyclerView.setAdapter(adapter);
mRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 2));
mRecyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (DetailMainActivity.FAB_Status) {
DetailMainActivity.hideFAB();
DetailMainActivity.FAB_Status = false;
}
return false;
}
});
}
private void setupAdapter() {
adapter = new DetailMainTaskAdapter(simpleTaskList, this);
}
AddSimpleTask
And this is my DialogFragment. I have set a setOnShowListener() in order to avoid the DialogFragment to get dismiss early.
#Override
public void onShow(DialogInterface dialogInterface) {
final AlertDialog dialog =(AlertDialog) getDialog();
if (dialog != null){
Button positiveButton = dialog.getButton(Dialog.BUTTON_POSITIVE);
Button negativeButton = dialog.getButton(Dialog.BUTTON_NEGATIVE);
positiveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mEditTextName.getText().toString().trim().isEmpty() ||
mEditTextContent.getText().toString().trim().isEmpty() ) {
if (mEditTextName.getText().toString().trim().isEmpty()) {
mEditTextName.setError("Can not be empty");
}
if (mEditTextContent.getText().toString().trim().isEmpty()) {
mEditTextContent.setError("Can not be empty");
}
}else {
presenter.beingInsertion(mEditTextName.getText().toString().trim(), mEditTextContent.getText().toString().trim()
, foreignId);
}
}
});
negativeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dismiss();
}
});
}
}
If the insert is successfully achieved the onInsertSuccess method is called (i am using MVP)
#Override
public void onInsertSuccess() {
Snackbar.make(getActivity().findViewById(R.id.containerMainDetail), "Actividad agregada", Snackbar.LENGTH_SHORT).show();
dismiss();
}
I have called adapter.notifyDataSetChanged() in many places, and i also tried with a custom interface, but i can not make this work.
Sorry for the long post, but thanks in advance for your help.
There are some errors in your statement but I'll get to that later. notifyDataSetChanged() only notifies the adapter that the underlying list (or array) has changed. The implication is that you first need to requery your database and obtain the new list before calling notifyDataSetChanged() on the adapter else there is no point as the underlying list will still be the same and it will not update the adapter.
The correct way of calling this will be through your custom listener interface and not in the onPause()/onResume() callbacks as there is the possibility that the user does not enter a value and hence you will unnecessarily be querying the database. In your custom listener interface implementation, first update the list with the new data from the DB and then notify the adapter.
Which leads to the error in assumption that onPause()/onResume() callbacks do not happen when your Activity is covered by a DialogFragment - this is incorrect. The moment the activity view is even partially covered, the onPause() callback is triggered.
I'm trying to make an method executable everytime the fragment appears. I have a MainActivity and a PagerAdapter and inside PagerAdapter, I have Fragments so my problem is that I placed a method inside my onCreate of Fragment but it's executing only once. Maybe the onCreate of Activity and Fragment both have roles here. After searching about a similar question I found this :
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// Do your Work
} else {
// Do your Work
}
}
But when I am putting my method here am getting a NullPointerException. My method:
public void retrieveLocalStoredNotes() {
notesArray = new ArrayList<String>();
notesIDArray = new ArrayList<String>();
for (NotesRealmClass note : NotesQueryRealm) {
notesArray.add(note.getTitle());
notesIDArray.add(note.getobjectId());
}
notesAdapter = new NotesAdapter(getActivity(), getData());
recyclerView.setAdapter(notesAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
}
Maybe am getting this error because I am initialising the variables in onCreate and setVisibleHint and it is running before onCreate. How can I make this workable or is my approach not enough for that.
Call your method in onResume() method.
I already checked a lot of same questions on StackOverflow, but I didn't find any solution to my issue.
In a DialogFragment, I call an AsyncTask method and when the result has been received from the server, I launched another DialogFragment.
Here is the code I use to launch the DialogFragment :
public class RequesterConfirmRent extends DialogFragment {
// Called from onPostExecute() in AsyncTask class.
public void onPostComputeAmountToPay(JSONArray array){
double amountToPay = 0.0;
String ownerName = "";
try{
if(!array.getJSONObject(0).getBoolean("success"))
Log.e("Error", "Error with JSON received");
else {
amountToPay = array.getJSONObject(1).getDouble("amountToPay");
ownerName = array.getJSONObject(2).getString("ownerName");
}
}catch(JSONException e){
Log.e(e.getClass().getName(), "JSONException", e);
}
// Create and show the DialogFragment
Paiement p = new Paiement();
Bundle bdl = new Bundle();
bdl.putString("ownerName", ownerName);
bdl.putDouble("amountToPay", amountToPay);
p.setArguments(bdl);
// Buggy line (NPE)
p.show(getFragmentManager(), "4554");
}
}
And here is the code of the DialogFragment I try to display:
public class Paiement extends DialogFragment {
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
if(getDialog() == null)
super.setShowsDialog(false);
Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.setTitle("Synthesis of your rent");
return dialog;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_paiement, container, false);
init(rootView);
return rootView;
}
private void init(View v){// Bla bla ...}
}
And I alway got a NullPointerException when I call the .show() method?
What did I do wrong?
Many thanks for your help!
EDIT 1 : As requested, here is the LogCat
05-11 09:58:34.470 31384-31384/com.example.celien.drivemycar
E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.NullPointerException
at android.support.v4.app.DialogFragment.show(DialogFragment.java:136)
at com.example.celien.drivemycar.fragment.RequesterConfirmRent.onPostComputeAmountToPay(RequesterConfirmRent.java:148)
EDIT 2 I modified the code like this, and it appears that getFragmentManager() is null. Why?
Paiement p = new Paiement();
Bundle bdl = new Bundle();
bdl.putString("ownerName", ownerName);
bdl.putDouble("amountToPay", amountToPay);
p.setArguments(bdl);
// BUGGY LINE
android.support.v4.app.FragmentManager f = getFragmentManager();
if(p == null)
Log.d("Exception ", "p is null");
if(f == null)
Log.d("Exception ", "f is null");
try {
p.show(f, "4554");
}catch(NullPointerException e){
Log.d("Exception ", e.toString());
}
EDIT 3:
Got some fresh infos! To avoid the creation of this Dialog, I display data in a Toast: Toast.makeText(this.getActivity(), "You have to pay "+amountToPay+"e to " +ownerName, Toast.LENGTH_LONG).show(); and also get a NPE!
BUT if I use the Log system, everything's fine :
Log.d("Rcvd ", String.valueOf(amountToPay));
Log.d("Rcvd ", ownerName);
So, why is my activity null?
If you get a NPE when calling p.show() but not p.setArguments(), it could be that p is ok but something inside the show call isn't?
On possible point to solve is that you're using a support version of FragmentManager, with the getFragmentManager() call. Try the getSupportFragmentManager() instead. It will fall back to the proper one when needed.
On the other hand, you're calling android.support.v4.app.FragmentManager. If you manually added the package, it's weird, so chances are your IDE did it for you. You could try to remove the package behind FragmentManager, and hope for the code be compliant to the non-support standard framework. Could be that only this reference to the support library is done, so removing the package part would solve the issue.
My advice: In an app, always stick to either the standard framework or the support library when defining activities and fragments. Because of that, make sure that every Activity and Fragment you create extends a proper support (or standard framework) version. Mixing them will end up with unexpected crashes.
Also, as mentioned in one of my comments, AsyncTask runs freely even after your fragment was detached, so no activity is properly referenced by this fragment anymore. This answer tells you to check if Fragment was detached by looking at isDetached(). Check for his answer. He's talking about using Loaders instead of AsyncTasks or move the AsyncTask up to the activity, so the activity is always available. Looking at the future, Loader is the best option (since it's the natural evolution of AsyncTask), looking at the present, try to move the AsyncTask up to the common Activity.
The interface
public interface GameSelectedListener {
public void onGameSelectedListener(int gameID, Boolean isCustom);
}
Inside FragmentA in the on attach I set the gameSelectedListener in on attach.
public void onAttach(Activity activity)
{
super.onAttach(activity);
gameSelectedListener = (GameSelectedListener)activity;
}
In one part of the code some data is sent
gameSelectedListener.onGameSelectedListener(groupItems.get(groupPosition).iD, isCustom);
Main activity which implements the interface and calls a method in FragmentB
#Override
public void onGameSelectedListener(int gameID, Boolean isCustom) {
// TODO Auto-generated method stub`enter code here`
FB.setGameID(gameID, isCustom);
}
Inside Fragment B is the setGameID method which just sets some data inside that fragment.
public void setGameID(int gameID, Boolean isCustom)
{
this.gameID = gameID;
this.isCustom = isCustom;
}
With log statements (not shown here). The data generated by fragment A is successfully sent to main activity. I log the values of the variables in setGameID method of fragment B also appear correctly to that generated by fragment A.
However here is the problem
I get null pointer exceptions when using gameID and isCustom from the FragmentB. So I set some default values to check it and I noticed that the value change made in setGameID does not effect the global variables even though when logging the values in setGameID show the correct values. Note that these two variables are not changed anywhere else in the code. Just in setGameID method.
I don't know if this helps but my fragments are java fragments (not XML based)
In main activity I create an instance of Fragment B in order to call setGameID. Note I declare this in the global area only.
FragmentB FB = new FragmentB();
Heres how it looks so far
Activity A -> Fragment Transaction add Fragment A -> From Fragment A Button click-> fragment replace A with B
EDIT Added some more code: Issue could be here.
gameSelectedListener.onGameSelectedListener(groupItems.get(groupPosition).iD, isCustom);
fragment = FragmentB.newInstance();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(Container.getId(), fragment, tag);
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
I think the problem could well be here because I invoke the listener and then make a the Fragment B instance. Could this be it?
Use an EventBus instead of a listener! This design pattern mentioned in the official android docs is bullshit!
https://github.com/greenrobot/EventBus
class FragmentB extends Fragment {
private int id;
public static FragmentB newInstance(int id){
Bundle args = new Bundle();
args.putInt("id", id);
FragmentB frag = new FragmentB();
frag.setArguments(args);
}
public void onCreate(Bundle b){
super.onCreate(b);
this.id = getArguments().getInt("id);
}
}
When you replace Fragment A by Fragment B.
#Override
public void onGameSelectedListener(int gameID, Boolean isCustom) {
...// rest of the code
Bundle args = new Bundle();
args.putInt("id", gameID);
args.putBoolean("bool", isCustom);
FB.setArguments(args);
}
In Fragment B
int value = getArguments().getInt("id");
I want to have a sensormanager on a fragment, which is only active when the fragment is active. If the user changes the fragment, the listener should be removed.
Adding and removing the listener is pretty simple. I'm not aware of any listeners / function on the fragment side, when the fragment appears / disappears. Also a problem was, that on almost all functions, this.getActivity() returned a null pointer.
That's my solution. I tried to cut it out of my Fragment. If there is anything wrong / syntax issues, please let me know.
public class MyFragment extends Fragment implements SensorEventListener {
private SensorManager mSensorManager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSensorManager = (SensorManager) this.getActivity().getSystemService(Activity.SENSOR_SERVICE);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.mylayout, container, false);
return rootView;
}
#Override
public void onSensorChanged(SensorEvent event) {
float x = event.values[0], y = event.values[1];
}
#Override public void onAccuracyChanged(Sensor sensor, int accuracy) { }
#Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
// First starts (gets called before everything else)
if(mSensorManager == null) {
return;
}
if(menuVisible) {
this.registerSensorListener();
} else {
this.unregisterSensorListener();
}
}
#Override
public void onStart() {
super.onStart();
if(this.getUserVisibleHint()) {
this.registerSensorListener();
}
}
#Override
public void onStop() {
super.onStop();
this.unregisterSensorListener();
}
private void registerSensorListener() {
mSensorManager.registerListener(this, mSensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0), SensorManager.SENSOR_DELAY_FASTEST);
}
private void unregisterSensorListener() {
mSensorManager.unregisterListener(this);
}
}
Hold a reference of Activity in your fragment to handle that nullpointerexception.
Here is an example of a fragment.
public class YourFragment extends Fragment {
private Activity mActivity;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mActivity = activity;
}
#Override
public void onResume() {
super.onResume();
// BIND sensor here with mActivity,
// could also be done in other fragment lifecycle events,
// depends on how you handle configChanges
}
#Override
public void onPause() {
super.onPause();
// UNBIND sensor here from mActivity,
// could also be done in other fragment lifecycle events,
// depends on how you handle configChanges
}
}
Debug that code do determine if you should handle the binding there or in another method e.g. onCreate of a fragment. I have not tested this code for your purpose.
Edit:
This is indeed as commented below a dirty fix and could easily resolve into exceptions in some cases. I just wanted to show how you can use fragment lifecycle methods to bind and unbind sensors with a reference to activity. I'm currently learning fragments for quite some time but still don't understand them thoroughly. I advice you to take a look at the source of Fragment and other components involved. This is the only place were fragments are documented thoroughly hence the documentation on reference in my opinion isn't that explanatory.
Some of the options regarding null value Activity:
If you want to be completely sure that getActivity doesn't return null you should wait for onActivityCreated to be called. This method tells the fragment that its activity has
completed its own Activity.onCreate(). After this getActivity() will not return null until initState() gets called by the FragmentManager.
// Called by the fragment manager once this fragment has been removed,
// so that we don't have any left-over state if the application decides
// to re-use the instance. This only clears state that the framework
// internally manages, not things the application sets.
void initState() {
mIndex = -1;
mWho = null;
mAdded = false;
mRemoving = false;
mResumed = false;
mFromLayout = false;
mInLayout = false;
mRestored = false;
mBackStackNesting = 0;
mFragmentManager = null;
mActivity = null;
mFragmentId = 0;
mContainerId = 0;
mTag = null;
mHidden = false;
mDetached = false;
mRetaining = false;
mLoaderManager = null;
mLoadersStarted = false;
mCheckedForLoaderManager = false;
}
Before you call getActivity you can always check if activity isn't null by calling isAdded() method. As you can see below this method checks if mActivity isn't null. Optionally you can create a recursive function with Handler.postDelayed that tries to return an non null Activity in intervalls (you should add a max try counter). But this is also a dirty trick.
//Return true if the fragment is currently added to its activity.
final public boolean isAdded() {
return mActivity != null && mAdded;
}