how to make callback in activities - android

i have 3 activities
A activity has a button . On click of that button a scan happens (a continuous porcess) and after time it gives a callback to onreceive method.
Onreceiving the call back B activity is started . B is singleTask instance . It shows a list .
On clicking of any of the item in list in B , next the C activity starts.{startactivity(Cintent)}
In mean time , when again a call back comes in A , due to continuous result of scan , it starts B activity , But since B is single task , so new instance is not created and it smoothly shows the updated list.
Problem is when , user is in page C , and A gets a callback , it triggers B start Activty and B seeing the current activity running (checking activty manager) to be C , triggers C , but this time C is again created (new instance launched ) despite C also being Singletask .
I donot want C to be again created , i want to use the same older instance .
A (Main Launcher) -> B (SingleTask) -> C(SingleTask)
**
Code snippet
**
public class MainActivity extends Activity implements OnClickListener {
private Button connectButton;
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
connectButton = (Button) findViewById(R.id.btn_Connect);
connectButton.setOnClickListener(this);
connectButton.setEnabled(true);
}
public void onClick(final View v) {
final Intent B = new Intent(context,B.class);
// start a specific job and wait for the callback
}
// on receiving the call back result start activity of B
#Override
public void onReceive(final Context c, final Intent intent) {
startActivity(B);
}
}
Now B Activity shows a list onstart and when clicked on any item in list it navigate to C .
public class B extends Activity {
#Override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.B_list);
final Context context = this;
// Create Intent for C
intentCList = new Intent(context,
C.class);
}
#SuppressWarnings("unchecked")
private void putintoListVIew(Intent intent) {
BList.setOnItemClickListener(new OnItemClickListener() {
startactivity(intentCList);
}
}
ANdroidManifest.xml
<activity
android:name="com.broadcom.wiced.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.broadcom.wiced.RouterListActivity"
android:label="#string/app_name"
android:launchMode="singleTask">
</activity>
<activity
android:name="com.broadcom.wiced.WicedListActivity"
android:label="#string/app_name"
android:launchMode="singleTask">
</activity>

You can add in A activity boolean flag isActive and make it true onResume and false onPause.
When activity A get callback, you can check is it active and decide need to run B or not.

Make your Activity B and Activity C as singleTop. This way even if they are already launched, the same instances will be put on top.

Related

How to finish specific activities not all activities

In my android application suppose several activities are there
if using intent I go to other activities like this
[Activity A]->[activity B]->[Activity C]->[Activity-D]->[Activity N]
and now when am on activity N when I pressed button then I want to go to Activity B and want to destroy Activity C And Activity D but Activity A should not destroy. I also searched in various posts but I didn't get exactly the same solution.
Any help will be appriciated
In ActivityN, to return to ActivityB use this:
Intent intent = new Intent(this, ActivityB.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
Using the flag CLEAR_TOP will finish all activities in the stack that are on top of ActivityB. In the example you gave, this will finish ActivityN, ActivityD and ActivityC. Using the flag SINGLE_TOP will make sure that this will return control to the existing instance of ActivityB (ie: it won't create a new instance of ActivityB).
In Your Activity C do like this
public static ActivityC instance = null;
public class ActivityC extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
instance = this;
}
}
And in your Activity D do like this
public static ActivityD instance = null;
public class ActivityD extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
instance = this;
}
}
Finally in your Activity N. Do Something like this
public class ActivityN extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button yourButton= (Button) findViewById(R.id.yourButton);
yourButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ActivityC.instance.finish();
Activityd.instance.finish();
finish();
}
});
}
}
Here's my approach.
From Activity A, don't just start the Activity B, call startActivityForResult() method. Do this for all subsequent calls.
Now, when you press the button from Activity N, set the result for a custom value and call the finish() method for Activity N. Now you should hit the onActivityResult method on your Activity D. Now you can check whether the result was you pressing the button. Depending on your result, keep on setting the result and subsequently calling finish() on each Activity.
This should technically work.
Try this code:
//Activity A
Intent i = new Intent(getApplicationContext,ActvityB.class);
startActivity(i);
//Activity B
Intent i = new Intent(getApplicationContext,ActvityC.class);
startActivity(i);
//Activity C
Intent i = new Intent(getApplicationContext,ActvityC.class);
startActivity(i);
finish();
// finish here actvity which you want to finish
//Try this second way:
In your first activity, declare one Activity object like this,
public static Activity fa;
onCreate()
{
fa = this;
}
now use that object in another Activity to finish first-activity like this,
onCreate()
{
FirstActivity.fa.finish();
}
EDIT : Use startActivityForResult() instead of startActivity()
So depending on the result you can change the behavour.
Say for example When you wanted to go to ActivityB just return some flag in the INTENT. When it will be caught in Activity D and C in onActivityResult(), finish them and you will be finally on B.
Flag Intent.FLAG_ACTIVITY_CLEAR_TOP may solve your problem:
http://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_CLEAR_TOP
You can start ActivityC, ActivityD, ActivityN with the same request code passed to startForResult(requestCode)
And then at ActivityN, use finishActivity(int requestCode).
Documentation for finishActivity(int requestCode)
Force finish another activity that you had previously started with startActivityForResult.
Params:
requestCode – The request code of the activity that you had given to startActivityForResult().
If there are multiple activities started with this request code, they will all be finished.

