Android Admob Interstitial Memory leak - java

I'm trying to show interstitials at the end of some Activities. The problem is the interstitials seem to prevent the Activities from being garbage collected causing an out-of-memory exception. How do i resolve this? Thanks in advance.
public class AdActivity extends FragmentActivity{
//...
protected InterstitialAd interstitial;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
// Create the interstitial.
interstitial = new InterstitialAd(this);
interstitial.setAdUnitId(INTERSTITIAL_UNIT_ID);
// Create ad request.
AdRequest adRequest2 = new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
.addTestDevice(deviceId)
.build();
// Begin loading interstitial.
interstitial.loadAd(adRequest2);
}
#Override
public void onPause() {
super.onPause();
displayInterstitial();
}
public void displayInterstitial() {
if (interstitial.isLoaded() && System.currentTimeMillis() >= lastInterstitial + timeLag * 1000) {
lastInterstitial = System.currentTimeMillis();
interstitial.show();
}
}
And i used it like:
public class ActivityA extends AdActivity{ //...
}

Ok i seem to have fixed it by changing
interstitial = new InterstitialAd(this);
to
interstitial = new InterstitialAd(getApplicationContext());
I don't completely understand memory management in java/android but I think whats going on is because the Activity references interstitial and interstitial has a reference to Activity so neither gets garbage-collected. Passing in the application context rather than the Activity context prevents this cycle dependency and solves the problems. Hope this helps someone :D.

One thing that helped me is to invoke the interstitial.show() on the uithread (since i guess its UI-stuff u have to do it on the ui-thread)

Just use application global context:
interstitial = new InterstitialAd(getApplication());
Don't use getApplicationContext(), because returned value will be your current activity.

Related

Android AsyncTask RecyclerView does not populate

I want to make an app lister application which fetches the application list via the packagemanager through an AsyncTask<Void, Void, List<PackageSummary>> nested in a singleton class. However, if and only if I implement the async task, the RecyclerView will not populate on the first OnCreate.
I am sure I am doing a silly mistake and/or do not understand AsyncTask and RecyclerView well enough, but for the love of me I cannot find the root of the issue.
In my toy app repository I have prepared two, relatively cleaner branches for illustration purposes:
One in which the packages are fetched in the main thread, and the recyclerview populates on first Oncreate (git_UI_thread).
One in which an AsyncTask<Void, Void, List<PackageSummary>> class is called. The application persistence is not set yet (on purpose), and the RecyclerView will only populate after the application is rotated (git_background_thread).
For those who are not inclined to click on the bitbucket link above, the code snippet of the inside of my AsyncTask looks like this:
#Override
protected void onPostExecute(List<SingletonPackageSummarySupplier.PackageSummary> packageSummaries) {
super.onPostExecute(packageSummaries);
isQueryingInProgress = false;
packageSummaryList = packageSummaries;
}
#Override
protected List<SingletonPackageSummarySupplier.PackageSummary> doInBackground(Void... voids) {
List<PackageSummary> installedPackages = new ArrayList<>();
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
List<ResolveInfo> resolveInfoList = context.getPackageManager().queryIntentActivities(intent, 0);
for (ResolveInfo resolveInfo : resolveInfoList) {
ActivityInfo activityInfo = resolveInfo.activityInfo;
installedPackages.add(new PackageSummary(resolveInfo.activityInfo));
}
return installedPackages;
}
And this is my Main activity OnCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
psList = SingletonPackageSummarySupplier.getInstance(context).getPackageSummaryListReadOnly();
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerViewLayoutManager = new LinearLayoutManager(context);
recyclerView.setLayoutManager(recyclerViewLayoutManager);
adapter = new AdapterApplist(context, psList);
recyclerView.setAdapter(adapter);
}
And this is how the singleton is fetched:
static SingletonPackageSummarySupplier instance;
public static SingletonPackageSummarySupplier getInstance(Context context) {
if (instance == null) {
instance = new SingletonPackageSummarySupplier(context);
} else{
instance.updateInstance(context);
}
return instance;
}
P.S.: I think (but not sure) the singleton pattern is justified in order to diminish the changes of memory leaks.
P.S.2: I have read a couple questions about this, but none had an accepted / working solution.
There are two steps: Update your data to AdapterApplist and notify it. Hence you should create a new method like:
public void setData(List<SingletonPackageSummarySupplier.PackageSummary> list)
{ //reset your data ere
}
inside AdapterApplist class. Then, update your post:
#Override
protected void onPostExecute(List<SingletonPackageSummarySupplier.PackageSummary> packageSummaries) {
super.onPostExecute(packageSummaries);
isQueryingInProgress = false;
packageSummaryList = packageSummaries;
adapter.setData(packageSummaryList);
adapter.notifyDataSetChanged();
}
Just add adapter.notifyDataSetChanged(); in your postexecute method of AsyncTask
Either I was unable to implement the observer pattern (note that the asynctask was in a singleton class separate from the recyclerview and activity), or it is just not working well in this case.
Anyway, I ended up fixing the issue with the relatively new lifecycle-aware components: MutableLiveData, LiveData and AndroidViewModel (instead of viewmodel, which does not get context as constructor parameter). It is simple and elegant.
The key part was this, in the activity:
PackageSummarySupplier model = ViewModelProviders.of(this).get(PackageSummarySupplier.class);
model.getPackageSummaryList().observe(this, packageSummaryList -> {
adapter = new AdapterApplist(context, packageSummaryList);
recyclerView.setAdapter(adapter);
});

