Android 7.0 and 7.1 getApplication() ClassCastException - android

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

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

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

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.

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

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

Related

May be the Application not created?

I have some Apps where I use a static reference of the Application instance.
That's usefull when I need to use context in some singleton Class that has application lifetime.
Here an example:
public class MyApp extends Application
{
private static MyApp smApplication;
public MyApp()
{
MyApp.smApplication = this;
}
public void onCreate()
{
super.onCreate();
MyApp.smApplication = this;
}
public static MyApp getApp() {
return MyApp.smApplication;
}
}
class Settings // Example of Singleton class
{
...
public boolean loadSettings()
{
Context context = MyApp.getApp(); // NullPointerException on the next line
SharedPreferences pref = context.getSharedPreferences(SHAREDPREF_FILENAME, Context.MODE_PRIVATE);
...
}
}
This works like a charm in the majority of the cases.
But... I have a number of NullPointerException crashes reported in the Play Console about that Context. Usually called in the MainActivity.onCreate or MyService.onCreate.
Application should Always be created before any other Activiy or Service. So I can't understand what happens. I've never had a similar crash on any of my devices.
smApplication is initialized in the constructor and never set to null.
It seems that in that cases Application is not created. It's also weird that all these crashes are reported in the PlayConsole but I cannot find them in Firebase Crashlitics as if neither Crashlitics has yet initialized in that cases (and FC shoul be initialized by the Application)
This has been happening for years in a small part of my users.
Any suggestion?
PS. I Do not need suggestion on code refactoring, just to understand what happens and how to avoid it.

Cannot cast Application to CustomApplication

I have a CustomApplication extends Application class, which is registered in AndroidManifest
<application
....
// Please, pay attention that I got this in my Manifest
android:name=".CustomApplication">
And at different part of my application, both some activities and services I do
getApplication()/getApplicationContext() then cast it to CustomApplication and it crashes in production on a variety of devices/sdk versions(beginning at android 6) due to a class cast exception. Caused by: java.lang.ClassCastException
Example:
class CustomApplication extends Application{
...
public static CustomApplication with(Context context) {
return (CustomApplication) context.getApplicationContext(); //crashes here
}
}
and service example:
class CustomService extends IntentService{
...
#Override
rotected void onHandleIntent(#Nullable Intent intent) {
CustomApplication app = CustomApplication.from(getApplication());
// tried getApplicationContext() also
}
}
and activity example:
class CustomActivity extends AppCompatActivity{
...
#Override
protected void onCreate(...){
CustomApplication app = CustomApplication.with(this);
}
What I've tried:
Tried services with different process=":process"
Tried deep linking with different launchModes
Tried activities with taskAffinity
launching from push notifications
process cleaning with system tray(on device), ps kill int adb shell
nothing helps me to reproduce an issue on emulator
I don't use Instant Run also (never used it)
Please don't provide me with suggests of using static application context instance
You can keep a static reference of your CustomApplication like below. You don't need to cast in the following way.
public class CustomApplication extends Application {
private static CustomApplication instance;
#Override
public void onCreate() {
super.onCreate();
instance = this;
}
public static CustomApplication getContext() {
return instance;
}
}
Then call CustomApplication.getContext();
You need to define your custom application in the manifest as follow:
<application
....
android:name="my.package.path.CustomApplication">
... activities ....
</application>
Also, you are getting an instance of a class that extends Application, not Context, that being said you should call this the following way:
CustomApplication customApplication;
customApplication = (CustomApplication)getApplication();
What you might have to apply in case you have BroadcastReceiver(No context available) is:
customApplication = (CustomApplication)getApplicationContext().getApplication();

ClassCastException while injecting dependencies with dagger

I'm using Dagger2 to inject my dependencies in all of my applications.
Some days ago I started getting Crash Reports for one of the applications from Samsung Android 7.0 (only these) devices.
java.lang.RuntimeException:
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2924)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2985)
..
Caused by: java.lang.ClassCastException:
at de.package.name.MyApplication.get(MyApplication.java:43)
at de.package.name.ui.base.BaseActivity.onCreate(BaseActivity.java:53)
at de.package.name.ui.startup.StartupActivity.onCreate(StartupActivity.java:26)
at android.app.Activity.performCreate(Activity.java:6912)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2877)
MyApplication class:
public class MyApplication extends MultiDexApplication {
private AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
setupAppComponent();
}
private void setupAppComponent() {
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.userApiModule(new UserApiModule())
.build();
appComponent.inject(this);
}
public static MyApplication get(Context context) {
return (MyApplication) context.getApplicationContext();
}
}
Relevant part of the BaseActivity class:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyApplication.get(this).getAppComponent().inject(this);
}
And finally, the StartupActivity Part:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupComponent(MyApplication.get(this).getAppComponent());
setContentView(R.layout.activity_startup);
startupPresenter.bindView(this);
}
public void setupComponent(AppComponent appComponent) {
startupComponent = DaggerStartupComponent.builder()
.appComponent(appComponent)
.startupModule(new StartupModule())
.build();
startupComponent.inject(this);
}
I already updated Dagger to the most recent version (2.11 for now). But I don't have any ideas about this issue. Also, I can't reproduce it on my Samsung S8 7.0 device.
So if you have any ideas, please let me know!
Cheers
edit:
If anyone runs into this problem. Take a look here: RuntimeException with Dagger 2 on Android 7.0 and Samsung devices
This might be your solution.
This has nothing to do with Dagger. The problem is here:
return (MyApplication) context.getApplicationContext();
The Context returned by getApplicationContext() is not guaranteed to be your Application instance. The only situation I've encountered where it wasn't was in an emulator, but it's always possible.
I prefer this approach:
private static MyApplication gInstance;
#Override
public void onCreate() {
gInstance = this;
}
public static MyApplication instance() {
return gInstance;
}
This is safe because the Application instance is created and its onCreate is called before any other Android component is created.

