Be great if someone can share a solution to this seemingly simple problem, as my app crashes when attempting to get a String Resource using the following line in my application within the onErrorResponse section of a simple Volley request:
mTextView.setText(sActivity.getString(R.string.connection_error,
customMessageParameter));
This issue appears to only occur for some users (despite attempting to replicate the crash myself), which is reported via Fabric, namely the following:
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual
method 'java.lang.String android.content.Context.getString(int)' on a null
object reference at
com.appname.MyFragment$13.onErrorResponse(MyFragment.java:651)
I ensure the Activity sActivity variable is initialised using the following function, which is invoked in each lifecycle call from onAttach to ensure it's available:
private void setActivity(Activity activity, Context context) {
if (activity != null) {
sActivity = activity;
} else if (getActivity() != null) {
sActivity = getActivity();
} else if (context != null) {
sActivity = (Activity) context;
}
}
I understand how to check the getString() call is not equal to null beforehand and how this can ensure the app will not crash, yet I need to obtain dynamic values from the String Resources at run-time that will vary.
From what I've gathered, the activity instance can vary using asynchronous network calls that can result in this issue. I've also considered simply using getString() on its own and also getResources().getString(), yet I'm unsure if this will prevent the issue from arising.
You should not pass the activity to the fragment and store it that way, this is likely the cause of your problem. Just use getActivity() from inside the fragment.
Also, your setActivity code does not necesarilly guarantee that sActivity won't be null. What happens if all 3 conditionals happen to be null? There is no final else to catch the situation where all 3 are null. Plus, Android can be funky sometimes while fragments/activites are inflating. Theres a good chance all 3 of those variables are null at the time of OnAttach. Either way, getActivity() should return what you need if you use it in the OnCreate or after the Fragment has fully been inflated. You shouldn't have an activity variable since getActivity does exactly what you need, and what happens when the activity changes but you have an older version of it stored in memory that you try to call methods on?
Also, use getResources().getString(), since you are getting the string from your string resources.
To summarize, your line of code should look like this instead (with no need for your setActivity method or sActivity variable).
getActivity().getResources().getString(R.string.connection_error)
It's been a while, so let me know if this doesn't work for you and I can try to help you further.
Related
I am starting EditCardActivity from MainActivity.
The app crashes first time and Android system shows an alert to "Open App Again".
When I reopen the app, it works as expected.
I have seen many answers on this site and I have done following according to those answers but it didn't work.
I have called the setContentView() inside onCreate() method before calling findViewByID().
I have verified that the ID I am passing in findViewByID() is spelled correctly.
I also tried to make the EditText a class member too and initialize it in onCreate() method.
I also tried using onStart(), onPostCreate() methods too.
I feel that the View has not been loaded when I am trying to call it and thus findViewByID() returns null. Hence I tried using Thread.sleep(1000) to give it 1 second to load but still same issue.
Here's the part of code that is having problem.
// MainActivity.java
public void editCard(View v) {
Intent i = new Intent(this, EditCardActivity.class);
startActivity(i);
}
<!--activity_edit_card.xml-->
...
<EditText
android:id="#+id/add_card_category_et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/margin"
android:ems="10"
android:hint="#string/add_card_category_et_hint"
android:inputType="text"
android:textSize="#dimen/font_size" />
...
// EditCardActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_card);
showContents();
}
private void showContents() {
EditText editCardCategoryET = findViewById(R.id.add_card_category_et);
editCardCategoryET.setText(currentCard.getCategory()); // This line is throwing NullPointerException
}
Error
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
Edit:
I got what was causing the error.
I was referring to the add_card_category_et instead of edit_card_category_et.
The former view belonged to the different layout file of another Activity of my application.
I am sorry I couldn't catch this small error.
Although small, it made me stuck for 3 days.
Anyway thanks for your answers and comments.
Because editCardCategoryET cant find any value. So it throws Exception. It can be solve by add extra character by adding " " . Then app will not crush. editCardCategoryET.setText(" "+currentCard.getCategory()); .
Also you can handle it in a try(), catch() method.
We have found several cases for this kind of crashes reported by backend logging monitoring. It seems the crashes do not tie to particular UX failure. And from the reports, there is no sign of how our own classes being involved(no sign of any of our classes names). Here is an example of typical crashes:
java.lang.NullPointerException: Attempt to read from field 'int android.view.View.mViewFlags' on a null object reference
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3357)
at android.view.View.updateDisplayListIfDirty(View.java:14288)
at android.view.View.getDisplayList(View.java:14315)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528)
at android.view.View.updateDisplayListIfDirty(View.java:14253)
at android.view.View.getDisplayList(View.java:14315)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528)
at android.view.View.updateDisplayListIfDirty(View.java:14253)
at android.view.View.getDisplayList(View.java:14315)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528)
at android.view.View.updateDisplayListIfDirty(View.java:14253)
at android.view.View.getDisplayList(View.java:14315)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528)
at android.view.View.updateDisplayListIfDirty(View.java:14253)
at android.view.View.getDisplayList(View.java:14315)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528)
at android.view.View.updateDisplayListIfDirty(View.java:14253)
at android.view.View.getDisplayList(View.java:14315)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528)
at android.view.View.updateDisplayListIfDirty(View.java:14253)
at android.view.View.getDisplayList(View.java:14315)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528)
at android.view.View.updateDisplayListIfDirty(View.java:14253)
at android.view.View.getDisplayList(View.java:14315)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528)
at android.view.View.updateDisplayListIfDirty(View.java:14253)
at android.view.View.getDisplayList(View.java:14315)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528)
at android.view.View.updateDisplayListIfDirty(View.java:14253)
at android.view.View.getDisplayList(View.java:14315)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:273)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:279)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:318)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:2561)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2377)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2007)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1086)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6453)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:846)
at android.view.Choreographer.doCallbacks(Choreographer.java:647)
at android.view.Choreographer.doFrame(Choreographer.java:601)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:829)
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:5254)
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:927)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:713)
Does anyone know whether there is related bug logged against Android code?
Possible Solution
I had this same issue. I setup an animation and in onAnimationEnd I was removing the object that had been animated which is when problems started. What I did was setup an asynchronous Runnable to wait 100 milliseconds after the animation had stopped before removing the animated object:
the object previously animated is this._loader
private void removeLoader() {
final ContentContainer self = this; // "CustomContainer" needs to match the type of `this`
Handler h = new Handler();
h.postAtTime(new Runnable() {
#Override
public void run() {
MainActivity.instance.runOnUiThread(new Runnable() {
#Override
public void run() {
try {
if(self._loader == null) {
// there is no loader. quit now while you still have the chance!!
return;
}
while(self._loader.getParent() != null) {
removeView(self._loader);
}
} catch(Exception e) {
Crashlytics.logException(e);
e.printStackTrace();
}
self._loader = null;
}
});
}
}, 100);
}
Cheers
I was facing same problem. I resolved with Handler.
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// remove fragment from here
}
});
The problem is in the ViewGroup's dispatchDraw() method. This method tries to draw all the ViewGroup's children. When a child is null, you get an exception, which most likely comes from this line: if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { (notice the mViewFlags).
So the problem is that one of your views, somewhere, is not properly initialized. I'm afraid that's the best I can do.
We started getting this error unexpectedly too. It was tracked down to fragment animations being the issue. More specifically using custom animations with replace() in a fragment transaction when the app is built against Local Maven repository for Support Libraries rev > 26.
Possible solution
Downgrade Local Maven repository for Support Libraries to rev 26. See here
Possible cause:
I was having the exact same issue. It turned out it started to happen when I added code to modify the view tree within onDraw() call. To be specific, I removed a view with children in my derived onDraw() when certain conditions were met. I now believe this is a bad thing to do, probably because the platform is trying to draw views that I have now removed from the view tree. I resolved the issue by posting the deletion with Runnable to happen after the call to onDraw() has finished.
Override dispatchDraw method and put in it a try/catch block, like this:
public void dispatchDraw(Canvas c)
{
try
{
super.dispatchDraw(c);
return;
}
catch(Exception exception)
{
return;
}
}
While it is ugly and not good practice, the only thing I could get to reliably work is just catching the exception in dispatchDraw() like below:
override fun dispatchDraw(canvas: Canvas?) {
/*
* We're doing this because of the below exception that is out of our control:
* java.lang.NullPointerException: Attempt to read from field
* 'int android.view.View.mViewFlags' on a null object reference at
* android.view.ViewGroup.dispatchDraw(ViewGroup.java:4111)
*/
try {
super.dispatchDraw(canvas)
} catch (e: NullPointerException) {
}
}
Just make sure your desired behavior is working correctly and you're not breaking something else by doing this.
Again, not ideal, but it's the only thing I could get to work and I'm absolutely sure in my case it's not breaking anything else.
Peace to you :)
I was trying to navigate from Fragment A to Fragment B, and Fragment A was a form that required data from Fragment B.
So when I tried to navigate without filling up A, it was throwing this exception.
Also, even if A was independent of the data B, it was throwing this exception.
I have no idea why but I added a condition where the user had to fill-up the form before navigating away and that solved the issue.
It's a threading issue. Could be that you're refreshing your ViewPager or some other adapter.
Have been facing this issue on and off, and realised that if you place it in the UI Thread in your Activity, then it'll render just fine.
activity?.runOnUiThread{
// Add Your UI Updating Methods Here
}
No delay / threading stuff required. Plz Read through...
The post is old but for the future readers, it would be helpful.
I explain in details what really happens with a use-case I faced and solved.
I have a viewflipper which animates flipping next and previous through its children using simple slide-in / slide-out animations. I need to remove a view from viewflipper just after flipping is completed and to make sure it happens at the right time, slide-in animations have a listener where I remove the view in there. Everything worked perfect for flip-to-next
while flip-to-previous threw the above mentioned exception. After some trial and error turns out:
when flipping to next the following is the sequence:
1-slide-out starts
2-slide-in starts
3-slide-out finishes
4-slide-in finishes
So having listener on slide-in is the right thing since both animations are guaranteed to be completed there.
But when flipping to previous the following is the sequence:
1-slide-in starts
2-slide-out starts
3-slide-in finishes
4-slide-out finishes
As you can see, when slide-in finishes, slide-out is not done yet and hence there happens the exception. I simply set the listener on slide-out and it worked perfectly.
While all of the other answers urge to remove the view with a delay (which of course helps to make sure concurrent animations are all done) but as you could see that is not the case.
As a general rule, when you have a set of animations running on a view (even with the exact same durations) -although the general belief is that they would finish both together - but they won't (remember that threads are virtually concurrent).
This is mainly because you are removing a view duaring touchEvent dispatching.
It's hard to find out the who is removing the view in a large code base.
For those who want the crash analysis, can check this post:
https://medium.com/#wanxiao1994/crash-analysis-resetcancelnextupflag-nullpointerexception-e409b7bdbad
I'm struggling a bit with my use of fragments for ICS. I've got a fragment (call it AnalysisFragment) that does a fair amount of number-crunching work, reading in a file and then performing a number of calculations on it. Most of this work is initiated in onActivityCreated, because I need to consult the app's settings file prior to doing the work, which in turn requires having the context, which is accessible through the activity, which isn't necessarily available until onActivityCreated is invoked.
Well, this work seems to be getting done again (twice!) whenever I rotate the display. In my LogCat, I see onDestroyView and onDestroy happening (once), followed by onCreate, onCreateView, and onActivityCreated (twice), all pertaining to AnalysisFragment.
Obviously, the work of re-painting the screen for a different orientation has to be done over again, but is there any way I can add avoid the number-crunching work a 2nd time (not to mention a 3rd time)?
I maybe should add that I'm instantiating a new copy of AnalysisFragment whenever the user selects a new file to analyze, as follows
public static AnalysisFragment newInstance
(
String ndsFileName,
ViewIndicator viewIndicator
)
{
AnalysisFragment analysisFragment = new AnalysisFragment( );
Bundle bundle = new Bundle( );
bundle.putString( "nds_file_name", ndsFileName );
bundle.putString( "view_indicator", viewIndicator.toString( ) );
analysisFragment.setArguments( bundle );
return analysisFragment;
}
However, during a re-orientation, Android must be doing it for me. After shutting down the instance I created, it instantiates another using the same bundle for the new screen orientation. Eventually, onActivityCreated gets called on the new instance, and my code is off reading in the same file it read moments ago and re-doing the number crunching.
Any insight would be appreciated ...
I'm currently working on an Android App and, almost every time I use it, I get a an error. Most of the time it doesn't crash the app, but it is still frustrating that I'm seeing this error. I thought I did a check for it, but I could be wrong. Thanks for the help! The relevant code is below. (It's relevant because the line outside the if statement is throwing the NullPointerException.)
Activity activity;
if(activity == null)
{
activity = new Activity();
}
Intent intent = new Intent(activity, Service.class);
You don't usually instantiate the Activity class in this manner. Please see the documentation on the Android Activity class here:
http://developer.android.com/reference/android/app/Activity.html
You should post some more of the surrounding code, but your problem is that creating new Intent requires a valid Context. Usually you create an Intent within an Activity (or Service or BroadcastReceiver) class so you can just do something like:
Intent intent = new Intent(this, Service.class);
Occasionally you'll create it somewhere else and pass it that valid Context, but you should pretty much never create an Activity by calling the constructor directly. There's a lot of other initialization necessary to make it useful.
As postet previously there is more to initiate for an activity than calling the constructor. Probably you get a null pointer exception deep within the Intent Constructer where it is trying to get some of the Activityinformation usually provided.
If you really want to create a Service, heres a link for starting a Service, but you should really read the whole article and probably some more of the activity lifecycle ressources.
http://developer.android.com/guide/topics/fundamentals/services.html#StartingAService
A similar question was asked here for two times and never there was any answer. Or the answer was: "it is impossible!" Sorry, it is possible too much:
try{
...
// the line that causes the error
LinearLayout cell = (LinearLayout) inflater.inflate(R.layout.channels_list_cell, column);
...
}
catch(Throwable e){
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show(); < breakpoint here!
}
At the breakpoint e is null. How can I seek for the error, please? Very possibly it is not the problem of java or Android, but of the Eclipse debugger, that itself needs debugging badly. But what have I to do, except changing to a different IDE? Any ideas? Beforehand grateful.
I have tried Throwable, Exception, RuntimeException. The result is the same.
An attempt to step over breakpoint causes NullPointerException, so, e seems really null at that moment already. Where could it be lost?
Edit:
I bring my gratitude to everybody and +1 to every answerer. It was an Eclipse bug. After restart Eclipse the Exception is not null anymore, it is a normal RuntimeException: Binary XML file line #15: You must supply a layout_width attribute. It would be another problem to be solved, but that one is solved.
If the exception you caught was a NullPointerException, the getMessage() method returns "null" which may be confusing. I know that this has sometimes confused me!
In the debugger, you should be able to select e and see a type and its fields. Also, another way to debug when things get really confusing is to go
e.printStackTrace();
(note - I'm not an Android guru so if this works differently on Android somebody please comment!)
Have you verified whether e is actually null or not? I.e. by adding something like if (e == null) Log.d("Exception is null"). I would then check if the log statement gets triggered both during normal execution and while debugging. If the results are different between the two, it would indicate a VM bug (unlikely, but possible). If the message doesn't get triggered in either case, then it's likely a debugger issue.
A few thoughts on further things you can try to debug the issue:
Try something like jdb and see if you get the same behaviour
You could get a dump of the jdwp communications between the debugger and the device, and see what's going on at that level. Maybe use wireshark or tcpdump and grab the data going over the usb bus to the device.
You could try adding some debug statements to dalvik itself. E.g. grab a copy of AOSP and build an emulator image, and then add some debugging statements to dalvik to try and track down what's going on.
You could attempt to do some sort of scripted jdwp session with the device
You could look at the bytecode (baksmali/dexdump/dedexer), to see if anything looks funny
Android does not always throws exception in a Throwable. It actually drives all the exceptions to the catLog. There you will find details of your exceptions even if in the catch block your exception is null.
You can easily access the catlog console from eclipse and filter to view the errors only
UPDATE:
Your breakpoint should be inside the catch block
I know this question was posted a while ago, and many times too! I fell into this trap yesterday and I thought I'll post what I found.
Problem definition: I used the following code
public class myAppActivity extends Activity
{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try { -- lots of code -- }
catch (Exception ex) {
Log.e ("eTutorPrism Error", "Caught this exception " + ex);
ex.printStackTrace();
}
}
}
Symptom was that 'ex' was always null and resume will give NullPointerException, although the actual exception was an IllegalArgumentException in a call made into another class from the code above.
ISSUE: onCreate() code does not display the exception caught. instead it shows exception = null.
Solution: do NOT use too much processing in onCreate(). Move as much as possible to another thread. So I changed the code to look like the following. voila, it works!!! I can see the actual exception displayed in the Logcat.
public class eTutorPrismAppActivity extends Activity
{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
eTutorPrismTest myTest = new eTutorPrismTest (getApplicationContext());
myTest.start();
}
}
class eTutorPrismTest extends Thread
{
private Context m_AppContext = null;
public eTutorPrismTest (Context appContext)
{
m_AppContext = appContext;
}
public void run ()
{
-- lots of code that needs appContext --
}
}
I am unsure of what causes this -- it could be an Eclipse bug as stated earlier. Regardless of the cause, I did find a workaround that seems to work. I hope it is useful to others as well.
After the exception is caught, assign it to another variable. The assigned variable should contain the correct Exception in the debugger.
SpecificException assignedVar = null;
try {
...
}
catch (SpecificException exc) {
assignedVar = exc; // <-- exc comes up null in the debugger, but assignedVar will be the correct object.
}
Hope this works for others as a workaround.