Loosing MainActivity on Background - android

Everytime the application go in background, and the RAM start filling out, the application start loosing variables (if im not wrong, this is the normal behavior of Android, it loose the instances of variables)
When I bring back the app from background the application crash, because I loose the MainActivity.
There is a way to relaunch this activity if there is not activity at all?
Is an ambiguous question but I found this question but I don't think is the best choice
ActivityManager mngr = (ActivityManager) getSystemService( ACTIVITY_SERVICE );
List<ActivityManager.RunningTaskInfo> taskList = mngr.getRunningTasks(10);
if(taskList.get(0).numActivities == 1 &&
taskList.get(0).topActivity.getClassName().equals(this.getClass().getName())) {
Log.i(TAG, "This is last activity in the stack");
}
Im loosing the full activity, well I can get the activity
#Override
public void onAttach(Activity activity) {
LocalNotification.registerReceiver(reloadReceiver, LocalNotification.RELOAD_CARTMG);
try {
mListener = (OnFragmentInteractionListener) activity;
MainActivity ma = (MainActivity)activity; //THIS IS LOOSE
ma.openMyList = false;
ma.openMyAddress = false;
ma.hideSearchButton();
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnFragmentInteractionListener");
}
super.onAttach(activity);
}
This is the Log inside the app
com.XXXX.mg E/Uncaught Exception detected in thread {}: Unable to start activity ComponentInfo{com.XXXX.mg/com.XXXX.view.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.XXXX.view.MainActivity.showShoppingCartIcon()' on a null object reference
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.XXXX.mg/com.XXXX.view.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.XXXX.view.MainActivity.showShoppingCartIcon()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2426)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1354)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5443)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.XXXX.view.MainActivity.showShoppingCartIcon()' on a null object reference
at com.XXXX.view.shoppingCart.ShoppingCartFragment.onDetach(ShoppingCartFragment.java:411)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1202)
at android.support.v4.app.FragmentManagerImpl.removeFragment(FragmentManager.java:1349)
at android.support.v4.app.BackStackRecord.popFromBackStack(BackStackRecord.java:915)
at android.support.v4.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1722)
at android.support.v4.app.FragmentManagerImpl$3.run(FragmentManager.java:593)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1617)
at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:339)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:602)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1260)
at android.app.Activity.performStart(Activity.java:6261)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2389)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490) 
at android.app.ActivityThread.-wrap11(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1354) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5443) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) 

I'm not sure if your app crashes just because you loose your MainActivity, you should be coding expecting this kind of behaviour, using onSaveInstanceState like #pablobu suggested is the right approach.
Can we see the logs? If you're loosing the state of your instances that's fine, you should save those states and restore them Recreating an Activity is it because of Fragments? you can also save those too, Handling Fragments Tutorial this is a good read.
Please, can you give us your logcat output, that might help a lot for us to see whats really going on.
EDIT
With your Logcat edit, try to take a look to the fragment lifecycle, onAttach executes first than onActivityCreated(), so if your Activity is already destroyed, your onAttach method will not have your activity, you should wait until your Activity is recreated .
Furthermore, you have your
super.onAttach(activity);
at the end of your code block, put it before your code block.
/**
This method was deprecated in API level 23.
Use onAttach(Context) instead.
*/
#Override
public void onAttach(Context context) {
super.onAttach(context);
MainActivity mainActivity;
if (context instanceof Activity) {
mainActivity = (MainActivity) context;
try {
mListener = (OnFragmentInteractionListener) mainActivity;
/**
Since you are getting a reference and accesing attributes you should be careful
with NullPointerException, check if not null first.
Or better yet refactor a little your code using an interface to handle this behaviour or use
the one you already created and just tell the activity what to do.
*/
/*if(mainActivity != null) {
ma.openMyList = false;
ma.openMyAddress = false;
ma.hideSearchButton();
}*/
} catch (ClassCastException e) {
throw new ClassCastException(mainActivity.getClass().getSimpleName() + " must implement OnFragmentInteractionListener");
}
}
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//since your Listener is global use mListener behaviour that I suggested here.
if (mListener != null){
mListener.openListOfSomething(false);
mListener.hideSearch();
}
}