Pressing back button from one activity refreshes previous activity in stack

On pressing back button from child activity parent activity displays for a second and refreshes itself.
In child activity I have this code in java file
#Override
public void onBackPressed()
{
Intent moveback =
new Intent(ClassActivityEdit.this, ClassActivity.class);
startActivity(moveback);
finish();
}
ClassActivityEdit is child class. In manifest file code is as follows
<activity android:name=".ClassActivity"
android:label="Class Activity">
<intent-filter>
<action android:name="com.teamtreehouse.oslist.ClassActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".ClassActivityEdit"
android:label="Class Activity"
android:noHistory="true">
<intent-filter>
<action android:name="com.teamtreehouse.oslist.ClassActivityEdit" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
On back button I just want the ClassActivity layout to be displayed without it being refreshed.
Edit:
ClassActivityEdit doesnt extend ClassActivity. Its just that some button press in ClassActivity will result in opening ClassActivityEdit.
Edit2
the below code in ClassActivity starts ClassActivityEdit
public void editListener(View v) {
Intent addNewClass =
new Intent(ClassActivity.this, ClassActivityEdit.class);
RelativeLayout buttonTableRow = (RelativeLayout) v.getParent();
TextView getCourseID = (TextView) buttonTableRow.findViewById(R.id.courseNumberActivity);
String courseIDString = getCourseID.getText().toString();
Bundle bundle = new Bundle();
//Add your data to bundle
bundle.putString("CourseIDString", courseIDString);
addNewClass.putExtras(bundle);
startActivity(addNewClass);
}
Edit 3: I also have a Landing (MAIN) activity which flashes for a second. On pressing back button from ClassActivityEdit activity Landing activity flashes again and then the ClassActivity activity loads. Finding it a bit tricky to solve.
public class LoadingPage extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loading_page);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Intent mainIntent = new Intent(LoadingPage.this, ClassActivity.class);
startActivity(mainIntent);
}
}, 1000);
}
}
Your Problem is so much strange ! just by not overriding OnBackPressed you will get the result you want.
I guess the problem is in your manifest.
android:noHistory="true"
It doesn't let the activity to stay in history stack, try removing it. also try this:
android:launchMode="singleInstance"
By doing this, the activity wont become created again.
The problem is with your override to the back press (which does not need to be overridden) and is likely a symptom of with what your activity does when focus returns to it.
Firstly if you don't override onBackPress the previous activity will load (that's the default behaviour because of the backstack) so you don't need to manually call it with a new intent and tell manually tell it to go to the previous activity.
When your parent activity (ClassActivity) then starts again it will go through the normal lifecycle - it will get resumed and all saved instance states get restored. Since you haven't posted it you need to make sure onResume and onRestart are not doing anything in your parent activity such as loading or setting data.
If you do keep the onBackPress you wrote then it will create a new instance and onCreate will always be called, unless it is singleInstance flagged, in which case onNewIntent will be called, but neither of these things seem to be what you want.
In response to your Edit 3 you need to make sure that LoadingPage has android:noHistory="true" so that it is not available to the backstack and then finish it explicitly to clean it up when you start the main class
That is a simple as calling finish when starting your intent
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Intent mainIntent = new Intent(LoadingPage.this, ClassActivity.class);
startActivity(mainIntent);
finish(); //end the wrapping activity (LoadingPage)
}
}, 1000);
The last thing you should be aware of is the difference between up and back navigation. In case you are navigating back via the home/up button you should also tell the manifest that these two activities are related. In the manifest entry for ClassActivityEdit you should add android:parentActivityName="com.teamtreehouse.oslist.ClassActivity"
Just let the back button do what it normally does. Don't override it and don't start a new activity. The parent activity is below the child activity in the stack, so it should appear when the child activity finishes.
By default, Android will retain activities in a stack, so when you go from Activity A to Activity B, Activity A will be brought back when you finish Activity B unless you do some other stuff like mess with the launchMode, finish A on returning from B, etc.
From what can be seen in your code, your problem should be solved by not overriding onBackPressed() in your child activity. Also, you should remove your <intent-filter> block for the child activity in the manifest.
I recommend reading up on managing the activity lifecycle and tasks and back stack.
First of all there is no need of overriding onBackPressed(). As Doug mentioned the parent activity is below the child activity in the stack , so it would be visible just after the child activity finishes on back pressed.
There is a suggestion for you as the ActionBarActivity is deprecated so it would be better to extend the class AppCompatActivity in your activity class.
I have tried to replicate the issue but failed. So I have created a classes.
LandingPage.java
public class LandingPage extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loading_page);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startActivity(new Intent(LandingPage.this, ClassActivity.class));
}
}, 1000);
}
}
ClassActivity.java
public class ClassActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.class_activity);
//Do whatever you want to do
}
public void editListener(View v)
{
Intent addNewClass = new Intent(ClassActivity.this,ClassActivityEdit.class);
RelativeLayout buttonTableRow = (RelativeLayout) v.getParent();
EditText getCourseID = (EditText) buttonTableRow.findViewById(R.id.courseNumberActivity);
String courseIDString = getCourseID.getText().toString();
addNewClass.putExtra("CourseIDString", courseIDString);
startActivity(addNewClass);
}
}
ChildActivityEdit.java
public class ClassActivityEdit extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.class_activity_edit);
String course_no = getIntent().getStringExtra("CourseIDString");
Toast.makeText(ClassActivityEdit.this,course_no,Toast.LENGTH_SHORT).show();
//Do whatever you want to do
}
}
Your main problem is that you have overridden onBackPressed in the child activity.
What I understand from your code is-
ClassActivity --> Parent Activity
ClassActivityEdit --> Child Activity
In manifest, android:noHistory="true" is specified for child i.e. ClassActivityEdit activity. So it won't be stored in stack. Nothing is mentioned for parent.
In onBackPressed of your child activity you are again creating new Parent activity even though it is already present in the stack. It's just below your child activity.
Even if you don't override onBackPressed, parent activity will still load. In your case, it is creating many instances of parent activity.
One more thing, unless you want your activity to handle or respond to specific actions, you don't need to add intent filters for activity in manifest. According to documentation,
"Intent filter Specifies the types of intents that an activity, service, or broadcast receiver can respond to. An intent filter declares the capabilities of its parent component — what an activity or service can do and what types of broadcasts a receiver can handle. It opens the component to receiving intents of the advertised type, while filtering out those that are not meaningful for the component."
you can using Intent easily move for back Activity. but your back activity refresh all date write in onresum() method then it esyly refresh data
In child activity I have this code in java file
#Override
public void onBackPressed()
{
Intent moveback =
new Intent(ClassActivityEdit.this, ClassActivity.class);
startActivity(moveback);
finish();
}
When you start child activity from parent activity your parent activity move to stack and child activity display in onBackPressed event on child activity you create a new instance of parent activity and in activity life cycle onCreate event called first and views inside it creating by default values, so when you click on back button in child activity without creating a new instance of parent activity android display parent activity with previous savedInstanceState then onResume event called.
for more details see Activity Life Cycle
Change your onBackPressed() in child activity to this or you can also remove the onBackPressed() from child activity
#Override
public void onBackPressed(){
super.onBackPressed(); // call super back pressed method
}
Make sure that you don't finish() parent activity when you move from parent activity to child activity
Try using FLAG_ACTIVITY_REORDER_TO_FRONT when starting the ClassActivity intent.
you said,
On pressing back button from ClassActivityEdit activity Landing activity flashes again and then the ClassActivity activity loads.
you might be calling finish() somewhere in the ClassActivity which will cause the activity to be removed from the stack. If so, remove it.
#Override
public void onBackPressed(){
finish();
super.onBackPressed();
}
this will solve your issue.
finish() will destroy your child activity and super.onBackPressed() will redirect you to parent activity.
You need to replace
startActivity(addNewClass);
with
startActivityForResult(addNewClass,101);
and then, in OnActivityResult you can refresh your data.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode==101){
if(resultCode==RESULT_CANCELED){
//refresh data accordingly
}else if(resultCode==RESULT_OK){
//refresh data accordingly
}
}
}

