Fragment calling onDestroyView but reference to adapter is null - android

java.lang.NullPointerException: Attempt to invoke virtual method 'void my.app.ui.fragment.adapter.IssueAdapter.setOnKeyListener(my.app.fragment.adapter.IssueAdapter$OnItemListener)' on a null object reference
at MyFragment.onDestroyView(MyFragment.java:429)
at android.support.v4.app.Fragment.performDestroyView(Fragment.java:2565)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1512)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1759)
at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:792)
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2596)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2383)
at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2338)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2245)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:703)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6939)
at java.lang.reflect.Method.invoke(Method.java:-2)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
In Fragment below the onCreateView will start an Observable timer where when it reaches 3 seconds the adapter issueAdapter will be instantiated. And then when onDestroyView is called, it will do some cleanups (setting issueAdapter.setOnKeyListener to null, for example)
Programatically the fragment should only be destroyed after 30 seconds (leaving time to issuesAdapter be instantiated). This is the first time I received that exception in maybe a year of production.
My question is, is that possible I'm missing some lifecycle aware code handler?
Obs.: The device don't allow rotation.
private final CompositeDisposable disposables = new CompositeDisposable();
private IssueAdapter issueAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(my_fragment, container, false);
unbinder = ButterKnife.bind(this, rootView);
disposables.add(
Observable
.timer(3, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(__ -> {
List<Issue> issues = AppRepository.getInstance().getIssues();
issueAdapter = new IssueAdapter(issues);
issueAdapter.setOnKeyListener(position -> {
this.issueSelected = issues.get(position);
});
}, ErrorService::notify)
);
return rootView;
}
#Override
public void onDestroyView() {
super.onDestroyView();
issueAdapter.setOnKeyListener(null);
unbinder.unbind();
}
#Override
public void onDestroy() {
super.onDestroy();
disposables.clear();
}
Thanks

Rotation is not the only configuration change that could possibly trigger your Fragment's destruction and re-creation. Additionally, the Fragment could be destroyed even without a configuration change; perhaps the user opened this screen and then immediately received a phone call, and their device killed your app's process to conserve resources.
All in all, even if you think onDestroyView() "shouldn't" be called before the three seconds are up, you still need to handle the fact that it can be.
Seems simple enough in this case: just check if issueAdapter is null before you try to null out its key listener.

Can you make a safety condition to adapter, because the object exist when all process was success but in error case issueAdapter was a null because not found instance. I recommend you in your onDestroy put
if(issueAdapter!=null){
issueAdapter.setOnKeyListener(null);
}

As Ben P. says, a null check would be the simplist solution. If you need to be sure that your issueAdapter isn't being cleared, you could add the following line to your OnCreate method in your fragment.
setRetainInstance(true);
This will make sure the same instance (with instance variables) is used if the fragment is recreated. If you don't need to ensure that your issueHandler does not get set to null, I would avoid using it though.

Related

NullPointerException when I am trying get orientation of screen

