Android exception handling best practice? - java

If my app crashes, it hangs for a couple of seconds before I'm told by Android that the app crashed and needs to close. So I was thinking of catching all exceptions in my app with a general:
try {
// ...
} catch(Exception e) {
// ...
}
And make a new Activity that explains that the application crashed instantly (and also giving users an opportunity to send a mail with the error details), instead of having that delay thanks to Android. Are there better methods of accomplishing this or is this discouraged?
Update: I am using a Nexus 5 with ART enabled and I am not noticing the delay I used to experience with apps crashing (the "hanging" I was talking about originally). I think since everything is native code now, the crash happens instantly along with getting all the crash information. Perhaps the Nexus 5 is just quick :) regardless, this may not be a worry in future releases of Android (given that ART is going to be the default runtime in Android L).

Here, check for the link for reference.
In here you create a class say ExceptionHandler that implements java.lang.Thread.UncaughtExceptionHandler..
Inside this class you will do your life saving stuff like creating stacktrace and gettin ready to upload error report etc....
Now comes the important part i.e. How to catch that exception.
Though it is very simple. Copy following line of code in your each Activity just after the call of super method in your overriden onCreate method.
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this));
Your Activity may look something like this…
public class ForceClose extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this));
setContentView(R.layout.main);
}
}

You could just use a generic alert dialog to quickly display error messages.
For example...
//******************************************
//some generic method
//******************************************
private void doStuff()
{
try
{
//do some stuff here
}
catch(Exception e)
{
messageBox("doStuff", e.getMessage());
}
}
//*********************************************************
//generic dialog, takes in the method name and error message
//*********************************************************
private void messageBox(String method, String message)
{
Log.d("EXCEPTION: " + method, message);
AlertDialog.Builder messageBox = new AlertDialog.Builder(this);
messageBox.setTitle(method);
messageBox.setMessage(message);
messageBox.setCancelable(false);
messageBox.setNeutralButton("OK", null);
messageBox.show();
}
You could also add other error handling options into this method, such as print stacktrace

i found the "wtf" (what a terrible failure) method in the Log class. From the description:
Depending on system configuration, a report may be added to the
DropBoxManager and/or the process may be terminated immediately with
an error dialog.
http://developer.android.com/reference/android/util/Log.html

Related

How to fix crash handling in android 10

I have a Unity Scene built with Cardboard SDK and exported as a library for Android. The library is used to play videos in cardboard mode on the android app. it's not the whole app, but a part in it. The rest of the android app is built with Kotlin and Java.
I have implemented that and all the functions work as expected, but, exiting the scene crashes the android.
We tried various ways to clear player prefs and even clear memory before closing the scene. But on android it always crashes. I have two android phones with android 9 and 10 for testing.
In the android app, I have made it such that as soon as the app crashes, I try to recover. My crash is that some lateinit var variables are destroyed. Their value becomes null and recovering the previous activity crashes it. So right after I exit the unity scene, I load the dereferenced variables back into memory and everything works again.
Note: I have tried using Application.Quit(); in unity, but it just closes the whole app. On the other hand, I only want to close the running scene
In unity [I call a function goBack in android part to close the app]:
public void GoToHome()
{
Pause();
Stop();
Resources.UnloadUnusedAssets();
PlayerPrefs.DeleteAll();
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
jo.Call("goBack");
}
In App:
public void goBack()
{
UnityPlayer.currentActivity.finish();
finish();
loadDerereferencedVars();
}
This goes perfectly on android 9. On the other phone with android 10, after I close the scene, the app continues to function, but, there comes a message
When I click close app, the app continues to work.
I have checked the logs and there is a null pointer dereference cause for the crash in Unity Main >...
If you'd like to see the Unity Crash Log from LogCat in Android Studio
So, since the app is still running, I thought, it would be better to just hide the crash report and just let the user not know about this crash, but still report it.
I tried enclosing my app in Application and added a method to catch uncaughtException.
here is my application class:
public class MyApp extends Application {
private static final String TAG = "MyAPP";
#Override
public void onCreate() {
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException (Thread thread, Throwable e) {
handleUncaughtException (thread, e);
}
});
}
/**
* Handles Uncaught Exceptions
*/
private void handleUncaughtException (Thread thread, Throwable e) {
// The following shows what I'd like, though it won't work like this.
Toast.makeText(getApplicationContext(), "Looks like I am having a bad day!", Toast.LENGTH_LONG).show();
Log.e("UncaughtException", "I found an exception!");
// Add some code logic if needed based on your requirement
}
}
Again, this works perfectly in Android 9 and I also got the error reported. However in the phone with android 10, I just get the crash report like the image above and no error is reported.
I want to know why the crash handling is not working and how can I fix it?
I would not finish the Activity you came from, instead just open a new intent (on UnityActivity). When you end this intent the app will come back to the last active Activity.
I will give you my script as an example:
public void sendJobToUnity(String fileName, boolean isNewJob){
//creates a new job. It exists inside the JobSelector Activity
isUnityLoaded = true;
//this is what you are looking for part1
Intent i = new Intent(JobSelector.this, MainUnityActivity.class); //same as (CurrentActivity.this, UnityActivity.this)
//those are how I send some data across the app. just ignore it
//i.putExtra("jobName", fileName);
//i.putExtra("isNewJob",isNewJob);
//i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivityForResult(i, 1); //this is what you are looking for part2
}
For closing it, in the MainUnityActivity Activity I have an override that Unity sends to Android in order to Unload the activity (not quit it completely cause you cannot load it again if you do it) like this:
#Override
protected void receiveJobAndUnloadUnity(String data){
saveCurrentJob(data); //saves the job it receives from Unity
mUnityPlayer.unload(); //this is what you are looking for part3
}
If you want to unload Unity from android you can put "mUnityPlayer.unload();" wherever you want, provided you have started the Activity the way I've shown you.
Note that "mUnityPlayer" is a default Unity variable and cannot be renamed