Libgdx Android: method onStart() not called after onCreate()

onStart()
I know that onStart() method is called after onCreate() ( via Activity Lifecycle documentation ), but in my LibGDX project this doesn't happen. I' ve this code:
#Override
protected void onStart()
{
super.onStart();
Gdx.app.debug(TAG, "onStart");
}
but the string in debug terminal appears only if I resume the app from background. I need to do stuff after the initialise of the activity, when it becomes visible.
EDIT: MORE CODE
public class AndroidLauncher extends AndroidApplication {
private final static String TAG = AndroidLauncher.class.getSimpleName();
GoogleResolver googleResolver;
GoogleSignInAccount acct;
private Preferences googlePrefs;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
googleResolver = new GoogleResolverAndroid();
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
config.useImmersiveMode = true;
config.useGyroscope = false;
config.useCompass = false;
config.useAccelerometer = false;
GoogleLoginHandler.getInstance().setContext(this.getContext());
GoogleLoginHandler.getInstance().startApiClient();
GameManager.getInstance().listener = googleResolver;
initialize(new MainCrucy(), config);
googlePrefs = Gdx.app.getPreferences(GOOGLE_PREF);
GoogleLoginHandler.getInstance().mGooglePrefs = Gdx.app.getPreferences(GOOGLE_PREF);
}
#Override
protected void onStart()
{
super.onStart();
Gdx.app.debug(TAG, "onStart");
OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(GoogleLoginHandler.getInstance().getGoogleApiClient());
if (opr.isDone())
{
Gdx.app.debug(TAG, "Loggato");
GoogleSignInResult result = opr.get();
handleSignInResult(result);
} else {
opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
#Override
public void onResult(GoogleSignInResult googleSignInResult) {
handleSignInResult(googleSignInResult);
}
});
}
}
This is what I do. But onStart() does anything
How long do you wait after launching you application?
You have to remember that your app can take time to Start. If what you say is true than you wouldn't see Gdx debug - it's still fires at onStart().
So I assume:
you launch an app
you don't want to wait so you minimize that
you open it and onStart() ends and you see debug logs
By the way, could you show more code?
In the meantime look at the life cycle of Android app.
Android lifecycle
You can't use Gdx.app.debug() before the Libgdx application has had a chance to start up. I'm not positive if this happens before onStart() because libgdx doesn't run on the UI thread. Also, you must also use Gdx.app.setLogLevel(Application.LOG_DEBUG) first or calls to Gdx.app.debug() will do nothing.
But you can just use Android's Log.d() instead.

Android setContentView on pretty short Activity life time