You can use the Bundle savedInstatceState, wich is given in OnCreate and similar methods:
private String aVariable;
#Override
public void onCreate (Bundle savedInstantceState) {
super.onCreate(savedInstanceState);
// Get the variable from savedInstanceState, if it isn't empty.
// If it is empty, it could be the first Activity run.
try {
aVariable = savedInstanceState.get("Key");
} catch (NullPointerException e) {
aVariable = "Baum";
}
}
#Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putString(aVariable, "Key");
}
These methods set the Variable "aVariable" to "Baum" on the first run
(NullPointerException, because there is no String to "Key").
Later, when the Activity is going to be destroyed, onSaveInstanceState will be called. There you save your variables (aVariable) under a Key ("Key").

Related

I get Fragment not attached to a context. What context need to use?

I get the Exception from Firebase Crashlytics
Fatal Exception: java.lang.IllegalStateException: Fragment MyFragment{122418b (05b123e6-aa8d-4de4-8f7e-49c95018234b)} not attached to a context.
at androidx.fragment.app.Fragment.requireContext(Fragment.java:774)
at androidx.fragment.app.Fragment.getResources(Fragment.java:838)
at com.timskiy.pregnancy.fragments.MyFragment$1$1.run(MyFragment.java:156)
at android.os.Handler.handleCallback(Handler.java:907)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:216)
at android.app.ActivityThread.main(ActivityThread.java:7625)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987)
Error line from fragment
imageView.setColorFilter(ContextCompat.getColor(getContext(), R.color.blue));
also tried
imageView.setColorFilter(getResources().getColor(R.color.blue));
I use viewPager in Activity and FragmentStatePagerAdapter. What context I need to use in fragment to setColorFilter? Thx
Add this in your fragment:
private Context mContext;
#Override
public void onAttach(Context context) {
super.onAttach(activity);
mContext = context;
}
#Override
public void onDetach() {
super.onDetach();
mContext = null;
}
And in your image view
imageView.setColorFilter(ContextCompat.getColor(mContext, R.color.blue));
You are getting this crash because you are trying to call getContext() from a fragment that has already been detached from the parent Activity.
From the stacktrace it appears that there is a call to MyFragment.java line 156 from a Handler, this leads me to assume that its some background work happening but its getting completed when the fragment has been detached.
A quick fix for this would be to check if the fragment is attached to activity before attempting to execute any line of code that modifies the view.
if (isAttachedToActivity()){
imageView.setColorFilter(ContextCompat.getColor(getContext(), R.color.blue));
}
or
if (isAttachedToActivity()){
imageView.setColorFilter(getResources().getColor(R.color.blue));
}
The isAttachedToActivity() looks like this:
public boolean isAttachedToActivity() {
boolean attached = isVisible() && getActivity() != null;
return attached;
}
Try to use application context to fetch app resources to prevent IllegalStateException (not attached to a context)
// Init global variable with the application context first:
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
if (appContext == null)
appContext = context.getApplicationContext();
}
Then use appContext var anywhere you want to get app resources ex:
imageView.setColorFilter(ContextCompat.getColor(appContext, R.color.blue));
Probably you're trying to reach ViewPager's child Fragmnet's components, when the fragment is not created yet, or it's already destroyed. Could you make your post more detailed?
In your fragment it is safe to use requireContext() / requireActivity() inside onViewCreated instead of getContext() / getActivity().
imageView.setColorFilter(ContextCompat.getColor(requireContext(), R.color.blue));

Bundle not restored in Activity (appcompat 7:25.1 bug)

