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);
}
}
Related
I was reading fragment documentation and found this:
Caution: If you need a Context object within your Fragment, you can call getContext(). However, be careful to call getContext() only when the fragment is attached to an activity. When the fragment isn't attached yet or was detached during the end of its lifecycle, getContext() returns null
So my question is what is the best place to call getContext() inside the fragment. Like i can call it in onCreateView, or onCreate() or onAttach() on any other place.
I am asking this because recently I got a crash of null pointer using getContext in my fragment. So I thought I should create a global Context object and access it inside the fragment. But then I came across this text from official documentation so I am a bit confused what would be the best place to initialize this Context object.
It all depends what you need that Context for. Sometimes it's just fine to call getApplicationContext(), in other cases it may be needed to use what you are given in onAttach() or call getActivity() if you are in Fragment code. Some are also providing own Application subclass, exposing static method like getAppContext().
In any case, AVOID saving the context as it may lead to memory leak. Get it dynamically when needed only.
As a lot of wrong answers are given, I'll provide what's the best way to handle context inside fragments.
The best solution is checking if the context has a value whenever you need it.
You can do it by wrapping the code in which you access the fragment in 2 ways:
if (getContext() != null) { /* code here */ }
or, as stated in the documentation there's this method:
isAdded()
which: "Return true if the fragment is currently added to its activity." -reference
Again: please AVOID saving the context in a local fragment's variable.
You can do something like this in your fragment.
#Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
// After this point the context is initialized.
context=activity;
}
NOTE: I don't really get it why it is so not liked this answer.
First af all, depending on the version of android(which was not mentioned), of course the OnAttach is deprecated, it has to be checked.
Next:
I think that if you need cobntext somewhere, you can make a private or protected variable in Fragment, so the context is destroyed when it is garbage collected.
protected MainActivity activity;
Make sure you hold this variable dearly and its reference is not passed to other classes.
This should do the job.
You can implement your logic like this :
private Context mContext;
#Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
}
#Override
public void onDetach() {
mContext = null;
super.onDetach();
}
When you required to use context,
if(mContext != null) {
//Add your logic here
}
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.
I see that if one instantiates a Dagger 2 Component in an Activity, then it's later nulled in the onDestroy() method like seen here.
public class MyActivity {
private MyActivityComponent component;
//...
public void onCreate() {
component = Dagger_MyActivityComponent.builder()
.myApplicationComponent(App.getComponent())
.build()
.inject(this);
//...
}
public void onDestroy() {
component = null;
}
}
What happens if I don't null that instance and what would happen?
Side note: in comments I've found useful hint why one would set it to null which is pretty convincing: "I don't think it's necessary but it defines scope pretty clear".
What happens if I don't null that instance [...]?
Nothing. After onDestroy gets called the activity object will be garbage collected at some point. If the activity gets recreated it will be a new object. Your dagger component will also be garbage collected then along with your activity. I usually don't null my components in onDestroy because I deem it unnecessary.
This will although not hold true if you keep static references to your activity or have some other sort of memory and activity leaks. But if you have those it will not make much of a difference either if you null your component.
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);
...
}
What is the correct way to implement a constructor in android?
It seems that in an Activity or Service 'onCreate()' is where the magic happens.
The reason I ask is because I would like to be sure I'm doing the right thing declaring
attributes in the top of my classes (Context in particular) and then setting the attribute values inside onCreate.
// Activity launched via an Intent, with some 'extras'
public class SomeActivity extends Activity {
private Context context;
private String foo;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set the object attribute for later use, good or Bad to do this?
context = getApplicationContext();
Intent fooIntent = getIntent();
foo = fooIntent.getStringExtra("foo");
}
private void someMethodThatNeedsContext() {
// For example:
Cursor c = this.context.getContentResolver().query(foo, xxx, xxx);
// Or is it better practice to:
// A) Pass the context as a local variable to this method
// B) Use getApplicationContext() locally when needed
}
}
Maybe either of these options is ok, and I'm over thinking it?
Any specific reading and/or suggestions you may have would greatly be helpful to me.
Yes, you are correct that initialization is supposed to take place in onCreate(). You don't really need neither to store a reference to a context, nor to call getApplicationContext(). Your activity is a context itself, so you just use wherever you need a context. For example, making a toast within an activity:
Toast.makeToast(this, "Some text", Toast.LENGTH_LONG).show();
Option B - Since you can call getApplicationContext() from any non-static methods in your Activity class.
In fact, Activity is derived from Context too (Somewhere in the inheritance tree..) so you can just do:
Cursor c = getContentResolver()....
You don't have to keep a reference to a context. Especially not static, that can cause problems.
And you are correct - since you usually don't create your own constructor for Activities, you put the code for construction in onCreate.
You are writing a method inside your activity, so you can call getApplicationContext() anywhere in your code, you don't need to use a local variable :
Cursor c = getApplicationContext().getContentResolver().query(foo, xxx, xxx);
Also remember that the activity itself is a context (the Activity class is derived from Context), so generally you can use this whenever you need to provide a context ( for example when creating an Intent : new Intent(this, ...)).