The first activity of my android app, the "launcher activity", finishes pretty quickly. It's goal is to redirect to the MainActivity or to the UserLoginActivity, depending on the value of a shared-preferences variable.
If this variable does not exist, it automatically perform a StartActivity to the MainActivity.
If this variable is set, then it will perform an HTTP request to my API, in order to Authenticate the user. Then it will start the MainActivity. The HTTP request usually takes less than one second.
The thing is that I would like to display a progress bar, in the center of the LauncherActivity, so the user can understand that something is loading.
The problem is that nothing is displayed on the screen. But if I comment the line that starts the activity, then it will be displayed... It seems that the activity duration is too fast to display anything !
I thought calling the setContentView() method will instantly load Views on the screen. Is my case a normal behavior ? How could I display a progress bar on the screen, knowing that the activity will last around one second ?
Here you can see my Launcher Activity
public class Launcher extends Activity {
private void goToUserLogin(){
Intent intent;
intent = new Intent(this, UserLoginActivity.class);
startActivity(intent);
finish();
}
private void goToMain(){
YokiAPI API = new YokiAPI(this);
Intent intent;
try {
if (API.authenticateSmart(YokiGlobals.preferences.getSavedUserId(this))) {
intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
} else {
this.goToUserLogin();
}
} catch (Exception e){}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launcher);
// Launch Demo if First Run
if (YokiGlobals.preferences.getFirstLaunch(this)){
YokiGlobals.preferences.updateFirstLaunch(false, this);
this.launchDemo();
}
/*
** If userId saved, smart Auth and go to Main
** Else go to User Login for Full Auth or register
*/
if (YokiGlobals.preferences.getSavedUserId(this) == null){
this.goToUserLogin();
}
else {
this.goToMain();
}
}
}
And the .xml ressource file
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="THIS TEXT WONT APPEAR"
android:layout_marginTop="208dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
Thanks,
Oscar
I thought calling the setContentView() method will instantly load Views on the screen
No it won't because you are still in onCreate(). If you want to see any UI you need to let the activity cycle to go further, so rework your code or move your authentication to separate activity, meybe?
PS: you use this. without any real reason.
Thank you for your help. I used AsyncTask in order to fetch data from the API.
The main UI thread can now load the view.
Here is some very simplified code that maybe could help others.
public class UserSmartAuthActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_smart_auth);
new SmartAuth().execute();
}
private class SmartAuth extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
Context context = getApplicationContext();
YokiAPI API = new YokiAPI(context);
Intent intent = null;
try {
if (API.authenticateSmart(YokiGlobals.preferences.getSavedUserId(context)))
intent = new Intent(context, MainActivity.class);
else
intent = new Intent(context, UserLoginActivity.class);
} catch (Exception e){}
startActivity(intent);
finish();
return null;
}
}
}

How to change the main task between two activities?