I have implemented simple drill-down pattern with several activities that pass data to display. But when I go back (either android back button or toolbar's back button) my app crashes in onCreate because parameters are gone.
Ok, there are hundreds similar questions. Please read on. I did investigation and even senior developer reviewed my code and he did not understood.
This is a log how it was called:
TestItemsActivity.onCreate()
TestItemsActivity.onStart()
TestItemsActivity.onResume()
TestItemsActivity.onPause()
RunTestActivity.onCreate()
RunTestActivity.onStart()
RunTestActivity.onResume()
TestItemsActivity.onSaveInstanceState()
TestItemsActivity.onStop()
RunTestActivity.onPause()
TestItemsActivity.onCreate()
The last sentence is important - why is onCreate called again? Activity lifecycle says that onResume is expected.
Let's look at the source code. I use appcompat 7:25.1.
TestItemsActivity
public class TestItemsActivity extends AppCompatActivity {
TestScript script;
protected void onCreate(Bundle state) {
log.debug("onCreate()");
super.onCreate(state);
setContentView(R.layout.act_script_items);
if (state != null) {
script = (TestScript) state.getSerializable(ScriptListActivity.KEY_SCRIPT);
} else {
script = (TestScript) getIntent().getSerializableExtra(ScriptListActivity.KEY_SCRIPT);
}
...
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
Intent intent = new Intent(TestItemsActivity.this, RunTestActivity.class);
intent.putExtra(RunTestActivity.KEY_POSITION, position);
intent.putExtra(ScriptListActivity.KEY_SCRIPT, script);
TestItemsActivity.this.startActivity(intent);
}
});
}
protected void onSaveInstanceState(Bundle state) {
state.putSerializable(ScriptListActivity.KEY_SCRIPT, script);
super.onSaveInstanceState(state);
}
AppCompatActivity
public class RunTestActivity extends AppCompatActivity {
protected void onCreate(Bundle state) {
log.debug("onCreate()");
super.onCreate(state);
setContentView(R.layout.act_script_items);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbarCalc);
if (toolbar != null) {
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
moveTaskToBack(true);
}
});
}
Intent intent = getIntent();
script = (TestScript) intent.getSerializableExtra(ScriptListActivity.KEY_SCRIPT);
}
And now the most interesting source code is the manifest:
<activity
android:name=".activities.TestItemsActivity"
android:label="#string/action_academy"
android:parentActivityName=".activities.ScriptListActivity">
</activity>
<activity
android:name=".activities.RunTestActivity"
android:label="#string/action_academy"
android:parentActivityName=".activities.TestItemsActivity">
</activity>
Accidentally I found that if I remove parentActivityName than android's back button does not start new activity (onCreate) and my app does not crashes! Unfortunatelly toolbar's back button disappears.
Some SO questions I read:
Saving Android Activity state using Save Instance State
save the state when back button is pressed
How to save activity state after pressing back button?
Bundle savedInstanceState is always null
SavedInstantState created during onSaveInstanceState not restored in onCreate
Can somebody explains what is going there?
Complete stacktrace including parts that I removed from source code above. It fails in adapter because scripts instance is null. The activity failed to initialize it either from intent or bundle (which is null despite that onSaveInstanceState was called)
java.lang.RuntimeException: Unable to start activity ComponentInfo{lelisoft.com.lelimath.debug/lelisoft.com.lelimath.activities.TestItemsActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List lelisoft.com.lelimath.data.TestScript.getItems()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
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)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List lelisoft.com.lelimath.data.TestScript.getItems()' on a null object reference
at lelisoft.com.lelimath.adapter.TestItemAdapter.<init>(TestItemAdapter.java:97)
at lelisoft.com.lelimath.activities.TestItemsActivity.onCreate(TestItemsActivity.java:55)
at android.app.Activity.performCreate(Activity.java:6679)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) 
at android.app.ActivityThread.-wrap12(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:154) 
Update:
Workaround for this problem is to use a theme without a toolbar:
<activity
android:name=".activities.CampaignActivity"
android:label="#string/action_academy"
android:theme="#style/AppTheme.NoActionBar">
</activity>
Unfortunatelly I need the toolbar for one activity.
As you can see from the trace you provided, the activity was stopped and state was saved. Therefore later when activity is to be restored it will call onCreate().
TestItemsActivity.onSaveInstanceState()
TestItemsActivity.onStop()

Android activity and fragment lifecycle issue?