Correct way to use Logs debug in android? Breakpoint

My app is currently crashing on start I only have one class MainActivity I'm trying to figure out what causing it
I found that there is multiple Log
Log.v(); // Verbose Log.d(); // Debug Log.i(); // Info Log.w(); // Warning Log.e(); // Error
Which one should I use ? and what about Breakpoint should I check every entry method ?
I tried implementing like this I'm not sure if it's the best or right way
try{
camera.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
openDialog();
}
});
catch (Exception ex)
{
Log.e("I shouldn't be here", ex.getMessage());
}
If you look at the logcat stacktrace, it already should tell you what caused the exception. You should only need to set breakpoints around where the exception happens
As for which level of logging you need, it is up to you to determine the severity & verbosity of the message. Info is a general print, error is critical, warn is somewhere in between and debug is for putting lots of details. And Log.wtf is just for laughs 😁 (although the actual reason is mentioned in the documentation)
Rather than using the default Log class, consider using Timber.
Remember, whenever you log in production a puppy dies. 🐶🐶🐶☠️

Android Studio show me the Error load: id=gralloc != hmi->id=gralloc

My IDE shows me the error even is empty project. As you can see I create the new project with empty activity. App is launched in mobile successfully and work fine. but logcat isn't working properly or any thing else I'm stuck help me out. And when I connect my mobile even I didn't build the project logcat is full of instruction/logs.
UPDATE:
First, gralloc stands for the low-level graphics buffer allocator.
The gralloc is part of the HAL (Hardware Abstraction Layer) which
means that the implementation is platform-specific. You can find the
interface definitions in
hardware/libhardware/include/hardware/gralloc.h. As expected from a
HAL component, the interface is divided into a module interface
(gralloc_module_t) and a device interface (alloc_device_t).
The error is very low level and related with OpenGLRenderer. Your device is trying to open some 64-bit library files, but if fails. Then the error occurs.
I did very deep search about this but nothing useful came up.
Try running apps on another devices and see the error occurs again.
Continue developing if the error is not causing crash or other important issue. If you find a solution, you will try again.
in my case, I tried to use Application class static context for calling new Activity and I changed it to local static Activity and problem solved.
Notice that this problem doesn't happen in all devices it just occur in some cases.
private static MainActivity u_static;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_users);
u_static = this;
}
public static void new(int id, String name){
Intent i = new Intent(u_static, NewActivity.class);
u_static.startActivity(i);
}
And something I notice that in some devices when an application stops working instead of showing error, this error happens. Trace and debug your codes.
About the crazy E/HAL: load: id=gralloc != hmi->id=gralloc
Reason for error: Generally, it is caused by the fact that the control object is not fetched, the click event of the control is executed, and the null value is related to the initialization control.
As
private Button bt;
bt.setOnclickListener(new OnClickLisenter(){....});
Is there a problem? Yes!
xml layout control
Check if the findViewById() is missing in the java code!
    The above leaked bt = (Button) findViewById(R.id...);