I have got a problem!
Why when I am trying to get screen orientation, my app gets NullPointerException.
Log:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
at android.content.ContextWrapper.getApplicationContext(ContextWrapper.java:106)
at adrian.bjd.masterdetail_myapp.MainActivity.getOrientation(MainActivity.kt:25)
at adrian.bjd.masterdetail_myapp.MainActivity.onClickItem(MainActivity.kt:43)
at adrian.bjd.masterdetail_myapp.Fragment.MenuFragment.onItemClick(MenuFragment.kt:46)
at android.widget.AdapterView.performItemClick(AdapterView.java:339)
at android.widget.AbsListView.performItemClick(AbsListView.java:1705)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:4171)
at android.widget.AbsListView$13.run(AbsListView.java:6734)
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:6682)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
My code:
fun getOrientation(): Int
{
val context = applicationContext
var orientation = 0
if(context.resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT)
{
orientation = 1
}
else if(context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE)
{
orientation = 2
}
return orientation
}
I am using a Fragments.
Plese help me !
If you are calling your function getOrientation() in onCreate() move to onResume() and Check. this may help
If you are trying to use your context from your Fragment I recommend to you to create this
private val mContext by lazy {
this#YourFragment.context
}
And then in your method getOrientation() just use mContext instead.
If you don't want to use the lazy in your onCreateView() add this
activity = activity as Context
And then you can use your activity as context
You only use getApplicationContext() when you know you need a Context for something that may live longer than any other likely Context you have at your disposal. Scenarios include:
Use getApplicationContext() if you need something tied to a Context that itself will have global scope. I use getApplicationContext(), for example, in WakefulIntentService, for the static WakeLock to be used for the service. Since that WakeLock is static, and I need a Context to get at PowerManager to create it, it is safest to use getApplicationContext().
Use getApplicationContext() when you bind to a Service from an Activity, if you wish to pass the ServiceConnection (i.e., the handle to the binding) between Activity instances via onRetainNonConfigurationInstance(). Android internally tracks bindings via these ServiceConnections and holds references to the Contexts that create the bindings. If you bind from the Activity, then the new Activity instance will have a reference to the ServiceConnection which has an implicit reference to the old Activity, and the old Activity cannot be garbage collected.
and in case you want to get the current orientation then you can use :
Activity.getResources().getConfiguration().orientation
Instead of calling this with application context , use below
#Override
public void onConfigurationChanged(#NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if( (newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE))
{ mainBinding.layoutDrawerView.openDrawer(GravityCompat.END);
}
}

IllegalStateException: Fragment YoutubeLessonFragment not attached to a context

I am using YouTubePlayerSupportFragment in one of my fragments but I am not using it inside the layout file but initialising it programmatically. Some of the users are facing this crash at runtime:
Fatal Exception: java.lang.IllegalStateException: Fragment YoutubeLessonFragment{3a2e875} 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.musicmuni.riyaz.youtubelesson.YoutubeLessonFragment.loadYoutubeVideo(YoutubeLessonFragment.java:168)
at com.musicmuni.riyaz.youtubelesson.YoutubeLessonPresenter$2.onModuleLoaded(YoutubeLessonPresenter.java:188)
at com.musicmuni.riyaz.data.AppDataRepositoryImpl$10.run(AppDataRepositoryImpl.java:187)
at android.os.Handler.handleCallback(Handler.java:754)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:163)
at android.app.ActivityThread.main(ActivityThread.java:6221)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
My code for initialising the youtube fragment goes like this:
private YouTubePlayerSupportFragment youtubePlayerFrag;
.........
public void loadYoutubeVideo(String videoId) {
mVideoId = videoId;
if(getContext() != null) {
youtubePlayerFrag = YouTubePlayerSupportFragment.newInstance();
youtubePlayerFrag.initialize(getString(R.string.youtube_api_developer_key),
this);
getChildFragmentManager().beginTransaction().add(R.id.flYoutubeVideoHolder,
youtubePlayerFrag).commit();
}
}
where loadYoutubeVideo(...) gets a callback from a background running thread loading the required video id. Any pointers here?
Probably your Fragment in not attached to the activity while you are calling getString() method.
because the docs says:
Fragments now have requireContext(), requireActivity(), requireHost(),
and requireFragmentManager() methods, which return a NonNull object of
the equivalent get methods or throw an IllegalStateException.
You might want to check if the fragment is attached to the activity or not, by calling isAdded() method of fragment.
Also you can pass the argument directly to newInstance(..args..) rather that creating initialise() method.

Caused by java.lang.IllegalStateException: Can't create ViewModelProvider for detached fragment