I'm so begineer level of Android.. so I need you guy's advice..
I have two activities
A -> MainActivity
B -> LoadingActivity
My problem is,
when I execute my application, firstly, A is started and it takes 4 seconds to do database task.. So I thought it would be better to make another activity just for showing loading page..
So in the MainActivity, I wrote this code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startActivity(new Intent(this, LoadingActivity.class)); <-- this
setContentView(R.layout.activity_main);
What I intended is, the LoadingActivity should be started, before this MainActivity is started, so that LoadingActivity shows the loading image on the screen for 4 seconds to cover MainActivity database task.
So, my intended sequence is,
B(show up on screen for 4sec) -> A(started almost same with B, working behind the B activity screen) -> B is killed (call finish() method) -> than, use the app.
please, give any advice, would be very appreciate..
And, here is my LoadingActivity class code..
public class LoadingActivity extends FragmentActivity{
private static int SPLASH_TIME_OUT = 6000;
private String tag = "LoadingSplash";
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.start_up);
String localUrl ="file:///android_asset/loading_gif.gif";
WebView wv=(WebView) findViewById(R.id.startup);
//wv.getSettings().setJavaScriptEnabled(true);
wv.getSettings().setPluginState(PluginState.ON);
//wv.getSettings().setAllowFileAccess(true);
Log.i(tag, "WebView get Setting finish....");
wv.setPadding(0, 0, 0, 0);
wv.setInitialScale(getScale());
//wv.getSettings().setLoadWithOverviewMode(true);
//wv.getSettings().setUseWideViewPort(true);
wv.loadUrl(localUrl);
new Handler().postDelayed(new Runnable() {
/*
* Showing splash screen with a timer. This will be useful when you
* want to show case your app logo / company
*/
#Override
public void run() {
// This method will be executed once the timer is over
// Start your app main activity
Log.i(tag, "Here is Runnable Method...");
finish();
}
}, SPLASH_TIME_OUT);
#SuppressLint("NewApi")
private int getScale(){
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
Point p = new Point();
display.getSize(p);
int width = p.x;
Double val = new Double(width)/new Double(800);
val = val * 100d;
return val.intValue();
}
}
You don't need two separate activities, you can execute an AsyncTask thread to do your database works and in "onPreExecute" method of AsyncTask class start to show your "desired custom view"(probably containing progressBar) and do your stuff in "doInBackground" method and in "onPost" method of AsyncTask class just set that "desired custom view"'s visibility to Gone.
Hope this works.
you can use Asynctask For Background processing. After Processing complete you can start next activity.You Should use progress dialog on async task :)
if you are not understanding then u can ask to me...
Regards
Asim

Why is my onResume being called twice?