Null pointer execption even when object is not null

I am facing a somewhat weird problem. I am trying to get the string from resources, I have a non activity class where I get the context like this:
App app= App.getInstance();
if (app != null) {
return app.getResources().getString(R.string.overview);
}
while debugging the control goes inside the if statement which means app is not null.
The App class:
public class App extends Application {
private static App app = new App ();
private App () {
}
#Override
public void onCreate() {
super.onCreate();
}
public static App getInstance() {
if (app == null) {
app = new App ();
}
return app;
}
}
Everything seems to be fine, but when I run it I get null pointer exception:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
at android.content.ContextWrapper.getResources(ContextWrapper.java:87)
at com.emanager.ui.adapters.HomePagerAdapter.getPageTitle(HomePagerAdapter.java:45)
at android.support.design.widget.TabLayout.populateFromPagerAdapter(TabLayout.java:773)
at android.support.design.widget.TabLayout.setPagerAdapter(TabLayout.java:764)
at android.support.design.widget.TabLayout.setupWithViewPager(TabLayout.java:716)
at com.emanager.ui.activities.HomeActivity.onCreate(HomeActivity.java:65)
at android.app.Activity.performCreate(Activity.java:6237)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
at android.app.ActivityThread.-wrap11(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5417) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
I have tried some other ways, but does not seem to fix it.
How do I fix this exception?
You should not create Application by your self, it will be created once your app run before activity start.
try this:
public class App extends Application {
private static App app;
#Override
public void onCreate() {
super.onCreate();
app = this;
}
public static App getInstance() {
return app;
}
}
Problem with your code is you declared a default constructor of Application class as a private constructor.Although it is not necessary to declare a constructor at all but if you declare it then you must make it public #MikeM. suggested this in comments of another answer of this question here
Just do this
public class App extends Application {
private static App app;
public App()
{
//got a public constructor
}
#Override
public void onCreate() {
super.onCreate();
app = this;
}
public static App getInstance() {
return app;
}
}
and in your AndroidMenifest.xml
<application
android:name=".App"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
Singleton pattern is a good one, although I do not understand why would you need all of that. Would you explain why exactly do you need to have your app instance available through the whole app?
Regarding your question, getApplicationContext() method should be a way for you.

Using ProGuard / Dexguard with multiple Android Studio Modules

I have an Android Studio android project with two modules, Module A and Module B. I am building and testing these modules and then distributing them as .aar files. When the parent app that uses the .aars runs I am encountering an AbstractMethodError and I can't figure out why. I have included -keep flags for classes and interfaces in the dexguard-project.txt files of both modules in the hopes that it would work but to no avail. Here's more information about the project:
Module A contains a class called Util.class.
public class Util {
private static CustomObject getObjectFromDb(Context context) {
return new CustomObject();
}
public static class GetObjectTask extends AsyncTask<Context, Void, CustomObject> {
FetchCustomObjectListener mListener;
Context mContext;
public GetObjectTask(Context context, FetchCustomObjectListener listener) {
mListener = listener;
mContext = context;
}
#Override
protected CustomObject doInBackground(Context... params) {
return getObjectFromDb(mContext);
}
#Override
protected void onPostExecute(CustomObject d) {
super.onPostExecute(d);
mListener.onCustomObjectFetched(d);
}
}
}
Module A also contains an interface called FetchCustomObjectListener.class
public interface FetchCustomObjectListener {
public void onObjectFetched(CustomObject d);
}
Module B contains a class called Startup.class:
public class Startup {
private Startup(Context context) {
super(context);
Util.GetObjectTask getObjectTask = new Util.GetObjectTask(context, new FetchCustomObjectListener() {
#Override
public void onObjectFetched(CustomObject d) {
//handle custom object here
}
});
getObjectTask.execute();
}
At runtime the Startup class creates an instance of GetObjectTask and executes it. GetObjectTask grabs an object from the database and tries to return it to Startup class via the interface FetchObjectListener. At this point I am getting the following error:
java.lang.AbstractMethodError: abstract method "void a.b.c.FetchObjectListener.onObjectFetched(a.b.c.CustomObject)"
at a.b.c.Util$GetObjectTask.onPostExecute(SourceFile:65)
at a.b.c.Util$GetObjectTask.onPostExecute(SourceFile:48)
at android.os.AsyncTask.finish(AsyncTask.java:632)
at android.os.AsyncTask.access$600(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
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:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
As I understand it, this error can occur when an interface is 'kept' by one module or class and not 'kept' by another when Dexguard is run. So one module has the actual name and one has the obfuscated name and because of this the two modules can't communicate using the interface and so the AbstractMethodError is thrown.
In the past I have used Dexguard to successfully compile and run this project, but have since modularized the project more and feel that this may be part of the problem. I'm trying to narrow down what could possibly be a problem and thought that perhaps two modules trying to use an interface might be causing the problem.
Any ideas on how to solve this would be appreciated.
It turns out to be an incorrect file filter on the first library when processing the second library. You may have seen the warnings about missing classes from the first library. The problem has been fixed in DexGuard 6.1.15.
Note that processing the final application (including its libraries) is more effective than processing the individual libraries, if you have the choice.

Categories

Resources