My problem is exactly like this link but it's not in android.
I have one button on a layout and two buttons on an another one. On my application, ClickScreen activity can be triggered by either FirstCase activity or SecondCase activity.
I tried to make a conditional statement on my ClickScreen for which activity is triggered but couldn't handle it. I don't want to create two more classes to do this since it's not an efficient technique.
private void goTo2ndPage() {
Intent i3 = new Intent(this, ClickScreen.class);
startActivity(i3);
}
public class ClickScreen extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.click_screen);
}
}
As we discussed in comments. It looks like what you really want is to add extra data in your intent so that Started Activity can get it and act accordingly.
Check out this post !
If FirstActivity is the root of the task, and it finishes itself and launches SecondActivity, then calling isTaskRoot() in SecondActivity immediately will return false, because the FirstActivity's finishing happens asynchronously and thus isn't done yet. Waiting for a second and then calling isTaskRoot() returns true.
public class FirstActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
finish();
startActivity(new Intent(this, SecondActivity.class));
}
}
public class SecondActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onResume() {
super.onResume();
((TextView)findViewById(R.id.tv1))
.setText("isTaskRoot() in onResume(): " + isTaskRoot());
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
((TextView)findViewById(R.id.tv2))
.setText("isTaskRoot() after 1s: " + isTaskRoot());
}
}, 1000);
}
}
Is there a way to …
(optimally) find out whether the activity will be the task root eventually, or,
(better than nothing) get some sort of notification/callback once the task is in its "final" state and thus isTaskRoot() will return the "truth"?
I've had a similar problem and I wanted tight control over exactly who the root activity is. In my case, the root could only be one of my own activities (not 3rd party ones), so I was able to use the following approach:
I extended the Application class, added a weak reference to an activity called currentRootActivity and added synchronized getter and setter.
Then I managed this state by myself when activities were created / destroyed. My use case was a little special because I was looking to replace one root with another, so I knew exactly where to reset my new state variable, but I'm pretty sure you can do the same.
I was even able to add this state logic in a shared base class for all of my activities. So this wasn't as disgusting as it sounds :)
As mentioned in the comments, the activity method isFinishing might also come in handy.
Try:
Intent intent = new Intent(this, SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
I expect that this will make SecondActivity the root activity.
I was wondering how to keep a record of launched activites for logging purposes. what broadcast receiver I have to subscribe to intercept this intent? or what intent-filter to use? I figure that I must use some type of long-running service in the background.
My first objetive is to track main-focus applications, some sort of history.
Want to get finally some similar to:
- Launched app com.android.xxx
- Launched app xx.yy.zz
- App xx.yy.zz lost focus
Thanks in advance
EDIT - Just see that app MyAppRank , that does exactly what i mean
What i'm able to figure out from your question is that you want to keep track of all the activities when they are launched in your application. If that is correct, the solution may work for you:
Crate a BaseActivity which all of your Activities should extend
public class BaseActivity extends Activity
{
private Activity activity;
public static final String INTENTFILTER_TRACK_MY_ACTIVITIES="INTENTFILTER_TRACK_MY_ACTIVITIES";
public static final String INTENTFILTER_REMOVE_MY_ACTIVITIES="INTENTFILTER_REMOVE_MY_ACTIVITIES";
public void setActivity(Activity act)
{
activity = act;
}
public Activity getActivity()
{
return activity;
}
#Override protected void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
Intent intent = new Intent();
intent.setAction(INTENTFILTER_TRACK_MY_ACTIVITIES);
intent.putExtra("activityName", activity.getClass().getSimpleName());
sendBroadcast(intent);
}
#Override protected void onDestroy()
{
// TODO Auto-generated method stub
super.onDestroy();
Intent intent = new Intent();
intent.setAction(INTENTFILTER_REMOVE_MY_ACTIVITIES);
intent.putExtra("activityName", activity.getClass().getSimpleName());
sendBroadcast(intent);
setActivity(null);
}
}
Now extend above BaseActivity for all your activities. i.e instead of extending your Activities should extend BaseActivity and call setActivity(this); in onCreate like below:
public class MyActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setActivity(this);
//write your other code form here
}
}
3.Then write a BroadcastReceiver like below:
class TrackActivitiesReceiver extends BroadcastReceiver
{
private static final Object SEPERATOR = ",";// use , as seperator
String sb="";
#Override
public void onReceive(Context context, Intent intent)
{
if(intent.getAction().equalsIgnoreCase(BaseActivity.INTENTFILTER_TRACK_MY_ACTIVITIES))
{
sb+=intent.getStringExtra("activityName");
sb+=SEPERATOR;
}
else if(intent.getAction().equalsIgnoreCase(BaseActivity.INTENTFILTER_REMOVE_MY_ACTIVITIES))
{
sb=sb.replace(intent.getStringExtra("activityName")+SEPERATOR, "");
}
}}
4Finally, Register above Receiver in your AndroidManifest.xml
<receiver
android:name="TrackActivitiesReceiver"
android:exported="false" >
<intent-filter>
<action android:name="INTENTFILTER_TRACK_MY_ACTIVITIES" />
</intent-filter>
</receiver>
Hope this solves your problem. cheers!
There are no Intents broadcast when applications are started or when applications come to the foreground. There isn't anything that you can hook into as a listener to get these events.
The way you can do this (which is the way apps like MyAppRank do it) is to use the methods of the ActivityManager:
getRunningTasks()
getRunningAppProcesses()
getRecentTasks()
You create a Service which runs all the time and at regular intervals calls methods of the ActvityManager to determine which task is in the foreground and you can "infer" what the user has done (or is doing). It isn't an exact science.
Note: You will need android.permission.GET_TASKS and none of this works anymore as of API 21 (Android 5, Lollipop). As of API 21 the security has been tightened and an application can only get information about its own tasks, not other tasks in the system.
I have tried almost all the solutions from SO but no success :(.
I have a simple myJavaClass.java with a couple of functions.
One of the functions in myJavaClass : startActivity() starts MyCustomActivity
public startActivity(Context context)
{
Intent intent = new Intent(context, MyCustomActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
This launches MyCustomActivity() as expected.
Now I have another function in myJavaClass.java to close/finish MyCustomActivity but it is not able to do so!
I have tried
Making MyCustomActivity SingleTop in manifest and creating the activity via an intent as above
Passing an activity instance to "this" in onCreate() of MyCustomActivity and calling MyCustomActivity.activity.finish() from myJava.class but that doesnt work as well
Please help me. I have been stuck here for hours now. I know the solution is very simple and conceptual but I am a newbie. Just building Java/Android concepts!
EDIT
MyCustomActivity
public Activity activity;
OnCreate()
{
...
this = activity;
}
MyJavaClass
public closeActivity(Context context)
{
Activity customActivity = MyCustomActivity.activity;
customActivity.finish();
}
I think that what you are trying to do is fundamentally bad. For a start, outside of the Activity code, there are no guarantees that the activity still exists - the memory manager may have cleaned it up, the user may have pressed Back etc. Think of Activities as independent entities - you can start them, and you can optionally get a result back when they finish what they're doing, but that's it.
Think about whether you really have to programmatically close the activity from outside it - I'd say this is an unusual design, but there are circumstances where it may be appropriate.
If so, what I think you want is a publish/subscribe system whereby MyCustomActivity can register a listener with MyJavaClass, and then receive a callback whereupon it can 'finish' itself.
public Activity activity implements FinishListener
{
public void onCreate(...)
{
//where does MyJavaClass come from? see in a minute
MyJavaClass myjava = getMyJavaclass();
myJava.addFinishListener( this );
}
public void onFinishCallback()
{
this.finish();
}
}
and
public class MyJavaClass
{
private List<FinishListener> finishListeners = ...;
public void addFinishListener( FinishListener fl )
{
this.finishListeners.add(fl);
}
public closeActivity(Context context)
{
for ( FinishListener fl : finishListeners )
{
fl.onFinishCallback();
}
}
}
and
public interface FinishListener
{
void onFinishCallback();
}
Now the only remaining issue is how to get MyJavaClass from the Activity. That's up to you - you may already know how, you may be able to put it in your Application implementation, it could be a singleton (bad), the listeners could be static (bad) or various other options.
Oh, and don't forget to remove the listener again in the Activity's onDestroy() method!
Just try this....
public closeActivity(Activity _activity)
{
_activity.finish();
}
you can't finish activity from other class until you have the reference of instance of Activity in that class, give the reference in that class and call finish() method to stop the activity.
activity.finish();
There are three different cases:
1) A user launches an app, navigates in it, pressed home and click on the app icon again to launch our app again.
2) A user launches an app, navigates in it, presses home, chooses recent and click on the app to launch our app again.
3) A user launches an app, navigates in it, click something in the app (TextView with a link), which calls another app (as example Email) and user clicks back button, which bring us back to our app.
I know about flag "clearTaskOnLaunch" flag, it solves case #1.
I know about about flag "excludeFromRecents", it solves case #2 (may be not the most user friendly solution, but it works).
What about case #3? I have a workaround right now. However, I will have to put it on all activities which can be lead to another app. I wonder, whether there is better way to solve it (without handling it in all such activities).
This should be handled on the Application level.
For API level 14, you can register an ActivityLifeCycleCallback in your Application class
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
You can use it, to know on an Application level, which activities are destroyed, paused, resumed etc etc. Whenever, an activity is paused, without a new activity being created/resumed, you should clear the Activity stack, and re-launch your startActivity
If you target SDK versions < 14, you should implement your own method, to know which activities are created/resumed and paused, and do the same whenever an activity is paused, without a new activity being created/resumed
1) define a public static normalPause = true variable in a Class.
2) in onPause method of all of your activities set it false (I am worry. We might not be in a normal pause)
2) in onCreate method of all of your activities set it true (Do not worry. We are in a normal pause)
3) in onResume of all of your Activities:
if(!Utilities.normalPause)
{
this.finish()
}
Enjoy!
It seems a similar question has already been asked. It sounds like the OP came up with a working solution. How do I collapse "child activities"?
EDIT:
Instead of using a button you can use a boolean to tell whether or not you need to collapse back to the main activity. Have your root activity extend from Activity and the child activities extend from CollapsableActivity. To get this to work in all cases I added startOutsideActivity() and startOutsideActivityForResult().
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class CollapsableActivity extends Activity {
private boolean returnToRoot;
public static final int COLLAPSE_BACK = -1; // something other than RESULT_CANEL (0)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
returnToRoot = true;
}
#Override
protected void onStart() {
super.onStart();
returnToRoot = true;
}
#Override
protected void onRestart() {
super.onRestart();
// start collapsing the stack
if (returnToRoot) {
setResult(COLLAPSE_BACK);
finish();
}
}
#Override
public void startActivityForResult(Intent intent, int requestCode) {
super.startActivityForResult(intent, requestCode);
returnToRoot = false;
}
public void startOutsideActivityForResult(Intent intent, int requestCode) {
super.startActivityForResult(intent, requestCode);
returnToRoot = true;
}
#Override
public void startActivity(Intent intent) {
// call startActivityForResult to make sure and catch the collapse condition
super.startActivityForResult(intent, 0);
returnToRoot = false;
}
public void startOutsideActivity(Intent intent) {
super.startActivity(intent);
returnToRoot = true;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == COLLAPSE_BACK) {
returnToRoot = true;
}
}
}
This worked properly for me in all cases you listed. The only difference is you need to call startOutsideActivity() or startOutsideActivityForResult() when you navigate away from you app. Personally, I think this adds clarity to your intentions. Hope it helps!
I know you don't want to manage it in all activities but you can do this and still handle the code in one place with a super activity
public abstract class BlundellActivity extends Activity {
#Override
public void onPause(){
// Whatever strategy you want
}
}
public class SomeActivity extends BlundellActivity {
// Do whatever you normally want to do
}
public class SomeActivity extends BlundellActivity {
// Do whatever you normally want to do here as well
}
Perhaps, android:noHistory is what you're looking for. If you declare all your activities except StartupActivity with this attribute, then they will be finished as the user navigates away from them and only StartupActivity will appear.
You can try this steps:
use one boolean static flag isFinish in StartupActivity with default false value.
in onCreate() of StartupActivity set isFinish value to false.
write below code in onResume() method of all activities in your project.
if(isFinish)
{
finish();
}
set isFinish value to true when you open any native app like email, browser etc.
or
5 . set isFinish value to true in onBackPress() method whenever you want to close application on back press.
Case 6: if android browser open on clicking on any link then use below code is onPause() method
if(isBrowserRunning("com.android.browser"))
{
isFinish = true;
finish();
}
////////////////
private boolean isBrowserRunning(String processName)
{
ActivityManager manager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
String packageName = manager.getRunningTasks(1).get(0).topActivity.getPackageName();
Log.i("LogTest", "Current process package name: " + packageName);
return processName.equalsIgnoreCase(packageName);
}
You can create a sample project to know other browser package name like opera mini, US browser etc.
add below permission in manifest:
<uses-permission
android:name="android.permission.GET_TASKS" />
You can call this.finish() on the onPause() of your Activity, that way the activity will be closed in the three cases.
You need to use bundle and pass appropriate parameter/or parameters from the calling app (i.e. click something in the app (TextView with a link)).
Retrieve the parameter in the called app (Email app).
You can send the name of the activity in the parameter.
Now being in Email app(the called app) Click of back button navigate back to your calling application.
Optionally you can save the state of activity from the caller program, as required.
You need to use Bundle, and Intent to implement this logic.
Code snippet:
In the calling program, we need to store parameters/data required for back button functionality in the called program.
Bundle bndleData = new Bundle();
Use putString(), putInt() methods of Bundle class.
String prefix = getPackageName().toString();
(this prefix can be stored in application level constants.java file as applicable)
bndleData.putString("ParentActivity", this.getLocalClassName());
Also store additional parameters if required
bndleData.putString("paramName", valueofParamName);
bndleData.putInt("IntChannelImage", chImageInt);
Intent intent = new Intent(v.getContext(), AMRChannelPlayer.class);
intent.putExtra(prefix + "bndleChnlData", bndleData);
startActivity(intent);
Caller Program:
Retrive the data, activity nae from bundle and use it in back button implementation:
prefix = getPackageName().toString();
Bundle extras = getIntent().getBundleExtra(prefix + "bndleData");
String parentActivity = extras.getString("ParentActivity");
extras.getString("paramName");
I hope this helps you.
Instead of using multiple solutions you can use a single one that solves all the problems.
Check this answer:
https://stackoverflow.com/a/8576529/327011
With a Broadcast and BroadcastReceivers in each activities of your application you can kill all activities whenever your application goes to background.
UPDATE:
To detect if your application when to background you can use onStop, check this to understand the theory: Activity side-by-side lifecycle
And this is the implementation: https://stackoverflow.com/a/5862048/327011
I think this is all you need :-)