I have the following stack trace for a crash caused by an NPE:
Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.daybreak.my.app/com.daybreak.my.app.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ViewSwitcher.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2430)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490)
at android.app.ActivityThread.access$900(ActivityThread.java:153)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1358)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5456)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:735)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ViewSwitcher.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
at com.daybreak.my.app.TimesFragment.onLocationChange(TimesFragment.java:446)
at com.daybreak.my.app.MainActivity.onLocationChange(MainActivity.java:289)
at com.daybreak.my.app.MainActivity.onCreate(MainActivity.java:112)
at android.app.Activity.performCreate(Activity.java:6302)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2383)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490)
at android.app.ActivityThread.access$900(ActivityThread.java:153)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1358)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5456)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:735)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
The way I have setup my app is as follows:
MainActivity
public class MainActivity extends AppCompatActivity implements LocationChangeListener {
#Override
public void onCreate(Bundle savedInstanceState) {
//...
onLocationChange(LocationManager.getSavedLocation(this)); // Manually calling onLocationChange() method
if (findViewById(R.id.fragment_container) != null) {
if (savedInstanceState != null) return;
showFragment(new TimesFragment(), TimesFragment.TAG);
}
}
#Override
public void onLocationChange(Locatin location) {
if (location == null) return;
//...
// Call attached onLocationChange() if it implements LocationChangeListener
Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
if (f instanceof LocationChangeListener)
((LocationChangeListener) f).onLocationChange(location);
}
}
TimesFragment
public class TimesFragment extends Fragment implements LocationChangeListener {
private ViewSwitcher viewSwitcher;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//...
viewSwitcher = (ViewSwitcher) view.findViewById(R.id.view_switcher);
}
#Override
public void onLocationChange(Location location) {
this.location = location;
viewSwitcher.setOnClickListener(null); //<-- NPE Cause here
updateContent();
}
}
MY EXPECTATION
From what I understand, the Activity.onCreate() will only be called after a fresh start or after the user navigates back to the app after the app has been killed (explicitly by the user or by memory management when other apps need memory). If this happens the fragments will also be destroyed and will need to be created, i.e., fragment's onCreateView() will be called. Therefore calling onLocationChange() from the MainActivity.onCreate() before attaching the fragment is safe as findFragmentById() within the onLocationChange() would not find any fragment.
REALITY
From the stack trace we can see that the call initiated from MainActivity.onCreate(). But what's puzzling for me is that at the time onLocationChange() is called from within MainActivity.onCreate(), findFragmentById() within the onLocationChange() finds the fragment in the view container and calls the fragments onLocationChange(). When this happens the viewSwitcher is NULL and causes the app to crash.
Obviously, fragment has already been added to the view container and the fragments onCreateView() has not been called yet.
THE QUESTION
I am not able to recreate this crash, and not sure of the lifecycle process that is causing this.
So can anyone tell me
how to reproduce this error and
the lifecycle process that is responsible for the flow that is causing the NPE?
This is being caused by device rotation. Can recreate the stack trace by rotating the device.
NOTE: This can happen even when app's orientation is locked (as in my case); if the user is in another app in an orientation that is different than the orientation your app is locked to and they switch back to the app, the orientation lifecycle for your app will be fired.
SOLUTION
Add f != null && f.isResumed() before calling methods from the fragment. isResumed() will return false if fragment hasn't been resumed after recreation.

Activity started from service visibility null

i am trying to have an activity launched from a service.
My problem is hiding/showing this activity.
The activity is started like so
overlay = new BubbleOverlay();
Intent intent = new Intent(this, overlay.getClass()).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Activity:
public class BubbleOverlay extends Activity {
private boolean active = false;
private View mainView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.overlay_layout);
mainView = findViewById(R.id.main_overlay_layout);
if(mainView == null)
Log.d("BubbleOverlay", "onCreate: MainView is null");
}
public void setActive(boolean value){
active = value;
}
public void hide(){
active = false;
mainView.setVisibility(View.INVISIBLE);
}
public void show(){
active = true;
mainView.setVisibility(View.VISIBLE);
}
I am trying to toggle the visibility of the mainView from the service.
Handler handler = new Handler();
Runnable runnable_longClick = new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
overlay.hide();
}
};
handler.postDelayed(runnable_longClick, 5000);
this produces the following error:
07-28 05:51:56.549 21690-21690/com.derp.derp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.derp.derp, PID: 21690
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.setVisibility(int)' on a null object reference
at com.derp.derp.BubbleOverlay.hide(BubbleOverlay.java:37)
at com.derp.derp.BubbleService$4.run(BubbleService.java:181)
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:6044)
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)
The reason you're getting the Null Pointer Exception is the mainView has not been initialised before its use. This happens because the Activity's onCreate() method which holds the object's initialise statement has not been called (with respect to the overlay object you created inside your Service). The onCreate() method will only be called once the Activity is created.
In order to call the hide() method of the Activity from the Service you need to create a proper communication channel between the Activity and the Service i.e. you need to bind the Service to your Activity. I know, this approach requires a bit of coding efforts but its the best approach and it will guarantee you flawless and smooth functioning for your app.

Android app crashes after update and Open on Google Play