java dynamic new control / custom control error
     Check if you forgot to create the object!
     The above leaked bt = new Button();
So the correct way to change the above code is:
private Button bt;
bt=(Button)findViewById(R.id...);
I encountered this issue while using runnable and passing an unassigned view.
This is caused by an empty view object where findViewById returns a null value.
Instead of passing the view object passing the value the view holds resolved the issue.

Save serializable object in persistent storage (android)

I need to store a complex custom object in persistent storage in order to save the user's game progress in my app. The object and every object within this object implements Serializable
I call the use the loading and saving methods to pass the object between activities. I also call the Save method onStop() to save the object when the app is closed/destroyed. It works fine.
public static Game Load(Context context){
try{
FileInputStream fis = context.openFileInput("player1.data");
ObjectInputStream is = new ObjectInputStream(fis);
Game game = (Game) is.readObject();
is.close();
fis.close();
return game;
}catch (Exception e){
Log.e("#Load", "creating new game - \n" + e.toString());
Game newGame = new Game();
return newGame;
}
}
public static void Save(Context context,Game game){
try{
FileOutputStream fos = context.getApplicationContext().openFileOutput("player1.data", Context.MODE_PRIVATE);
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(game);
os.close();
fos.close();
}catch (Exception e){
Log.e("#Save", "Failed to save - \n" + e.toString());
}
}
However, if the app is Force Closed or closed and destroyed, the Game object gets messed up. When relaunched, the application will load the game that was saved onStop(), but when the game object is changed/interacted with by the user through the application, my app force closes with the "has stopped unexpectedly" display message on the phone screen. From looking at the log, i know that when the Game object is being loaded on launch after being Force Closed / Destroyed, the Load method is returning game rather than newGame, so somehow the saving/loading process in between the Force Close messes something up.
On the log, I see this:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
So, I am led to believe that something strange is going on with using Serializable, or I am incorrectly writing to persistent storage.
My questions: Do you see anything fundamentally wrong with my code? (keep in mind that this code does work, it just doesn't work under the Force Close circumstance)
I have been told to look into using gson/JSON (?) for my purposes; will this method have better results than Serializable and how can I use this?
Update: It seems that when Force Stop occurs, no methods are called - including the onDestroy() and onStop(). If this is the case, then why is my app not returning newGame? Looking at the log while Force Closing, a message that said something about "onSavedInstance not called," what is this?
I am getting the feeling that I should avoid Serializable entirely...
onCreate snippet
Game game;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
game = LoadGame.Load(this); //LoadGame is the class which contains Save,Load methods
#Override
protected void onStop() {
LoadGame.Save(this,game);
super.onStop();
}
Tips, Serialization is awesome i use it all the time, the thing is, you are actually saving on a Thread that actually encountered a problem, are you expecting a magical call to onStop() ? so either
You call your save methods routinely on a different thread, so it keeps on saving irrespective of what happens.-after all its a game-
You maybe add a try/catch to your code and catch certain exceptions and manually call a save method on a different Thread, well with this you need sick Encapsulation. This might not serve you well as errors like noSuchMethod etc, can not be caught so a force close might happen
either way your preference.

Listening for LogCat Entires made by my own application

Am I able to listen for messages being places into the LogCat by my own application?
For example something like...
// Somewhere in my application (on a background service):
Log.i("myModule", "Something been done");
and....
// Somewhere else something like...
LogCatListener logCatListener = new LogCatListener()
{
public void onInfoRecieved(String tag, String message)
{
//Do whatever you want with the message
}
}
I'm an Android noob so be gentle with me!
Thanks.
Unfortunately it looks like you directly can't do that for typical Log calls (.d, .i, .w). If you look at the source code of the Log class (https://android.googlesource.com/platform/frameworks/base/+/android-4.3_r2.1/core/java/android/util/Log.java) you'll see that these calls are just translated into a println_native, a private function mapped to a native implementation.
Also, the Log class is final, so you can't extend it and hook into .d , .i , .e, .w
I'm afraid your only solution is to write a Log class wrapper if you need to capture those calls. This will work for your custom Log's but obviously not for the system-issued calls to the Log class.
But good news is there's a special Log function that allows listeners. There's a funny method on the Log class:
public static TerribleFailureHandler setWtfHandler(TerribleFailureHandler handler)
And you can set a handler that will be called when you do
Log.wtf (TAG, message)
funny google method names :)

Categories