In my app I am using location services, and after first install the app asks for Location permission. If the user click OK, permission is granted, if Cancel, then I have another dialog with some info.
Then - if the user has turned off the GPSon his device, a dialog will come up which asks to enable GPS - if Ok is clicked, the device settings are opened and here the user can enable the GPS.
As far as now everything works fine. But I need to restart the activity after the user is back from settings. (So I can load some items according the location).
For this I used onresume():
#Override
protected void onResume() { //restart activity after back from GPS settings
String action = getIntent().getAction();
// Prevent endless loop by adding a unique action, don't restart if action is present
if(action == null || !action.equals("created")) {
Intent intent = new Intent(this, Okoli.class);
startActivity(intent);
finish();
}
// Remove the unique action so the next time onResume is called it will restart
else
getIntent().setAction(null);
super.onResume();
}
I used there a unique action to avoid loop restart, so in oncreate I am setting also getIntent().setAction("created");
Now this is working fine - the activity restarts after the user is back from settings, but it conflicts with Permission dialog which I mentioned as first.
So if I have the onResume function, and the user installs the app, the Location permission dialog comes up, but in this case the user can't click CANCEL, because the dialog is looping forever if he clicks cancel. So it is appearing again and again until he clicks OK.
When I remove the whole onResume section from my code, then the Permission dialog works fine, but I need onresume for restarting activity.
okey, finally I store a value to SharedPreferences - when user doesn't allow the location access, and then I check this value onResume and only restart the activity if the value is not set. Works fine!
Related
I am a newbie on Android and I am creating a launcher. I want apps to be removed (uninstalled) so I have a list and I invoke system to uninstall it.
How can I know if the user pressed "Cancel" or "Ok" in the system dialog?
(I know the system will unisntall the app if I press "Ok" or wont if I press "Cancel", I just need to know how to get the answer to remove or not the app of my list [ArrayList]).
If you cant know it, how can I do to remove an app from a list without knowing if the user is going to uninstall it or not?
public void uninstall (int position){
Uri package1 = Uri.parse("package:"+apps_block.get(position).name.toString());
Intent uninstall = new Intent(Intent.ACTION_DELETE, package1);
startActivity(uninstall);
AppDetail toRemove = adapter_block.getItem(position);
adapter_block.remove(toRemove);
}
With this code, the app is always removed from my list even I press "Cancel".
You are removing the item from the list immediately after startActivity(). The user has not even seen the dialog yet by that point.
You could listen for the ACTION_PACKAGE_REMOVED system broadcast, confirm that it was for your requested package, and remove the package from the list at that point. By doing this from your activity via registerReceiver(), you can find out fairly quickly and have easy access to your UI code to update the list.
Having an issue with lifecycle events and need some help if possible. I have read the other posts with similar issue and error however, still stuck .... Explaination may be a little long.
I have an App that requires the user to login when any 'backgrounding' event occurs (App switch, screen sleep, phone call and so on). Previously I was using the method of 'getRunningTasks' to check is my app is no longer top of stack to trigger the login flags and activity. I am now using a suggested timer method via onPause / onResume in my Application class which works great.
Now the issue at hand, and the questions:
App into background by Device Home button.
App is in the background, all my checks and flags are properly set. When I relaunch the app (Icon press), it loads the last activity, then from the onResume function - performs a startIntent for the login activity - based on the flag set in the timer event. The user logs in, and returns to the activity they were on (Stock List). All Good.
App into background by App Switch
timer event fires and all login flags are properly done as previous example.
--> Click 'device Home'button, then App icon --- App loads properly and loads the Login Activity, users logs in -- all good.
Problem area
2b. App into background by App Switch --> Example, Android pull down menu, jump to device settings - then return to app via the device back button
timer event fires and all login flags are properly done as previous example.
--> Click device 'return/back' button to return directly to the app.
User goes to Login screen, clicks 'Login' button - gets app crash due to :
java.lang.RuntimeException: Performing pause of activity that is not resumed
followed by
java.lang.RuntimeException: Performing stop of activity that is not resumed
My own system Logs in the lifecycle events all seem to fire in the appropriate order.
Basic overview from app re-launch:
-> DashBoard onResume
-> check for login flag and call intent for Login activity
Dashboard onPause
Login onResume
Login - user login hit button
Login onPause --- activity finish
Return to Dashboard onResume
-> Load details
The only diff is in the last senario ... the DashBoard onPause happens after the Login onResume. Not sure if this is the problem, or an Async delay issue with the lifecycle events.
My Manifest includes:
android:minSdkVersion="10" --- Maintaining old API due to clients with older devices
android:targetSdkVersion="19"
Any help or suggestions on what may be out of whack here? or how to avoid this error.
Thanks
--
Some code:
From BaseActivity.java
~~~~~~
private AppPreferences mAppPrefs;
protected MyApplication mMyApp;
#Override
protected void onPause() {
super.onPause();
//start timer
mMyApp.startActivityTransitionTimer();
}
#Override
protected void onResume() {
super.onResume();
//update current Activity Name
mMyApp.setCurrentActivity(this);
mMyApp.stopActivityTransitionTimer();
mAppPrefs = new AppPreferences(getApplicationContext());
if (mAppPrefs.getAppDestroyed() == true
|| mAppPrefs.getExitType() == AppPreferences.EXITTYPE_FULLEXIT) {
// we want to fully exit/close the app
this.finish();
} else {
if (mAppPrefs.getForceLoginState() == true) {
//~~~~ process login events
Intent intent = new Intent(this, LoginScreen.class);
startActivity(intent);
return;
}
}
}
DashboardActivity extends BaseActivity
{
#Override
protected void onPause() {
super.onPause();
if (((MyApplication)this.getApplication()).getProcessingLogout()){
// if we are already processing a login, do not continue here
return;
}
// ~~~ activity specific onPause event such as unregisterReceivers
((MyApplication)this.getApplication()).startActivityTransitionTimer();
}
#Override
protected void onResume() {
super.onResume();
if (((MyApplication)this.getApplication()).getProcessingLogout()){
// if we are already processing a login, do not continue here
return;
}
// ~~~ activity specific onResume events such as registerReceivers
}
}
When open my application first time , i pressed home key.
again i click my application.
its not calling onResume() directly. its loading from splash screen onCreate().
is it android default.?
After i've pressed "Back" button , app has closed . there after ,i opened the application and pressed home key, the issue dont come its calling onResume() method not from splash screen onCreate().
My problem is , before pressing back key, if we press home key and open the app, tha app will opened newly. its added in stack.
I've download "Facebook" application and checked. that app also hav same issue.
How do resolve this problem in android?
Android may decide to kill your application when it's not in the foreground. If the application was killed, starting it again would probably show the splash screen again.
When open my application first time , i pressed home key.
again i click my application.
When you press Home Key then your application will go in background, and it will start from where you left if you directly open your application from background apps list. (Button beside HOME key)
And if you click on application icon from list of apps, it will launch again from first activity.
You can refer to this link
How to make an android app return to the last open activity when relaunched?
Check your Developer options.
My guess is that your problem is "Don't keep activities".
i got solution from here: http://code.google.com/p/android/issues/detail?id=2373
add this code onCreate() method in splash screen activity:
if (!isTaskRoot()) {
final Intent intent = getIntent();
final String intentAction = intent.getAction();
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) &&
intentAction != null && intentAction.equals(Intent.ACTION_MAIN)) {
finish();
}
}
I think your app will be killed if you need too much memory in the background. So if you know that your app goes to the background free some memory. It must not be all but for testing you could try it.
There is also a callback which informs you that you should free your memory:
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
#Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if(level >= TRIM_MEMORY_MODERATE) {
// free some memory
} else if(level >= TRIM_MEMORY_BACKGROUND) {
// free some more memory
}
}
I have an application that uses Urban Airship for push notification. When a notification arrives and the user clicks on it, activity A in my application should open and do something.
I've installed the BroadcastReceiver as is shown in the docs, and it's almost working.
When my app is in the foreground I don't let the user see the notification at all, and just handle it automatically.
When my app is not running at all, the activity opens up just fine.
When my app is in the background (which always happens when A is the top activity), a second instance of Activity A is created.
This is, of course, a problem. I don't want two A activities, I just want one of them. Here's the relevant BroadcastReceiver code:
#Override
public void onReceive(Context ctx, Intent intent)
{
Log.i(tag, "Push notification received: " + intent.toString());
String action = intent.getAction();
int notificationId = intent.getIntExtra(PushManager.EXTRA_NOTIFICATION_ID, -1);
if(action.equals(PushManager.ACTION_NOTIFICATION_OPENED))
{
Intent intentActivity = new Intent(ctx, ActivityA.class);
intentActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
UAirship.shared().getApplicationContext().startActivity((intentActivity);
}
}
UPDATE:
I tried to bypass this bug by calling System.exit(0) when the user presses Back on Activity A. The process ended, but then it was restarted immediately! My BroadcastReceiver is not called again in the second instance. What's happening?
UPDATE 2:
#codeMagic asked for more information about the app and activity A.
This app lets its user review certain items and comment on them. Activity A is started when the app is launched. If the user's session isn't valid any more, a Login activity is started. Once the user logs in, activity A becomes active again. A only has a "No items to review" message and a "Try now" button.
When the user logs in, the server starts sending push notifications whenever a new item is available for review. When the app gets the notification, activity A accesses the server and gets the next item to review. The item is shown in activity B. Once the review is submitted to the server, activity B finishes and activity A is again the top activity.
The server knows when a user is reviewing an item (because activity A fetched it), and doesn't send push notifications until the review is submitted - meaning a notification can't come if the user isn't logged in or if the user is viewing activity B.
While I agree there is a subtle race condition here, it is not causing the problem I'm seeing - in testing I am 100% positive there's no race condition - the push notification is only sent after Activity A becomes active again.
The solution was to add a launchMode='singleTask' to the activity in AndroidManifest.xml . As a result, instead of a new activity, onNewIntent of the same activity instance is called.
You can use one of several Intent Flags. FLAG_ACTIVITY_REORDER_TO_FRONT being one of them. This will bring the Activity to the front of the stack if it is already in the stack and if not then it will create a new instance. I believe you will still need FLAG_ACTIVITY_NEW_TASK if you aren't calling it from an Activity
Intent.FLAG_ACTIVITY_CLEAR_TOP should also work. But this will clear any other Activities on the stack. It just depends on what other functionality you need. Look through the Intent Flags and see which of these will work best for you
There are multiple scenarios when this could happen. One of them can be handled this way. Please see my answer here: https://stackoverflow.com/a/44117025/2959575
Ok, two notes on this :
You can register a broadcast receiver via the manifest so it is independent of any parts of your app. and use a Singleton pattern (keep a static reference to your activity somewhere in your app) that way you can check if their is an activity viewing or not and process accordingly.
// your activity A
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
myActivityReference = this;
}
public void onPause() {
super.onPause();
if (isFinishing()) {
myActivityReference = null;
}
}
or you can keep everything as it is and use activity lunching modes flags in your manifest such as singleTop, singleInstance ... etc. take a look here android activity lunch modes
Here is my problem -
I copied my .apk file onto phone memory card and launch my application clicking on it and it allows me to install my application.I install my application.Finally,I got system installation pop up containing two options "Open" and "Done".When i click "Open" my application got launched.Up to this point everything is working without any problem.
Now in my application I click on a button and some download is taking place as a result(Showing progress dialog).Now I press a Home button,so my application goes to background.
Now I again launch my application by going inside Menu and clicking on my application icon.
Expected result - Still I Should see Progress Dialog for downloading.
Actual result - A new instance/session of my application is getting started.
So how to avoid this so that only one and one instance/session of my application should run.
#Palejandro, here you are. Put the code below into your main activity onCreate() method:
// Possible work around for market launches. See
// http://code.google.com/p/android/issues/detail?id=2373
// for more details. Essentially, the market launches the main activity
// on top of other activities.
// We never want this to happen. Instead, we check if we are the root
// and if not, we finish.
if (!isTaskRoot()) {
final Intent intent = getIntent();
final String intentAction = intent.getAction();
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null && intentAction.equals(Intent.ACTION_MAIN)) {
Log.w(TAG, "Main Activity is not the root. Finishing Main Activity instead of launching.");
finish();
return;
}
}
I used this piece of code in my projects and it works fine!
I believe you need to put
<activity
android:launchMode="singleInstance"
</activity>
in the manifest file.
what do your OnPause, OnResume and OnCreate?
I will bet money you are not saving anything OnPause, and starting a new instance all the time via OnCreate.
You should read the notes on Activity Lifecycles.
If you haven't got this sorted yet, I would say your app is actually being killed when home is pressed, or perhaps you have a bug that doesn't latch onto whatever object is keeping state.
// put below code in your launcher activity before call super and setcontentview()
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
// get the info from the currently running task
List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(10);
boolean alreadyTask=false;
for(ActivityManager.RunningTaskInfo info : taskInfo){
ComponentName componentInfo = info.topActivity;
String value= componentInfo.getPackageName();
if(value.contains(getPackageName()) && !info.topActivity.getClassName().contains(getPackageName()+".LauncherActivity")){
alreadyTask=true;
Log.i(TAG, "second instance found!!!");
break;
}
}
if(alreadyTask){
finish();
}
I don't have a solution but the problem is that the intent used to start the app is different when you open it directly from install compared to opening it from your home screen. Since it will get started by two different intents it will open a new instance the second time round.
A quick work around is to avoid pressing "Open" when you have installed the application. Press "Done" and then find the application yourself.
See: http://code.google.com/p/android/issues/detail?id=2373