why the "up" button moves me to the main activity and not to the parent activity

I have an application with three activities.
MainActivity which looks like that:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button b = new Button(this);
b.setText("click me to go to child activity");
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, ChildActivity.class));
}
});
setContentView(b);
}
}
ChildActivity which looks like that:
public class ChildActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new TextView(this) {{
setText("I'm the child activity");
}});
}
}
And OtherActivity which looks like that:
public class OtherActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new TextView(this) {{
setText("I'm other activity");
}});
}
}
In the manifest I have such declaration:
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity android:name="pl.psobolewski.test.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="pl.psobolewski.test.ChildActivity" />
<activity android:name="pl.psobolewski.test.OtherActivity" />
</application>
Now when I start the application, it starts with MainActivity, from there I can go to ChildActivity, but there is no way to go to OtherActivity.
Then in the manifest I change this line:
<activity android:name="pl.psobolewski.test.ChildActivity" />
to:
<activity android:name="pl.psobolewski.test.ChildActivity" android:parentActivityName="pl.psobolewski.test.OtherActivity" />
Now I start again this application on my phone, which has Android API 16. It starts with MainActivity, there I can press the button and move to ChildActivity. Now the ChildActivity looks a little bit different than before: the logo on ActionBar has a little arrow-like icon (documentation calls it "a left-facing caret") which means it can be used to move up. But when I press it I don't go to OtherActivity - even though it is declared as the parent of ChildActivity - but to the MainActivity.
I find it contrary with the Android documentation which says:
http://developer.android.com/guide/topics/manifest/activity-element.html
"android:parentActivityName
The system reads this attribute to determine which activity should be started when the use presses the Up button in the action bar. The system can also use this information to synthesize a back stack of activities with TaskStackBuilder."
I also thought that adding android:parentActivityName attribute without calling setDisplayHomeAsUpEnabled would not turn the application logo into the up button - the documentation at http://developer.android.com/training/implementing-navigation/ancestral.html suggests so.
My question is: why the "up" button moves me to the MainActivity and not to the OtherActivity?
The Action Bar up navigation handler has been implemented in such a way that if the parent of current activity has no parent, then an Intent is created with ACTION_MAIN & CATEGORY_LAUNCHER to start the activity. This results in MainActivity being launched.
Have a look at definition of getParentActivityIntent() in Activity.java
To overcome this, in your ChildActivity.java override below 2 methods of Activity.
#Override
public boolean shouldUpRecreateTask(Intent intent) {
return true; // This creates a new task stack
}
#Override
public Intent getParentActivityIntent() {
Intent intent = new Intent(this, OtherActivity.class);
return intent;
}
If you don't want to override getParentActivityIntent, then you need to define a parent activity for OtherActivity in AndroidManifest.xml file, to overcome the earlier mentioned reason.
If you don't override shouldUpRecreateTask, since OtherActivity does not appear in history stack, it will remove all activities until the root activity of the task is reached, resulting in 'in-app home' behavior.

How to tag Activity

I'm using this code to jump back in activity stack (mainly to move to home Activity):
Intent goTo = new Intent(this, HomeActivity.class);
goTo.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(goTo);
So I create new Intent and set "target" to HomeActivity which is in Activity stack so whole stack will be cleared from top to this HomeActivity.
Now I need slightly different use case. I have for example five Activities A-B-C-D-E (A started B etc.) on the stack. Now I need to jump from E to C or B depending of what user choose. The problem is that Activities A, B, C, D, E have same class. So I can't use example above because I don't know how to target that Activity.
So the question is if there is any way how to "tag activity" or manipulate with stack.
Thanks!
I haven't tried it myself, but I think the best option would be to refactor your app to use a stack of Fragments within a single Activity (since you can then more easily manage the backstack using the provided addToBackStack() and popBackStack() methods). Basically this involves moving most of the code in your Activity into a Fragment and then adding the backstack manipulation code in the Activity). You can look at the code for FragmentBreadCrumbs (with API 11+) or the code for HanselAndGretel (for use with the compatibility library) to see how this can be implemented.
However, if you want to continue using your current multi-Activity approach, the following is some code I came up with to illustrate how you can do this.
First, add several internal classes to alias your current Activity and put these classes into a sequence list (note also the simplistic getSequencedActivityIntent() method that I wrote, you can add more advanced logic if you need - maybe use a HashMap to associate each class in the sequence with an arbitrary tag value?):
public class MyActivity extends Activity {
public static class A extends MyActivity {}
public static class B extends MyActivity {}
public static class C extends MyActivity {}
public static class D extends MyActivity {}
public static class E extends MyActivity {}
public static class F extends MyActivity {}
public static class G extends MyActivity {}
public static class H extends MyActivity {}
public static class I extends MyActivity {}
public static class J extends MyActivity {}
private final static List<Class<?>> SEQUENCE = Arrays.asList(new Class<?>[] {
A.class, B.class, C.class, D.class, E.class,
F.class, G.class, H.class, I.class, J.class,
});
private Intent getSequencedActivityIntent(int step) {
final int current = SEQUENCE.indexOf(this.getClass());
if (current == -1) new Intent(this, SEQUENCE.get(0));
final int target = current + step;
if (target < 0 || target > SEQUENCE.size() - 1) return null;
return new Intent(this, SEQUENCE.get(target));
}
// the rest of your activity code
}
Don't forget to add their entries to your AndroidManifest.xml file too (singleTop is optional - it will prevent the Activity instance in the stack to be created again when brought back to the front):
<activity android:name=".MyActivity$A" android:launchMode="singleTop" />
<activity android:name=".MyActivity$B" android:launchMode="singleTop" />
<activity android:name=".MyActivity$C" android:launchMode="singleTop" />
<activity android:name=".MyActivity$D" android:launchMode="singleTop" />
<activity android:name=".MyActivity$E" android:launchMode="singleTop" />
<activity android:name=".MyActivity$F" android:launchMode="singleTop" />
<activity android:name=".MyActivity$G" android:launchMode="singleTop" />
<activity android:name=".MyActivity$H" android:launchMode="singleTop" />
<activity android:name=".MyActivity$I" android:launchMode="singleTop" />
<activity android:name=".MyActivity$J" android:launchMode="singleTop" />
Now, whenever you need to start a new "top" instance of your Activity, you can do something like:
final Intent intent = getSequencedActivityIntent(+1);
if (intent == null) return;
intent.putExtra("dataset", dataSet);
startActivity(intent);
And when you need to go back to one of the instance in the backstack you can do:
final Intent intent = getSequencedActivityIntent(- stepBack);
if (intent == null) return;
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
You can index your activities without having to worry about handling all the chain of onActivityResults using a super Activity that you extend in all your activities
Here is an implementation (I did not test it) but if you extend this SuperActivity in all your Activities, you can call fallBackToActivity( int ) to any activity using its index and each activity now has a getIndex(). You can use it to fallback to a relative index like getIndex()-3
package sherif.android.stack.overflow;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class SuperActivity extends Activity {
private static String EXTRA_INDEX = "SUPER_INDEX";
private static int RESULT_FALLBACK = 0x123456;
private int index;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(getIntent()!=null) {
index = getIntent().getIntExtra(EXTRA_INDEX, -1) + 1;
}
}
protected final int getIndex() {
return index;
}
protected final void fallBackToActivity(int index) {
Intent intent = new Intent();
intent.putExtra(EXTRA_INDEX, index);
setResult(RESULT_FALLBACK, intent);
finish();
}
#Override
public void startActivityForResult(Intent intent, int requestCode) {
intent.putExtra(EXTRA_INDEX, getIndex());
super.startActivityForResult(intent, requestCode);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_FALLBACK) {
if(data.getIntExtra(EXTRA_INDEX, -1)!=getIndex()) {
setResult(RESULT_FALLBACK, data);
finish();
}
}
}
}
You can just keep a condition in your statement
if user chooses this item pass intent to B class
and if user chooses that item pass intent to C class
Add extra to your intent that will point the activity what to do.
For example
intent.putExtra("STATE", 1);
And get this value in onCreate of your activity.
getIntent().getExtras()
As I understand Android only targets the class of activity and not a particular instance of activity. So, I think you won't be able to do what you want by just adding some flags on Intent.
I think the easiest approach would be to implement it on your own by something like this
a) Create some singleton and have a member in it which points to instance of activity to which you want to return (as example activity B). Probably, you will have to store all activities in some list to be able to get instance of some previously launched activity.
b) Override onResume for all activities and in it do following check:
if (SomeSingleton.getTargetActivity() != null && this != SomeSingleton.getTargetActivity())
finish();
else
SomeSingleton.setTargetActivity(null);
c) As soon as you need to return from E do
SomeSingleton.setTargetActivity(B);
finish();
This will close top activity (which is E) and call onResume on activity D. It will check whether it's target. If it's not then it will close it and system will call onResume on activity C and so on.
If you want to use an abnormal approach, or some tricky once, you will have more problems later. I think you can
Define a abstract/non-abstract subclass of Activity and define everything you want. If other classes are exactly the same as the above class, so just subclass from it and do nothing more. But if the classes ( Activities ) may different from each other, you can provide abstract/non-abstract methods to define additional abilities.
So
You write a reusable codes for all activities,
You act normal so you will get good result
You can control everything specialized in your activites
You can control stack using manifest file
and more
for detailed information see below codes:
Parent Activity:
public abstract class AbstractActivity extends Activity {
AbstractActivity currentActivity;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
currentActivity = this;
someProtectedMethod();
commonMethod();
// etc...
/* event handling */
Button btn_first = (Button) findViewById(R.id.btn_first);
Button btn_second = (Button) findViewById(R.id.btn_second);
btn_first.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(currentActivity, FirstActivity.class);
currentActivity.startActivity(intent);
}
});
btn_second.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(currentActivity, SecondActivity.class);
currentActivity.startActivity(intent);
}
});
}
/** you must override it, so you can control specified things safe */
protected abstract void someProtectedMethod();
protected void commonMethod() {
Log.i("LOG", "Hello From " + getClass().getName());
}
#Override
protected void onResume() {
super.onResume();
//some statement that work in all activities to
Log.i("LOG", "On Resume: " + getClass().getName());
}
}
First Activity:
public class FirstActivity extends AbstractActivity {
#Override
protected void someProtectedMethod() {
Log.i("LOG", "Special Action From First Activity");
}
}
Second Activity:
public class SecondActivity extends AbstractActivity {
#Override
protected void someProtectedMethod() {
Log.i("LOG", "Special Action From Second Activity");
}
}
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<Button
android:id="#+id/btn_first"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:text="Open First Activity" />
<Button
android:id="#+id/btn_second"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:text="Open Second Activity" />
</LinearLayout>
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activity_control"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".FirstActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SecondActivity"
android:label="#string/app_name" >
</activity>
</application>
</manifest>
The best and the easiest solution (so far) will be use Fragments and FragmentManager. Then tag each Fragment and use FragmentManager. Using only Activity can be very difficult to have almost the same result.

Android: dynamically choosing a launch activity doesn't always work

I've read a few articles here (and other places) that describe how to dynamically choose which activity to show when launching an app. Below is my code:
AndroidManifest.xml
<activity android:name=".StartupActivity"
android:theme="#android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
StartupActivity.java
public class StartupActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Intent intent;
if (RandomClass.getSomeStaticBoolean())
{
intent = new Intent(this, ActivityOften.class);
}
else
{
intent = new Intent(this, ActivityRare.class);
}
startActivity(intent);
finish();
}
}
Both ActivityOften and ActivityRare are declared in the manifest (without the launcher category of course) and extend ListActivity and Activity respectively. 99% of the time the 1st activity to get shown is ActivityOften based on RandomClass.getSomeStaticBoolean().
So launching my app from the icon for the 1st time I break inside the StartupActivity.onCreate. The choice is properly made. But then any subsequent attempts to launch the app (from a shortcut or the apps menu) show the ActivityOften again. No further breaks occur inside the StartupActivity class. Despite the fact that I know that RandomClass.getSomeStaticBoolean() has changed value and that ActivityRare should appear, the 1st activity keeps popping up.
Any ideas?
Thanks, Merci, Gracias, Danke, Grazie!
Sean
It is happening because your application activity is loaded from the history stack.
Set android:noHistory=true in the manifest for both ActivityOften and ActivityRare. That should solve your problem.
Just as a suggestion, you could just have one activity instead of three by choosing the content View dynamically. i.e.
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (RandomClass.getSomeStaticBoolean())
{
setContentView(R.layout.Often);
// Set up often ....
}
else
{
setContentView(R.layout.Rare);
// Set up rare ....
}
}
This would mean that you would have to write setup code both views in on activity, which can get a bit messy.

Categories

Resources