I need some help to ressolve the following crash. I am refreshing my list on Restart in Activity by calling fragment in viewpager to refresh its list. Following is the stacktrace of the crash:
Caused by java.lang.IllegalStateException: Can't create ViewModelProvider for detached fragment
at android.arch.lifecycle.ViewModelProviders.checkActivity(ViewModelProviders.java:51)
at android.arch.lifecycle.ViewModelProviders.of(ViewModelProviders.java:105)
at com.ui.fragments.mainpagerfragments.ConversationListFragment.searchConversation(ConversationListFragment.java:383)
at com.ui.activities.HomeActivity.onRestart(HomeActivity.java:288)
at android.app.Instrumentation.callActivityOnRestart(Instrumentation.java:1256)
at android.app.Activity.performRestart(Activity.java:6365)
at android.app.Activity.performResume(Activity.java:6376)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3299)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3345)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1532)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5728)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
call from activity onRestart :
((MyListFragment) adapter.getFragmentAtPosition(0)).search("");
method in fragment :
public void search(String query) {
query = "%" + query + "%";
if (myListViewModel == null) {
myListViewModel = ViewModelProviders.of(this, viewModelFactory).get(MyListViewModel.class);
}
if (myListViewModel.mList != null && myListViewModel.mList.hasActiveObservers()) {
myListViewModel.mList.removeObservers(this);
}
myListViewModel.getFilteredList(query).observe(this, mainObserver);
}
If you're using a viewpager, be sure that the corresponding fragment is actually attached to its activity (this is what the error tries to tell you). It might happen that the fragment is not visible, thus it's not attached (depending on how the view pager was configured).
a quick&dirty fix:
public void search(String query) {
if(!isAdded()) return; //<---- returns if the fragment is not attached
query = "%" + query + "%";
if (myListViewModel == null) {
myListViewModel = ViewModelProviders.of(this, viewModelFactory).get(MyListViewModel.class);
}
if (myListViewModel.mList != null && myListViewModel.mList.hasActiveObservers()) {
myListViewModel.mList.removeObservers(this);
}
myListViewModel.getFilteredList(query).observe(this, mainObserver);
}
However, you should re-investigate in your architecture, because those checks often imply some other code smells. When you're working with the new Android Architecture Patterns, there should be no need of this check as the lifecycle pattern handles all this for you: https://developer.android.com/topic/libraries/architecture/lifecycle
So, basically, you should not directly call any function of a fragment directly, instead call the corresponding business logic, which notifies the fragment to update its views.
Since the error is that the fragment is not attached yet, it needs to be done when we are sure the fragment is actually attached. Its a good way of doing this; by putting the code inside the override method onAttach
#Override
public void onAttach(Context context) {
super.onAttach(context);
myListViewModel = ViewModelProviders.of(this, viewModelFactory).get(MyListViewModel.class);
}

How to call fragment method from other fragments? [duplicate]

