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.
Related
I am looking for help to better understand LiveData in Android.
I have created an application that allows a user to view, edit or create entries in a db.
I have used a viewmodel on the form activity to share information between the activity and fragments and to also make the data Lifecycle aware.
The code works great when I load a entry from the database. Any changes are captured and saved back to the database
However when I want to create a new entry using the same code I get
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method ...null object reference when I try to update the object in the viewmodel. Sample below tries to set the Name value when a user enters a new one:
public void afterTextChanged(Editable s) {
patternViewModel.getPattern().getValue().setName(s.toString());
((FlyPatternDetailActivity)getActivity()).setHasChanged(true);
((FlyPatternDetailActivity)getActivity()).setActionBar(s.toString());
}
My question is how to update the livedata object of my entity if I dont get an object back from my database and I am going to create a new entry.
My viewmodel is:
public class PatternViewModel extends AndroidViewModel {
private PatternRepository repo;
private LiveData<FlyPattern> mObservablePattern;
public PatternViewModel(#NonNull Application application) {
super(application);
if (mObservablePattern == null) {
mObservablePattern = new MutableLiveData<>();
}
repo = PatternRepository.getInstance(((FlyTyingJournalApplicationClass) application).getDatabase());
}
public void loadPattern(final long id){
if(id != -1)
mObservablePattern = repo.getPattern(id);
}
public LiveData<FlyPattern> getPattern(){
return mObservablePattern;
}
public void insertPattern() {
repo.insertPattern(mObservablePattern.getValue());
}
public void updateFlyPattern(){
repo.updatePattern(mObservablePattern.getValue());
}
public void deleteFlyPattern(){
repo.deletePattern(mObservablePattern.getValue());
}
}
I understand why I am getting the nullpointException.
My question is how to instantiate my mObservablePattern so I can update it.
It gets instantiated if the loadPattern returns an object.
If the loaddata does not run or does return an object from the database then I cannot update mObservablePattern.
Stacktrace from the Error:
Process: com.rb.android.flytyingjournal, PID: 4957
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.rb.android.flytyingjournal.entities.FlyPattern.setType(java.lang.String)' on a null object reference
at com.rb.android.flytyingjournal.flypatterndetails.PatternDetailsFragment$5.onItemSelected(PatternDetailsFragment.java:325)
at android.widget.AdapterView.fireOnSelected(AdapterView.java:931)
at android.widget.AdapterView.dispatchOnItemSelected(AdapterView.java:920)
at android.widget.AdapterView.-wrap1(AdapterView.java)
at android.widget.AdapterView$SelectionNotifier.run(AdapterView.java:890)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
You are trying to call setName() on a NULL. Because patternViewModel.getPattern().getValue() returns the value that is held in the LiveData, which might be NULL in your case. You can add a null check:
if (patternViewModel.getPattern().getValue() == null) {
FlyPattern flyPattern = new FlyPattern();
flyPattern.setName("foo");
patternViewModel.getPattern().setValue(flyPattern);
} else {
patternViewModel.getPattern().getValue().setName("foo");
}
Or you can create a function in the ViewModel called e.g. setFlyPatternName() and use it to update your DB.
In your PatternViewModel.java
public void setFlyPatternName(String name) {
if (mObservablePattern.getValue == null) {
FlyPattern flyPattern = new FlyPattern();
flyPattern.setName(name);
mObservablePattern.setValue(flyPattern);
repo.insertFlyPattern();
} else {
mObservablePattern.getValue().setName(name);
repo.updateFlyPattern();
}
}
Edit: The proper way of doing this is actually a bit different.
Normally your repository functions need to work on the background thread, since you are dealing with i/o, but if you want them to work on the mainThread you need to at least create a callback and pass that callback object to your repository function, which will be called when the data is inserted/updated/deleted. And when the callback function is called you need to call the setValue() on the LiveData and set the data to your livedata object.
Create a callback interface:
public interface InsertCallback {
void onDataInserted(FlyPattern flyPattern);
void onDataInsertFailed();
}
Change your repositories insert function's body to accept the Callback object as parameter
public void insertFlyPattern(FlyPattern flyPattern, InsertCallback insertCallback) {
// Do your insertion and if it is successful call insertCallback.onDataInserted(flyPattern), otherwise call insertCallback.onDataInsertFailed();
}
In your ViewModel implement InsertCallback and it's method
public class PatternViewModel extends AndroidViewModel implements InsertCallback {
//....
public void onDataInserted(FlyPattern flyPattern) {
mObservablePattern.setValue(flyPattern);
}
public void onDataInsertFailed() {
//Show error message
}
}
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
In the React Native AppState library:
iOS has three states background->inactive->active
Android only has background->active
When an Android app is fully backgrounded the MainActivity goes from onPause -> onStop
When there is a System Notification e.g. an In app purchase it goes to onPause
I need to run some code when the app goes from background to the foreground
onStop -> onResume
I don't want it to run if the app was briefly paused because of a system notification
onPause -> onResume
Is this possible? The lifecycle events for React do not have an onHostStop
I tried emitting an event from MainActivity for each Activity lifecycle event but that caused the App to crash with a null pointer exception.
Is it even possible to emit an event to React Native from MainActivity?
Thanks
EDIT Added code to show attempt to emit event from MainActivity
MainActivity.java snippet
import com.facebook.react.ReactActivity;
import com.facebook.react.modules.core.DeviceEventManagerModule;
public class MainActivity extends ReactActivity {
DeviceEventManagerModule.RCTDeviceEventEmitter eventEmitter;
#Override
public void onStop() {
super.onStop();
eventEmitter.emit("onStop", "ActivityonStop");
}
}
React Native
const nativeEventListener = DeviceEventEmitter.addListener('onStop',
(e)=>{
console.log("NATIVE_EVENT");
dispatch({type: "NATIVE_EVENT"})
})
error in logcat
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.realer.android, PID: 15251
java.lang.RuntimeException: Unable to stop activity {com.realer.android/com.realer.android.MainActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'void com.facebook.react.modules.core.DeviceEventManagerModule$RCTDeviceEventEmitter.emit(java.lang.String, java.lang.Object)' on a null object reference
at android.app.ActivityThread.performStopActivityInner(ActivityThread.java:3837)
at android.app.ActivityThread.handleStopActivity(ActivityThread.java:3886)
at android.app.ActivityThread.-wrap25(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1494)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'void com.facebook.react.modules.core.DeviceEventManagerModule$RCTDeviceEventEmitter.emit(java.lang.String, java.lang.Object)' on a null object reference
at com.realer.android.MainActivity.onStop(MainActivity.java:40)
at android.app.Instrumentation.callActivityOnStop(Instrumentation.java:1289)
at android.app.Activity.performStop(Activity.java:6839)
at android.app.ActivityThread.performStopActivityInner(ActivityThread.java:3834)
at android.app.ActivityThread.handleStopActivity(ActivityThread.java:3886)
at android.app.ActivityThread.-wrap25(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1494)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
Try updating your MainActivity.java like this:
public class MainActivity extends ReactActivity {
#Override
public void onStop() {
super.onStop();
WritableMap params = Arguments.createMap(); // add here the data you want to send
params.putString("event", "ActivityonStop"); // <- example
getReactInstanceManager().getCurrentReactContext()
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("onStop", params);
}
}
Let me know if this works. In my apps I usually send the events from a class that extends ReactContextBaseJavaModule where I can access the context just by calling getReactApplicationContext(), but it seems that it might work if you can obtain the ReactContext from the ReactInstanceManager.
According to docs
private void sendEvent(ReactContext reactContext,
String eventName,
#Nullable WritableMap params) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
If you are emitting from other class where context is not accessible then
you can set Context to static class and then access it from any other classes.
// ContextHolder.java
import com.facebook.react.bridge.ReactApplicationContext;
public class ContextHolder {
private static ReactApplicationContext reactContext;
public static ReactApplicationContext getReactContext() {
return reactContext;
}
public static void setReactContext(ReactApplicationContext context) {
ContextHolder.reactContext = context;
}
}
So instead of reactContext you can simply call ContextHolder.getReactContext()
Don't forget to set context in Module constructor
public class TheModule extends ReactContextBaseJavaModule {
public TheModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
ContextHolder.setReactContext(reactContext); // <- set
...
I am trying to write Unit test cases for Activities in my app by extending the test class with ActivityUnitTestCase. I could successfully run the test cases earlier but now I'm always getting the exception while running them. Even though I'm pretty familiar with handling NullPointerExceptions, I couldn't figure out the problem that's causing this. I couldn't find any similar questions so I'm posting this one.
Stack trace shows me there is a null object reference at this line in my code
activity = startActivity(mIntent, null, null);
But the startActivity method is supposed to get the instance of the activity I'm testing. I'm not sure why it's returning null.
Here is the Stack trace.
java.lang.NullPointerException: Attempt to write to field 'android.os.IBinder android.app.ActivityThread.mLastIntendedActivityToken' on a null object reference
at android.app.Activity.performCreate(Activity.java:6372)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
at android.support.test.runner.MonitoringInstrumentation.callActivityOnCreate(MonitoringInstrumentation.java:346)
at android.test.ActivityUnitTestCase.startActivity(ActivityUnitTestCase.java:158)
at com.abc.test.MainActivityTest.access$100(MainActivityTest.java:16)
at com.abc.test.MainActivityTest$1.run(MainActivityTest.java:34)
at android.app.Instrumentation$SyncRunnable.run(Instrumentation.java:1891)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6117)
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:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
Test running failed: Instrumentation run failed due to 'java.lang.NullPointerException'
Here is the Test class
public class MainActivityTest extends ActivityUnitTestCase<MainActivity>{
private Intent mIntent;
private MainActivity activity;
public MainActivityTest() {
super(MainActivity.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
//Create an intent to launch target Activity as it is not automatically started by Android Instrumentation
mIntent = new Intent(getInstrumentation().getContext(), MainActivity.class);
//Start the activity under test in isolation, in the main thread to avoid assertion error.
getInstrumentation().runOnMainSync(new Runnable() {
#Override
public void run() {
activity = startActivity(mIntent, null, null);
}
});
}
#Override
protected void tearDown() throws Exception {
super.tearDown();
}
/**
* Tests the preconditions of this test fixture.
*/
#SmallTest
public void testPreconditions() {
assertNotNull("MainActivity is null", getActivity());
}
#MediumTest
public void testSecondActivityWasLaunchedWithIntent() {
// Get the intent for the next started activity
final Intent launchIntent = getStartedActivityIntent();
//Verify the intent was not null.
assertNotNull("Intent was null", launchIntent);
//Verify that LaunchActivity was finished
assertTrue(isFinishCalled());
}
}
#prudhvi I don't think I have a silver bullet, unfortunately, but I would suggest trying to follow these steps to upgrade to the new test support libraries in the newer versions of the SDK. Sorry that I can't be of more help!
I had the same issue.
The solution was to make the test an ActivityInstrumentationTestCase2 instead of an ActivityUnitTestCase, and have the activity created for me in the background
There's a good chance something in your application class (i.e. X extends Application) is crashing early on. If that's the case you'll see this error.... Checkout your logcat for traces.
i changed ActivityUnitTestCase to ActivityInstrumentationTestCase2 and removed my startActivity() calls (seems that ActivityInstrumentationTestCase2 automatically starts the activity) now it runs again
I have extended the Application object as MyApplication and the design is as follows
public class MyApplication extends Application {
private MyObject myObject;
public MyApplication () {
mInstance = this;
}
public static MyApplication getInstance() {
return mInstance;
}
public MyObject getMyObject(){
return myObject;
}
public setMyObject(MyObject object){
myObject = object;
}
}
I am accessing the myObject value in Activities as well as Services as MyApplication.getInstance().getMyObject(). I don't see any issue with this normally, but in production for few users sometimes suddenly getMyObject() is returning null i.e getting reset. First I was under the impression that the OS might be killing and re-creating the app due to which I am observing null. I am not avoiding the memory low scenario, however if that is the case it should be killing the Activities and the Services too before destroying the Application object.
Inside an Activity I am keeping a reference of MyApplication as
private MyApplication myApp = MyApplication.getInstance();
So this is how my observation from logs regarding the getMyObject() value.
myApp.getMyObject() prints != null
then a Service MyService gets called and inside that
MyApplication.getInstance().getMyObject() prints == null
again back in the activity myApp.getMyObject() or MyApplication.getInstance().getMyObject() prints != null
myObject has been initialized before printing these logs and in between these logs there is no myObject reset code getting called.
Can it happen that the Application object got re-created but the Acitivty is still active?
or
Can Service get a different instance of Application than that of the Activity thread?
As per my understanding in a app life-cycle myApp should always be equal to MyApplication.getInstance() as OS should maintain single instance of Application.
Note: Also would like to add that I am getting this un-usual behavior in Samsung Tab 4.
Don't store Data in the Application Object
The applicataion object will not stay in memory forever. When a user sends your application to the background by e.g. pressing the home button the application object might be killed if the system requires the memory. This might happen after minutes but could take hours. When the user then resumes the application the application object might not be the same as before and mMyObject will be null if it has no initial value.
Solutions
Make null checks and act accordingly
Use some form of data-storage
Initialize your object in the application constructor
public MyApplication () {
mInstance = this;
mMyObject = new MyObject()
}
You don't wanna have public constructor, but a onCreate() method.
You also want a static instance of the class.
public class MyApplication extends Application {
private MyObject myObject;
private static MyApplication mInstance;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
public static MyApplication getInstance() {
return mInstance;
}
public MyObject getMyObject(){
return myObject;
}
public setMyObject(MyObject object){
myObject = object;
}
}
And of course change your manifest to tell that's this is your class that will handle the application (if not done yet)
<application
android:name="com.XXX.MyApplication"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme">