Okay, I'm at a loss with this problem, it doesn't quite make sense to me. In my app, my Application-class looks something like this:
public class MyApplication extends MultiDexApplication {
private static Context sContext;
#Override
public void onCreate() {
super.onCreate();
sContext = getApplicationContext();
SomeClass.someMethod(sContext.getString(R.string.some_string));
[...]
}
[...]
}
The app itself runs a few Services. Now for some reason I get reports of users getting a NullPointerException for sContext.getString(R.string.some_string). Not a lot, to be honest a very small amount of users, mostly on Android 4 and Samsung devices, and about 50% of the errors have the app running in the background, but still enough to get at least two people to complain. And I don't know how this could happen. I have no idea how this could happen for <1% of my users. Has anyone encountered something similiar or has an idea how sContext could be null at that point?
Make sure you have this in your manifest.xml
<application android:name="packagename.MyApplication"/>
The problem is on this lane I guess:
SomeClass.someMethod(sContext.getString(R.string.some_string));
So, you can do it using getResources().getString()... or just getString(R.string.some_string) instead of sContext.getString(...)
Related
Currently trying to obtain profile trace logs files for a huge Android app, that we have instrumented on MyApplication class, following the documentation about instrumenting my app to get trace logs.
We are trying to dig into what happens when our app is initialized and Dagger2 creates the object graph when the app is started.
A cold startup can take a few seconds normally, the issue I have is that when I add the Debug traces, it dramatically slows down the initialization of the app, making it crash with an ANR message.
com.github.anrwatchdog.ANRError: Application Not Responding
Caused by: com.github.anrwatchdog.ANRError$$$_Thread: main (state = RUNNABLE)
I would like to know if there is a way to prevent the Android OS from crashing my app when it blocks for a long period of time, or to at least increase the ANR threshold.
Any help or tips are welcome. Thanks!
For further context, this is roughly what I am doing in my MyApplication.class:
public void onCreate() {
super.onCreate();
Debug.startMethodTracing("MyApp_onCreate()");
injectSelf();
AppInit.initApp(this);
Debug.stopMethodTracing();
}
Actually, it turns out we have our own ANRWatchDogManager which I wasn't aware of, where I can extend the limit.
public class ANRWatchDogManager implements ANRWatchDog.ANRListener {
Somewhere in that class:
public void startANRWatchDog() {
final int timeoutInterval = isDebugBuild() && isEmulator()
? ANR_INCREASED_TIMEOUT
: ANR_DEFAULT_TIMEOUT;
new ANRWatchDog(timeoutInterval).setANRListener(this).start();
}
While profiling my Google Cardboard application, I found out a very large memory leak (15Mb!) each time I left the activity with the 3D graphics.
After a long and grievous investigation, I found out that the source of the problem was a Context leak that happened each time I closed my CardboardActivity subclass.
The solution can be found in the accepted answer*
* wow... this is awkward... Note for any kind (and experienced) reviewer: I am writing a question to whom I know the answer already: am I supposed to do something for style, like add some fake suspense ("will our heroes prevail?! Find out in the accepted answer!"), like in a old Batman TV series or something?
After dicing and slicing my CardboardActivity subclass, until nothing else but the base class remained, I had to conclude that the base class itself was leaking the context.
I searched the web and found this post explaining how the activity in question leaked the context by failing to un-register a listener with a private instance of a class.
Upon trying to invoke said method manually (using reflection), I found out that in the current version of the Cardboard SDK (0.5.4 at the time of writing), the field is not present anymore.
Long story short: all sensors are now handled by an undocumented (yet public) SensorConnection class instantiated in CardboardActivity as a sensorConnection field, which is still plagued by the bug detailed in my first link.
This led me to this solution:
get the sensorConnection field in the CardboardActivity by reflection
use it to get the magneticSensor field, again by reflection
invoke the setOnCardboardTheaterListener with null argument, to clear the binding holding the reference to the Context in the Activity onDestroy method.
this boils down to the following code:
private void workAroundLeak() {
try {
// Get the sensor Connection
Class<?> c1 = Class.forName("com.google.vrtoolkit.cardboard.CardboardActivity");
Field sensorsField = c1.getDeclaredField("sensorConnection");
sensorsField.setAccessible(true);
SensorConnection sc = (SensorConnection) sensorsField.get(this);
if(sc == null) return;
// Get the magnetSensor
Class<?> c2 = Class.forName("com.google.vrtoolkit.cardboard.sensors.SensorConnection");
Field magnetField = c2.getDeclaredField("magnetSensor");
magnetField.setAccessible(true);
MagnetSensor ms = (MagnetSensor) magnetField.get(sc);
if(ms == null) return;
ms.setOnCardboardTriggerListener(null);
} catch(Exception e) {}
}
#Override
protected void onDestroy() {
workAroundLeak();
super.onDestroy();
}
which solved the problem entirely.
A word to the wise: since this solution relies on reflection, it might break (without consequences other than doing nothing, likely) as soon as Google will update the SDK (possibly fixing the issue in a clean way).
Hope this helps someone
I'm making an app that uses Network Service Discovery, let's call it a "Wi-fi Chat". And at some point I want to unregister a service created earlier in order to avoid creation of countless copies of it. But the problem is, when I cal;
mNsdManager.unregisterService(mRegistrationListener);
I get "listener is not registered" error. To make sure that I have STILL THE SAME object of that listener I even initialized it in a class that extends Application class and still I get this error. So, the question is: how to unregister a service properly? Thank you in advance.
Also, I looked through "NsdChat" sample application, and it crashes at the same point with the same error!
Well, I kinda found a solution. Much thanks to this Wizard who fixed NsdChat Google example.
The solution is: in tearDown() method, inside which we call unregisterService(RegistrationListener listener) we should do this
public void tearDown() {
if (mRegistrationListener != null) {
try {
mNsdManager.unregisterService(mRegistrationListener);
} finally {
}
mRegistrationListener = null;
}
}
Though I still have no clue how actually this works, so if you have any thoughts regarding this puzzle, please post an answer
Sometimes my application crashes while trying to open it. As the app hasn't completely started I don't get an error report. I also can't connect my application to the emulator because this behaviour is not reproducable. Sometimes it just crashes once. In other times I can try to open/reopen it as often as I want and it works perfect.
I only use the network-connection (no camera and other stuff). I don't have any services which could crash the application and I tried to reproduce my error by trying to stop the application while it loads something in the background - no success at all.
What do you think could be the reason for crashing? How can I get a log-file, stacktrace something useful for fixing this problem? I simply can't reproduce it so I never see a Logcat-Output when it occurs.
It might be a Fragment-Initializing-Problem but I can't see my mistake. This never occured before and it's just not a common mistake. It might crash only once/twice a week - but it crashes in some point in time...
I've uploaded my project on github but I don't think this is helping somehow.
My main question is: What for opportunities do I have to see what might be the reason behind these random crashes?
Root your phone and install CatLog. When it crashes, open CatLog and save the log so you can view it later.
Or try this if you want to automate it:
Create an exception handler that saves a stack trace to a file.
public class UncaughtExceptionSaver implements UncaughtExceptionHandler{
UncaughtExceptionHandler previousHandler;
Context context;
public UncaughtExceptionSaver (Context context){
this.context = context;
previousHandler= Thread.getUncaughtExceptionHandler();
}
#Override
void uncaughtException(Thread t, Throwable e){
/*Save the stacktrace from the throwable to a
file in your external directory, using context. */
previousHandler.uncaughtException(t,e);
}
}
Then in an Application subclass, call this in the onCreate method:
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionSaver(this));
I am developing on a library that is somehow getting a CalledFromWrongThread Exception crash on Samsung Galaxy S1 (api v7 - android 2.1). The code is something like this:
class MyWebViewClient extends WebViewClient {
#Override
public void shouldOverrideUrlLoading(WebView view, String url) {
someListener.addToUiView();
}
}
and of course, the method that is actually throwing the error (which implements a listener callback):
View v;
public void addToUiView(){
v.addView(new TextView(context)); //<-- this line is throwing the error on rare occasions
}
I'm skipping some code in between, but i'm not doing anything weird in other places. Also note: this crash only seems to have been happening a very very small % of the time. (not necessarily conclusive, as not everyone reports their data).
has anyone else come across this?? Is WebCore threading messing things up?
Now I haven't actually tested this but I am going to answer to the best of my knowledge. That said, my instinct is telling me that you are only seeing the error intermittently because web requests from a WebView (browser) happen with varying levels of asynchronicity and probably utilize a thread pool to accomplish this. Basically, sometimes it requests resources in parallel and sometimes it doesn't. Worse yet you might be seeing this error on only a single device because OEMs optimize OS level code (like the WebView internals) based on their preferences and opinions (especially Samsung). Either way the real problem is that you are doing something "UI related" in a place that is definitely not guaranteed to be "UI friendly"... That is, anywhere where you are getting a subsystem callback.
The solution to your problem is much more simpler than the explanation: just use your context (that I am assuming is an Activity)..
Activitys have a built in function called runOnUiThread(Runnable) that will guard the code inside the runnable from running on the wrong thread. Basically, your problem is really common and android has a built-in solution. runOnUiThread will only add overhead if required, in other words if your thread is the UI thread, it will just run the Runnable, if it isn't it uses the correct Handler (the one associated with the UI thread) to run the Runnable.
Here is what it should look like:
View v;
public void addToUiView() {
final Activity activity = (Activity) context;
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
v.addView(new TextView(activity));
}
});
}
i coded that up right inside the SO window so my apologies for any egregious errors, I hope that helps, and let me know if you need more info or of this doesn't solve your problem -ck