Basically, this is what I'm doing
1) Set AlarmManager to execute BroadcastReceiver (BCR)
Intent intent = new Intent(m_Context, BCR.class);
intent.putExtras(extras);
PendingIntent pendingIntent = PendingIntent.getBroadcast(m_Context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, StartTime, pendingIntent)
2) Start MyActivity from BCR
#Override
public void onReceive(Context context, Intent intent) {
Intent newIntent = new Intent(context, MyActivity.class);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(newIntent);
}
3) Have MyActivity turn on the screen if its not on
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(LayoutParams.FLAG_DISMISS_KEYGUARD);
getWindow().addFlags(LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().addFlags(LayoutParams.FLAG_TURN_SCREEN_ON);
setContentView(R.layout.myactivity);
}
#Overide
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
}
For some reason, I notice that right when MyActivity is opened, it's flow goes like:
onCreate/onNewIntent -> onResume -> onPause -> onResume
I'm not sure why it does an onPause right away. I notice this only happens when the screened is being turned on by the flags. Does anyone know why this happens? Is there any way this behavior can be prevented?
if you trying request permissions every time it can cause such problems, just check if you already granted them
requestPermissions can cause it:
onCreate
onStart
onResume
onPause
onResume
Use this method ContextCompat.checkSelfPermission(context, permission) to check if permission was granted or not before requesting it
This method returns int and you can check it with PackageManager.PERMISSION_GRANTED constant
Just in case anyone else runs into this, I seem to notice this behaviour only when I inflate fragments inside of an activity via XML layout. I don't know if this behaviour also happens with the compatibility library version of Fragments (I'm using android.app.Fragment)
It seems the activity will call Activity#onResume once before calling Fragment#onResume to any added Fragments, and then will call Activity#onResume again.
Activity:onCreate
Fragment:onAttach
Activity:onAttachFragments
Fragment:onCreate
Activity: onStart
Activity: onResume
Fragment: onResume
Activity: onResume
If you have ES File Explorer then FORCE STOP it. Somehow, they interrupt your app's lifecycle (comments suggest some kind of overlay).
My issue with onResume being caused twice was because onPause was somehow being called after the activity was created.. something was interrupting my app.
And this only happens after being opened for the first time after installation or built from studio.
I got the clue from another post and found out it was because of ES File Explorer. Why does onResume() seem to be called twice?
As soon as I force stop ES File Explorer, this hiccup behavior no longer happens... it's frustrating to know after trying many other proposed solutions. So beware of any other interrupting apps like this one.
I was researching about this for a while because on the internet there is no any mention about this weird behaviour. I don't have a solution how to overcome this dark-side-behavior but I have found an exact scenario when it certainly happens.
onPause-onResume-onPause-onResume just happens every time, when app is starting first time after installation. You can simply invoke this behavior by doing any change in code and rerunning (which includes recompiling) the app from your IDE.
No matter if you use AppCompat libs or not. I have tested both cases and behavior carries on.
Note: Tested on Android Marshmallow.
I have borrowed the code from this thread about fragment and activity lifecycle and here it is (just copy, paste, declare activity in manifest and run Forest run):
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class TestActivity extends Activity {
private static final String TAG = "ACTIVITY";
public TestActivity() {
super();
Log.d(TAG, this + ": this()");
}
protected void finalize() throws Throwable {
super.finalize();
Log.d(TAG, this + ": finalize()");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, this + ": onCreate()");
TextView tv = new TextView(this);
tv.setText("Hello world");
setContentView(tv);
if (getFragmentManager().findFragmentByTag("test_fragment") == null) {
Log.d(TAG, this + ": Existing fragment not found.");
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(new TestFragment(), "test_fragment").commit();
} else {
Log.d(TAG, this + ": Existing fragment found.");
}
}
#Override
public void onStart() {
super.onStart();
Log.d(TAG, this + ": onStart()");
}
#Override
public void onResume() {
super.onResume();
Log.d(TAG, this + ": onResume()");
}
#Override
public void onPause() {
super.onPause();
Log.d(TAG, this + ": onPause()");
}
#Override
public void onStop() {
super.onStop();
Log.d(TAG, this + ": onStop()");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, this + ": onDestroy()");
}
public static class TestFragment extends Fragment {
private static final String TAG = "FRAGMENT";
public TestFragment() {
super();
Log.d(TAG, this + ": this() " + this);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, this + ": onCreate()");
}
#Override
public void onAttach(final Context context) {
super.onAttach(context);
Log.d(TAG, this + ": onAttach(" + context + ")");
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(TAG, this + ": onActivityCreated()");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, this + ": onCreateView()");
return null;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.d(TAG, this + ": onViewCreated()");
}
#Override
public void onDestroyView() {
super.onDestroyView();
Log.d(TAG, this + ": onDestroyView()");
}
#Override
public void onDetach() {
super.onDetach();
Log.d(TAG, this + ": onDetach()");
}
#Override
public void onStart() {
super.onStart();
Log.d(TAG, this + ": onStart()");
}
#Override
public void onResume() {
super.onResume();
Log.d(TAG, this + ": onResume()");
}
#Override
public void onPause() {
super.onPause();
Log.d(TAG, this + ": onPause()");
}
#Override
public void onStop() {
super.onStop();
Log.d(TAG, this + ": onStop()");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, this + ": onDestroy()");
}
}
}
I don't know for sure what's going on, but I suspect that your activity is being restarted because setting the screen on is treated by the system as a configuration change. You might try logging the configuration on each call to onResume to see if that's what's happening and, if so, what is actually changing. You can then modify the manifest to tell the system that your activity will handle the change on its own.
protected void onResume() [
super.onResume();
Configuration config = new Configuration();
config.setToDefaults();
Log.d("Config", config.toString());
. . .
}
I have similar problem.
My situation was next
CurrentActivity extends MainActivity
CurrentFragment extends MainFragment
I was opening CurrentActivity with intent as usually. In onCreate CurrentAcitivity I was replacing CurrentFragment.
Life Cycle was:
1. onResume MainActivity
2. onResume CurrentActivity
3. onResume MainFragment
4. onResume CurrentFragment
called onPause Automatically, and after that again
onResume MainActivity
onResume CurrentActivity
onResume MainFragment
onResume CurrentFragment
I decide to retest everything and after few hours spend trying and playing I found root issue.
In MainFragment onStart I was calling startActivityForResult every time (in my case android popup for turning on Wifi) which was call onPause on MainFragment. And all of us know that after onPause next is onResume.
So its not Android bug, it's only mine :-)
Happy lifecycle debuging!
I also ran into this onresume-onpause-onresume sequence (on 4.1.2 and above, but I did not experience this on 2.3). My problem was related to wakelock handling: I accidentally forgot to release a wakelock and reacquiring it caused an error with a message "WakeLock finalized while still held". This problem resulted in onPause being called immediately after onResume and resulted in faulty behavior.
My suggestion is: check for errors in the log, those might be related to this issue.
Another hint: turning on the screen might be a bit more tricky than simply using window flags. You might want to check this answer here - it suggests you set up a receiver to check if the screen has already been turned on and launch the desired activity only after: https://stackoverflow.com/a/16346369/875442
I had a similar issue, and my problem was that at the onCreate() method, I was doing:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.setContentView(R.layout.friends); <-- problem
}
My call to "super." was triggering the onResume() twice. It worked as intended after I changed it to just:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.friends); <-- 'super.' removed
}
Hope it helps.
Have you tried calling your getWindow().addFlags(...) before calling super.onCreate(savedInstanceState) in onCreate method?
I had a similar problem. onResume was called twice when my onCreate looked like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setContentView(R.layout.main);
...
}
Changing it to:
#Override
public void onCreate(Bundle savedInstanceState) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
...
}
... fixed the problem.
It seems that using Activity from the support library saves and restores instance automatically. Therefore, only do your work if savedInstanceState is null.
I just ran into this, and it seems that getWindow().addFlags() and tweaking Window properties in general might be a culprit.
When my code is like this
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_generic_fragment_host);
// performing fragment transaction when instance state is null...
onResume() is triggered twice, but when I remove requestWindowFeature(), it's only called once.
I think you should have a look at that question:
Nexus 5 going to sleep mode makes activity life cycle buggy
You should find leads
Basically a lot of stuff can trigger this. Some resume processes that loses focus can do it. A few apps will cause it to happen too. The only way to cope is to block the double running. Note, this will also have an errant pause thrown in for good measure.
boolean resumeblock = false;
#Override
protected void onResume() {
super.onResume();
sceneView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
sceneView.getViewTreeObserver().removeOnPreDrawListener(this);
if (resumeblock) return false;
resumeblock = true;
//Some code.
return false;
}
});
}
This is a solid way to prevent such things. It will block double resumes. But, it will also block two resumes that preserve the memory. So if you just lost focus and it doesn't need to rebuild your stuff. It will block that too. Which might be a benefit clearly, since if you're using the resume to control some changes over focus, you only actually care if you need to rebuild that stuff because of focus. Since the pre-draw listeners can only be called by the one thread and they must be called in sequence, the code here will only run once. Until something properly destroys the entire activity and sets resumeblock back to false.
as #TWL said
ES File Explorer
was the issue for me !
Uninstalling the app solved the problem.
When this ES File Explorer was installed, onStart() -> onResume() -> onPause() -> onResume() .. was the problem.
onResume() was called 2'ce.
I had the same problem. Mine was for this code in runtime
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
I just put it in manifest
android:screenOrientation="landscape"
no more problem about twice call to onCreate and onResume.
I didn't see an adequate answer to the question, so I decided this.
From My Notes:
"It seems that the activity runs onResume() onPause() then onResume again. The very last method that runs is the onSizeChanged(). So a good practice would be to start threads only after the onSizeChanged() method has been executed."
So you could: Make a log of each method that runs. Determine the last method that runs. Ensure that you have a Boolean that initializes false, and only changes to true after your last method runs. Then you can start all threading operations, once you check that the Boolean is true.
-For anyone wondering: I am using a surfaceview that has a onSizeChanged() method that executes very last.
I had the same problem because of setting the UiMode in the onCreate() of MainActivity. Changing the theme triggered activity recreation and made two calls to onPause() and onStart().
I was sure this was happening in my app until I realized I had planted two of Jake Wharton's Timber trees, and onResume() was just being logged twice, not called twice.
i also faced this issue this is because of fragments..
the number of fragments you have in activity onResume() will call that number of times. to overcome i used flag variables in SharedPrefrences

Categories

Resources