I have an app on Google Play that tends to make the app crash if it is in the background when the app is updated and then re-opened by the user. The crash only happens sometimes, which is hinting towards a race condition somewhere. I am having a hard time debugging this and have only been able to reproduce this a few times myself, though I have got some stack traces reported by users. The stack traces are never pointing to the same line in the code, but the stack trace always enters my code through performResumeActivity() in Android and thus onResume() in my code. Note that this has never occurred to me or been reported by users in any other context than when updating the app (as far as I am able to tell). This does not mean that it only occurs when updating the app, but this is the only way I have seen the crash occur.
Steps to (sometimes) reproduce:
Install an old app version, e.g. by adb install app-release-previous-version.apk.
Open the app, play around a little bit and then minimize the app.
Open Google Play and update the app to the latest version.
Open the app from Google Play (we can open it from there after update).
The app crashes in performResumeActivity()/onResume() from time to time.
I'll add the code for the Activity where the crash occurs. Non-important code for this crash is not pasted, but let me know if I should add more code. The various stack traces I have are pasted at the end of the question.
MyActivity (important parts only)
public class MyActivity extends AppCompatActivity
{
private MyMainFragment myMainFragment = null;
private FilteredRecipes myFilteredRecipes = null;
private MyShoppingList myShoppingList = null;
private boolean mShouldReadAutomaticSave = false;
// <snip> other members
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mShouldReadAutomaticSave = savedInstanceState == null;
setContentView(R.layout.my_activity);
// Setup Toolbar / ActionBar.
Toolbar toolbar = (Toolbar) findViewById(R.id.my_main_toolbar);
setSupportActionBar(toolbar);
NavigationView navigationView = (NavigationView) findViewById(R.id.my_navigationview);
if (navigationView != null)
{
// <snip> Setup navigationView
}
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.my_drawer_layout);
if (drawerLayout != null)
{
// <snip> Setup DrawerLayout
}
if (myShoppingList == null) { myShoppingList = new MyShoppingList(this); }
if (myFilteredRecipes == null) { myFilteredRecipes = new MyFilteredRecipes(this); }
if (myMainFragment == null) { myMainFragment = new MyMainFragment(); }
if (savedInstanceState == null)
{
// Runs a thread to read recipes from an SQLite database. This is not the culprit.
filterAllRecipes(null);
}
else
{
restoreState(savedInstanceState); // See method below
}
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.fade_in, R.anim.none)
.replace(R.id.my_content_frame, myMainFragment, "main_fragment")
.commit();
}
#Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
if (myFilteredRecipes != null)
{
myFilteredRecipes.onSaveInstanceState(outState); // Restores from Bundle
}
if (myShoppingList != null)
{
myShoppingList.onSaveInstanceState(outState); // Restores from Bundle
}
if (myMainFragment != null)
{
getSupportFragmentManager().putFragment(outState, "myFragment", myMainFragment); // Restores from Bundle
}
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
}
private void restoreState(Bundle savedInstanceState)
{
myShoppingList.onRestoreInstanceState(savedInstanceState);
myFilteredRecipes.onRestoreInstanceState(savedInstanceState);
myMainFragment = (MyMainFragment)
getSupportFragmentManager().getFragment(savedInstanceState, "myFragment");
}
#Override
public void onResume()
{
super.onResume();
// These tests were added as an attempt to cure the crash.
// Probably fixed some of the crashes (stack traces below), but not the entire issue.
if (myShoppingList == null) { myShoppingList = new MyShoppingList(this); }
if (myFilteredRecipes == null) { myFilteredRecipes = new MyFilteredRecipes(this); }
if (myMainFragment == null)
{
myMainFragment = new MyMainFragment();
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.fade_in, R.anim.none)
.replace(R.id.my_content_frame, myMainFragment, "main_fragment")
.commit();
}
if (mShouldReadAutomaticSave) // Set in onCreate() when applicable
{
mShouldReadAutomaticSave = false;
final MyActivity mThis = this;
Thread loadAutomaticSaveThread = new Thread()
{
#Override
public void run()
{
// Load automatic save if any. Must be done last to avoid race condition in LoadShoppingListTaks.
JSONObject automaticSave = ShoppingListFileHandler.readAutomaticSavedShoppingList(mThis);
if (automaticSave != null)
{
// This task takes the JSON data from the file read above, reads data from an SQLite database and sets up the myShoppingList data.
// Calls back to MyActivity.onShoppingListLoaded() when done.
// NOTE: There has been a crash in here when myShoppingList was null. This was before the "== null" tests above was added.
new ShoppingListFileHandler.LoadShoppingListTask(mThis, myShoppingList, automaticSave, false).execute();
}
}
};
loadAutomaticSaveThread.setName("LoadAutomaticSaveThread");
loadAutomaticSaveThread.start();
}
}
// This is called from the LoadShoppingListTask when done.
#Override
public synchronized void onShoppingListLoaded()
{
if (myShoppingList != null)
{
// MyShoppingList.notifyDataSetChanged will call notifyDataSetChanged on a
// RecyclerView adapter in the main Fragment. There is a stack trace for this below.
myShoppingList.notifyDataSetChanged();
}
}
}
So that's the Activity where the crashes occur. Here are the stack traces I have got, some of them are partly obfuscated, since I hadn't understood what it did at that time.
Stack trace for a missing Fragment
Notes: It seems that we get a Fragment that is null, i.e. it is probably myMainFragment that is null when trying to restart the Activity.
java.lang.RuntimeException: Unable to resume activity {com.my.app/com.my.app.activities.MyActivity}: java.lang.IllegalArgumentException: No view found for id 0x7f0f0089 (com.my.app/my_content_frame) for fragment a{215e6dc #0 id=0x7f0f0089 main_fragment}
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3403)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3434)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2772)
at android.app.ActivityThread.access$900(ActivityThread.java:177)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1449)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5951)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
Caused by: java.lang.IllegalArgumentException: No view found for id 0x7f0f0089 (com.my.app/my_content_frame) for fragment a{215e6dc #0 id=0x7f0f0089 main_fragment}
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1098)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1286)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:758)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1671)
at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:388)
at android.support.v4.app.FragmentActivity.onPostResume(FragmentActivity.java:512)
at android.support.v7.app.AppCompatActivity.onPostResume(AppCompatActivity.java:178)
at android.app.Activity.performResume(Activity.java:6430)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3392)
... 11 more
Stack trace for Shopping List == null
Notes: Crash in the LoadShoppingListTask since the myShoppingList member was null in the task. This happened before adding the tests in the start of onResume().
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:304)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String[] com.my.app.shoppinglist.j.a(android.content.Context, java.util.ArrayList, java.lang.String, android.util.SparseIntArray, org.json.JSONArray, java.util.ArrayList, boolean)' on a null object reference
at com.my.app.filehandling.ShoppingListFileHandler$LoadShoppingListTask.doInBackground(ShoppingListFileHandler.java:882)
at com.my.app.filehandling.ShoppingListFileHandler$LoadShoppingListTask.doInBackground(ShoppingListFileHandler.java:770)
at android.os.AsyncTask$2.call(AsyncTask.java:292)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
... 4 more
Stack trace from RecyclerView in the main Fragment
Notes: There are multiple of these in various places in the RecyclerView when binding data. This particular RecyclerView lives in the main Fragment in the Activity. These crashes are the only times I have had problems with it. The RecyclerView reads its data from the myShoppingList member in the Activity. It seems like the Views are not created yet.
java.lang.NullPointerException: Attempt to read from field 'android.widget.TextView com.my.app.gui.fragments.shoppinglist.k.a' on a null object reference
at com.my.app.gui.fragments.shoppinglist.ShoppingListAdapter.bindRecipeName(ShoppingListAdapter.java:401)
at com.my.app.gui.fragments.shoppinglist.ShoppingListAdapter.onBindViewHolder(ShoppingListAdapter.java:249)
at com.my.app.gui.fragments.shoppinglist.ShoppingListAdapter.onBindViewHolder(ShoppingListAdapter.java:31)
at com.my.app.gui.fragments.shoppinglist.ShoppingListAdapter.access$000(ShoppingListAdapter.java:31)
at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:5471)
at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:5504)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4741)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4617)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1994)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1390)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1353)
<snip> Long stack trace inside Android classes...
Stack trace with Fragment == null
Notes: This was the first stack trace I got. Unfortunately I had not realized that I had to add deobscufation files at this point, so the stack trace is not that useful. But it seems obvious that the member myMainFragment was null at the crash.
java.lang.RuntimeException: Unable to resume activity {com.my.app/com.my.app.activities.MyActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'int com.my.app.gui.fragments.c.a.L()' on a null object reference
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3403)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3434)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2772)
at android.app.ActivityThread.access$900(ActivityThread.java:177)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1449)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5951)
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:1400)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int com.my.app.gui.fragments.c.a.L()' on a null object reference
at com.my.app.activities.MyActivity.t(Unknown Source)
at com.my.app.activities.MyActivity.onResume(Unknown Source)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1255)
at android.app.Activity.performResume(Activity.java:6412)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3392)
... 11 more
I cannot see where I have taken the wrong turn. Any hints and comments are appreciated.

Categories

Resources