Android 7.0 and 7.1 getApplication() ClassCastException
Asked Answered
G

5

26

In Developer Console I see a lot of crashes with stacktrace like this

java.lang.RuntimeException: 
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2984)
  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3045)
  at android.app.ActivityThread.-wrap14(ActivityThread.java:0)
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1642)
  at android.os.Handler.dispatchMessage(Handler.java:102)
  at android.os.Looper.loop(Looper.java:154)
  at android.app.ActivityThread.main(ActivityThread.java:6776)
  at java.lang.reflect.Method.invoke(Native Method:0)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
Caused by: java.lang.ClassCastException: 
  at com.myapp.ui.BaseActivity.getApp(BaseActivity.java:193)
  at com.myapp.ui.BaseActivity.onCreate(BaseActivity.java:275)
  at com.myapp.ui.CastActivity.onCreate(CastActivity.java:39)
  at com.myapp.ui.MainActivity.onCreate(MainActivity.java:268)
  at android.app.Activity.performCreate(Activity.java:6955)
  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2927)

getApp method of BaseActivity is

public App getApp() {
        return (App) getApplication();
    }

App class is

public class App extends MultiDexApplication { ...

and in manifest application tag contains reference to this class

 <application
        android:name="com.myapp.App"

98% of crashes is for android 7.0, rest is 7.1. No other android versions are affected.

EDIT: I use proguard so it can be somehow related but keeping class

-keep class com.myapp.** { *;}
-keep interface com.myapp.** { *;}

Note: It may not be related but in same android versions it looks like App's onCreate method is sometimes not called. I observed it because some objects which are created in onCreate were null when they were accessed from Service (started by AlarmManager) or BroadcastReceiver

Does anyone has idea what can cause it, how to fix it or work around it? Thanks

EDIT 2: I ended up with something like this:

   public App getApp() {

    Application application = getApplication();
    App app = null;

    try {
        app = (App) application;
    } catch (Exception e) {
        if (application != null) {
            Log.e(TAG, "getApp Exception: application class: " + application.getClass().getName());
        } else {
            Log.e(TAG, "getApp Exception: application object is null");
        }
    }

    return app;
}

It at least doesn't crash and I can check getApp() == null

Greenlee answered 30/6, 2017 at 7:18 Comment(4)
Hi, have you find the solution?Allheal
@user5599807 unfortunately notGreenlee
how common is this crash? there are always weird rare crashes that are vendor/rom specific.Census
I see the problem on Android 8.0 and 8.1 as well.Undergo
F
13

Casting fails because getApplication() returns an Application and NOT the desired sub-class.

I've had some success where I caught the error and asked the user to reboot their device or reinstall the app.

Unfortunately, there's no real fix to this rare crash. Google won't fix the lifecycle-related issue, but said it reduced in Android 7.1+. Source: https://issuetracker.google.com/issues/37137009

Foghorn answered 10/10, 2017 at 22:22 Comment(3)
This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From ReviewLindsay
I think my newly edited answer provides closure to the OP's question.Foghorn
Agreed. +1 from me.Lindsay
S
1

I think you should cast getApplicationContext() into App instead.

Sphere answered 30/6, 2017 at 7:24 Comment(3)
Can you explain why it should help please?Greenlee
It is an alternative, sometimes when programming for android I experienced that minor changes like that can get rid of an exception.Sphere
problem is that it may not return application object in some cases (ie vendor implementation of android) #5019045Greenlee
D
1

While I cannot say if this solution works.

I think that static Application instance should solve the problem.

class MyApp extends Application {
  private static final sInstance;

  public void onCreate() {
    sInstance = this;
  }

  public static MyApp getInstance() {
    return sInstance;
  }
}

Instead of calling getActivity() if you call MyApp.getInstance() you should not need to cast. So there should not be any ClassCastException anymore.

Discommodity answered 1/11, 2017 at 14:3 Comment(0)
A
0

You should override attachBaseContext in your application class like this:

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    MultiDex.install(this);
}

Check this link for more information: https://developer.android.com/reference/android/support/multidex/MultiDexApplication.html

Anthropocentric answered 30/6, 2017 at 7:26 Comment(7)
I don't have to do it because it's already done in MultiDexApplication. In link which you share it says you can extend MultiDexApplication or override attachBaseContextGreenlee
@vandzi can you post your app class oncreateAnthropocentric
There is nothing useful there just super.onCreate(); Analytics initialisation. I think problem is somewhere elseGreenlee
I recreated your implementation and it works on my side on android 7.0, it think it is somewhere elseAnthropocentric
It doesn't always crash. It crashes only for some devices/users and probably randomly.Greenlee
Does it crash on samsungs?Sphere
Yes, I saw samsung s7 as top device in reports, but other devices too. Common thing is android 7.0Greenlee
S
0

This might help

public class App extends MultiDexApplication { 

        public static App app = null;

        public static App getInstance() {
            return app;
        }

        @Override
        public void onCreate() {
            super.onCreate();
            app = this;
        }
}

you doesn't need to cast getApplication(), reason is you are already in Application class so simply just use this keyword to get application instance. Hope you find useful

Sashasashay answered 19/9, 2017 at 7:19 Comment(5)
getApp is in activity so I have to cast itGreenlee
Though you doesn't need to cast use getApplicationContext() in your activitySashasashay
developer.android.com/reference/android/content/Context.html getApplicationContext() Return the context of the single, global Application object of the current process.Sashasashay
I don't want to get context. I want to get App instance.Greenlee
that I already answered. you need to read above statement. global Application object (That means App instance)Sashasashay

© 2022 - 2024 — McMap. All rights reserved.