I have two Android apps that communicate with each other through BroadcastReceiver. But if the second receiver application wasn’t started, the first one just sits there... The second application, once started, needs to continue running indefinitely, but not interrupt the first application by popping up over it. So I need a way to start the second application through the first one, BUT the screen has to continue showing the first application.
Through the first app, I check for presence of the second application, and if it's found and is not running, I start the application:
Intent SecondApp = getPackageManager().getLaunchIntentForPackage("com.example.app2");
startActivity(SecondApp);
But this brings up the second application to the screen ontop of the first one. So I need a solution to ether
1) Start the second application under the fist one
Or
2) Put the current first application immediately one on top of the second app
What’s the best solution here, and how to do it?
I assume that your second application has a service running in background and when you do the startActivity(SecondApp); pass some parameters with the intent, and in the second app read this parameter and just call finish after starting the service if that parameter is present.
Thank you guys for your help. The command finish() surprisingly does get rind of the UI, but doesn’t kill the application.
There was still the issue of only “minimizing” it when I start it from scratch through the first app, and run the second application normally in all other cases. So I added a boolean flag to the first application intent:
Intent SecondApp = getPackageManager().getLaunchIntentForPackage("com.example.app2");
SecondApp.putExtra("StartMinimized",true);
startActivity(SecondApp);
In the second application onCreate I put this code in:
Intent glob_intent = getIntent();
boolean startmini = glob_intent.getBooleanExtra("StartMinimized",false);
glob_intent.putExtra("StartMinimized",false);
if(startmini)
{
finish();
Toast.makeText(this,"L",Toast.LENGTH_LONG).show(); //Inform that app started
}
Now when starting the first application, the second application only flashes a white screen for a moment. I think this is good enough.
I found that substituting finish(); with super.moveTaskToBack(true); also works, but can cause glitching later. This way I personally started the second application twice, or caused the introduction dialog to not display when making the application one instance only.
Related
When using the intended(IntentMatcher) from the Android Espresso API, is it possible to do this twice in the same Activity?
So for example I click a button which starts an Activity for result. I check that this Activity has fired using intended(IntentMatcher). That works.
However, when I get the result, I want to fire off an Intent for a different Activity. In this case just a local Activity in the same app package with no result.
When I do this manually in the app it works fine, but Espresso can't seem to detect the second Intent in my test. What I am I missing or is this not possible? Alternatively, how should I be doing it? Maybe my design is bad.
When I do the check I'm trying this:
intended(toPackage(<packageName>));
intended(hasComponent(hasClassName(<className>)));
The first line matches but not the second one. And even if the second line is not completely correct it never seems to show anything in the error log about the second Activity I'm actually starting.
Another thing adding to the confusion is that two intents are definitely being fired as it shows that in the log. They both seem to be the same one but with slightly different details - one is a package, one is a component. Does it log the result from the first Intent as an Intent in itself? Sounds unlikely but where is this other intent coming from? I know it's not the second Activity I'm launching as it still fires even when that Activity isn't called (when the first Intent result is a fail).
I've also considered that maybe it's not getting detected because it's not waiting long enough for the second intent to fire. If that were the case, what would I do about that? I don't see much talk about handling time sensitive things in Espresso. Like checking if a progress bar is shown but then hidden again while not pressing anything. How do you do that? Maybe it's the same answer.
Any help appreciated!
Ok I found the problem. My IdlingResource wasn't working.
After fixing that it works like a charm :)
My application is launched using a tag, and based on the information contained in tag, it further proceeds. Now my app can also be started by using touching icon, and later it asks user to touch the tag. Small flow would be as below.
So MainActivity may contains tag data(if started from TagProcessorActivity), or may not contain data (if started from icon launch). Data is passed as intent extra value from TagProcessorActivity to IconLaunchActivity then to MainActivity. After main activity, app operation proceeds. When I leave the main activity, all my previous activities gets finish. I have checked onDestroy() is called for each activity. Now if I logout after MainActivity, (Logout simply a feature that closes all existing activity), and relaunch my application from recent app, my tag details still appears in MainActivity, which I dont know why.
To make is more clear my questions are:
1) Why activity which was destroyed still contains the information from previous launch.
2) I know about removeExtra() method, but is there some better options to tackle this problem.
3) and none the less, is there some thing wrong in my code or android is keeping that instance of intent extra?
PS: Not clear which piece of code to post, so if required feel free to ask for code.
Applications never exit in Android. onDestroy only destroys the activity, not any static variables left in the app. These will keep their value the next time an Activity is launched. This can be combined with some other features (like launching from the recent tasks menu causing you to launch the same intent) and this is the behavior you will get. The answer I always used was to detect this case (by checking the intent, there's a field that says if this is a restart or fresh), and ignoring the intent extras if so.
A finished task launched from Recents (as opposed to home screen launcher icon) will receive the old Intent, including its Extras, Data, etc. There is a way to know that it was launched from Recents so you can handle the Intent appropriately.
protected boolean wasLaunchedFromRecents() {
return (getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY;
}
In my humble opinion, that flag is poorly named (other flags referencing the Recents list actually use that word, e.g. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS, FLAG_ACTIVITY_RETAIN_IN_RECENTS) and the documentation was never updated to reflect the fact that many popular Android devices have a dedicated button for Recents:
This flag is not normally set by application code, but set for you by the system if this activity is being launched from history (longpress home key).
I'm designing an app composed two activities. The first one always run, and is asked to trigger a second one when some stuff happens. This works fine with the standard code used for running activities:
Intent myIntent = new Intent(this, allarme.class);
myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(myIntent);
however, the activity in allarme.class is not started if i'm using another app (i.e. gmail),
whilel it works perfectly from home or when the screen is locked.
I'm sure that the first activity is still running, it's just that the second action is not triggered.
Should I change anything in the manifest file to fix this?
I'm not really clear about what you want.
but I guess you want to run two activities simultaneously, am I right?
while one activity run in background and one activity update the UI.
always keep in mind that Android architecture only allowed one activity to run at the time. If you want to pass the data from Asynchronous Task, you can call the method from that class and let your handler 'recent' class update the UI.
You can create a background service that always run at background even if you are using another app or phone is locked. Here is link for more help :
http://developer.android.com/training/run-background-service/create-service.html
Thanks everybody, I think I solved it.
Basically, I found out that an activity already running can be brought to focus when re-started with a basic startActivity. Then I can immediatley switch to the new activity without losing the focus.
The first activity of my application is a splash screen, where some animation is displayed while some loading occurs in a background thread using AsyncTask.
Once the loading in the background is done, I want to start a new activity. What is the correct way to do that ?
Start a new activity directly from the onPostExecute method of the AsyncTask class.
Check if the current activity is displayed before starting the new activity :
If the current activity is display, start the new activity.
If the current activity is NOT display, use a flag (boolean) and check the flag during the onResume method in order to start the new activity there.
My main concern is :
If my application went to the background (due to an incoming phone call, a home key press, ...) and the background thread (AsyncTask) finished executing, and a new activity is started from the onPostExecute method while my application is still in the background : What happens ?
Will the new activity start directly as soon as my application is visible again ?
I faced a similar situation: my application went to background and after some time the app started an intent displaying another activity. However, the app's behavior now depends on the os that it's running:
on pre 4.4 devices the app silently opens the new activity and remains in background. When the user resumes the application, he is prompted with the second activity already.
on 4.4 devices (tested on 4.4.2 and 4.4.4) the app opens the second activity, but after 3-4 seconds, the app pops to foreground, interrumping the user.
Hope it helps anybody. I'm still looking solutions for the second case in order to prevent the app from popping to foreground.
From my experience i am answering your question
Question1
If you using AsyncTask you have to start new activity in OnPostExecute(). In my experience this is the correct way of doing it.
Question2
When ever your press the home key or receiving phone call. Your activity will go in to background until you exit the app by pressing back button(at that time your app is exited). So when you come back to your app your new activity will be visible if background process get finished. Otherwise you will see the start splash screen.
I think that it is dependent upon the OS of android. It has defined some built in priority model for each of the components.
Look at the answer given by commonsware.
change process priority in android
this gives brief idea about components priority.
I'm trying to kill 2 activities on the onclick of a button. The current activity and the previous activity. Using their pids. I'm just able to kill one activity. Why does this happen?
public void onClick(View v) {
android.os.Process.killProcess(pidofmain);
android.os.Process.killProcess(android.os.Process.myPid());
}
If I see in my logcat, The activity with pid "pidofmain" is getting killed whereas the current activity is not getting killed.
"pidofmain" is an integer i received from the previous activity using an intent.
Leave process killing to the OS. This is bad for any kind of program in a timesharing OS. If you want to conserve memory or something like that, let the OS handle it.
Also you can't really know if the process was correctly killed because well, if it is you wouldn't know, and if it doesn't you were not supposed to do it.
What do you want to do this for?
A much better way to do this is to call finish() for the current activity. You can also signal the previous activity to finish if it calls the current activity using startActivityForResult(Intent). The current activity would call setResult(int) before calling finish() to send a return code back to the previous activity. The previous activity can test the return code in onActivityResult(int, int, Intent) and also call finish() based on the result code.
Killing processes should be left to the OS. Once the activities finish, the will kill it off if it needs the resources. Otherwise it can let it around, which might help speed up a relaunch of your app if the user wants to run it again.
This isn't a definitive answer, but more like some thoughts that I have but it's too late for my to fire up Eclipse and prototype them. If it doesn't help you let me know and I'll try to look into it deeper tomorrow night.
A few thoughts (I hope they help):
1) Android apps really are single-threaded, and your main activity controls all the dispatch events (including events to what I assume to be a second thread that you created). If you kill the main activity, I'm pretty sure that your application would terminate execution immediately following your first call to android.os.Process.killProcess(pidofmain), and you'd never make it to your second call because you would have killed your entire application. Again, this is assuming by the variable name pidofmain that you are killing the main UI thread and not just an activity called main.
2) I'm a little curious also about where you got pidofmain? It sounds like you have three activities total, and in the first activity you get it's process id and send it to the second activity in an intent bundle, which also gets passed along to a third activity (which is the place where you're trying to kill this whole thing)? If that is the case, and you're trying to kill the currently running activity, the table in the documentation here leads me to believe that you can't just kill an activity that's in the resumed state using the same method. Official Android Docs for Activity You might want to try calling the finish() method for your currently running activity.
What exactly do you see in logcat? And what happens in the UI? Does the visible activity continue to run, but the other activity has been removed from the backstack?