This question already has answers here:
how to call function from other fragment class
(2 answers)
Closed 5 years ago.
In my application I want call fragment methods from other fragments, I write below codes but when call this method show me below error in logcat and Force close application.
For show this two fragments into activity I use TabLayout and ViewPager.
My Review Fragment codes:
public void getComments(final Context context) {
JsonObject requestBean = new JsonObject();
requestBean.addProperty("entityType", 1);
requestBean.addProperty("reviewType", 5);
requestBean.addProperty("reviewUserType", 2);
requestBean.addProperty("entityID", serialID);
requestBean.addProperty("celebrityId", 0);
requestBean.addProperty("pageIndex", 1);
requestBean.addProperty("pageSize", 10);
InterfaceApi api = ApiClient.getClient().create(InterfaceApi.class);
Call<CommentResponse> call = api.getComments(token, requestBean);
call.enqueue(new Callback<CommentResponse>() {
#Override
public void onResponse(Call<CommentResponse> call, Response<CommentResponse> response) {
if (response.body().getData() != null) {
if (response.body().getData().size() > 0) {
reviewMovieFrag_NoComment.setText("");
} else {
reviewMovieFrag_NoComment.setText(context.getResources().getString(R.string.noReviews));
SerialReview_CastProgress.setVisibility(View.GONE);
}
commentModel.clear();
commentModel.addAll(response.body().getData());
commentsListAdapter.notifyDataSetChanged();
reviewMovieFrag_newsCommentsRecyclerView.setAdapter(commentsListAdapter);
reviewMovieFrag_newsCommentsUserTypeText.setText(userTypeStr);
reviewMovieFrag_newsCommentsReviewTypeText.setText(reviewTypeStr);
reviewMovieFrag_Progress.setVisibility(View.GONE);
}
}
#Override
public void onFailure(Call<CommentResponse> call, Throwable t) {
reviewMovieFrag_Progress.setVisibility(View.GONE);
}
});
}
I want call this method (getComments method) into InfoFragment and for this I write this code :
new MovieDetail_reviewFragment().getComments(getActivity());
But in LogCat show me this error :
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at com.test.app.Fragments.MovieDetailFragments.MovieDetail_reviewFragment$6.onResponse(MovieDetail_reviewFragment.java:301)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:68)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5349)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:908)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)
Show error for this line :
reviewMovieFrag_NoComment.setText(context.getResources().getString(R.string.noReviews));
ATTENTION : Dear moderators and dear users I know this error for NullPointer but I don't know how can I fix it?
I tried for fix this issue but I can't so I ask in StackOverFlow.
Please help me and don't give me negative points or duplicate my post!
Please help me, Thanks all
Here,
new MovieDetail_reviewFragment().getComments(getActivity());
Is creating your fragment class newly. You need to use all variables when Fragment class created at starting.
Use viewPager.setOffscreenPageLimit(fragmentNumber); - this will help you to create all fragment when tab initialized.
Then use instance to access any fragment method.
Declare at top of fragment class, private static FragmentClass instance = null;
inside your Fragment class override onCreate() and initialize instance,
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
instance = this;
}
Create getInstance() method in fragment contains your calling method,
public static FragmentClass getInstance(){
return instance;
}
Finally call method from another fragment,
FragmentClass.getInstance().yourMethod();
don't take it otherwise but what you are doing is not good design pattern,
you should use interfaces for communicating between any two fragments. It will make things easier for you. Look into this post Basic Communication between two fragments

Android Attempt to read from field on a null object reference

I have an Activity with some Fragments used in a ViewPager, sometimes user sends me some crash report that i don't understand.
I can not produce this crash and most of the user have no problem at all.
The crash Log says:
java.lang.NullPointerException: Attempt to read from field 'com.mehdok.views.treeview.TreeNode$TreeNodeClickListener com.mehdok.mafatih.MainActivity.nodeClickListener2' on a null object reference
The nodeClickListener2 is in my main activity:
public TreeNode.TreeNodeClickListener nodeClickListener2 = new TreeNode.TreeNodeClickListener()
{
#Override
public void onClick(TreeNode node, Object value)
{
TreeViewHolderNoBorder.TreeViewItem item = (TreeViewHolderNoBorder.TreeViewItem) value;
if(node.isLeaf() && !item.nodeNavUri.equals(""))
{
openNodePage2(item);
}
}
};
And in fragmets i use it like this:
tView.setDefaultNodeClickListener(((MainActivity) getActivity()).nodeClickListener2);
What can i do to prevent this crash?
tnx in advance.
Where do you access your activity field from your fragment? You should do it starting from onAttach() up until onDetach().
If you try to access it too soon like in your constructor or in your fragment's onCreate(), this would explain the crash. Same if you try to access it after the fragment is detached from the Activity.
That is possible, sometimes Activity will be recycled, when you call getActivity() in Fragment, it will return null. so before you call getActivity() you can write code as below:
if (isAdded()) {
tView.setDefaultNodeClickListener(((MainActivity) getActivity()).nodeClickListener2);
...
}

Categories

Resources