I have two Activities: Activity A and Activity B. Activity A consists of a custom ListView and a custom ListView Adapter. When chosing an item of the ListView Activity B appears and displays the user relevant information. When pressing the back/return button Activity B calls finish().
I do not intend to create as many activites as items the ListView has. I want Activity B to be able to change it's layout id. So far my application crashes on every attempt I make to turn the setContentView method variable.
relevant code from Activity A :
// code
if (position == 0 && imaginaryInt == 3) // item position in the ListView
{
ActivityB b = new ActivityB();
b.setLayoutID(R.layout.main_c); // this line causes the crash
Intent intent = new Intent(view.getContext(),b.getClass());
startActivityForResult(intent, 0);
if (position == 1 && imaginaryInt == 3 ) {...}
Acivity B :
public class ActivityB extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_b);
}
#Override
public void onBackPressed() {
Intent intent = new Intent();
setResult(RESULT_OK,intent);
super.onBackPressed();
}
}
Overriding setContentView() in ActivityB and changing params to R.layout.main_c did work!
Unfortunately I ran out of ideas how to manage to change the the layout of ActivityB from ActivityA.
Any help is highly appreciated.
EDIT: ---SOLUTION---
To be able to change the layout od ActivityB from ActivityA I gave each ListView click a static unique id. In ActivityB the layout is simply changed with the setContentView method and if the row with the unqiue id was clicked.
You can pass the information you want through the Intent used to start the Activity. For example:
if (position == 0 && imaginaryInt == 3)
{
Intent intent = new Intent(view.getContext(),ActivityB.class);
intent.putExtra("layout_id", R.layout.main_c); // pass the id as an int extra
startActivityForResult(intent, 0);
}
And then, in your ActivityB class:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int layoutId = getIntent().getIntExtra("layout_id", R.layout.default_value);
setContentView(layoutId);
}
You cannot operate on layout of ActivityB from ActivityA.
on this line:
b.setLayoutID(R.layout.main_c);
b is NOT EXISTENT at the time you are trying to call. It will exist only after startActivity.
And even then you, as I remember, cannot do that from activity A - activity B is not synchronized with A.
Use other means: for example create service to signal ActivityB to change layout.
Related
I have two Activities A and B.
Activity A has a Tablayout with some Tabs. When I navigate from A to B I use this:
Intent intent = new Intent(A, B.class);
A.startActivity(intent);
When I now navigate back from B to A I have a question:
1) When using Android's back button, the selected tab / scrolling position from A was remembered
2) When using an Intent or NavUtils.navigateUpFromSameTask(this); then the selected tab and scroll Position is NOT remembered but set to initial value
Can someone explain me what is going on here?
1) when navigation from activity A to B, the android system does not destroy activity A, but takes it to the back stack and adds B to the foreground. thats why when you press the back button or call onBackPressed() from the java code activity B is destroyed and A is set to the foreground. here is an example from the docs : Understand Tasks and Back stack
2) when using an intent/navigateUpFromSameTask activity A is recreated and set to the foreground and B is set to the background, it's like adding another activity A to the stack so it will be A,B,A but if you press the back btn then you will be back to B and then A.
if you want to keep the scroll position and other data in activity A you call the onBackPressed in B or use the onSaveInstanceState to save the data and use it in the onCreate .
here is an example of saved instance:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putString("VariableName", variableData);
savedInstanceState.putString("VariableName", variableData);
savedInstanceState.putString("VariableName", variableData);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.penguin_main);
if(savedInstanceState!=null){
bookData = (String) savedInstanceState.getSerializable("VariableName");
bookData = (String) savedInstanceState.getSerializable("VariableName");
bookData = (String) savedInstanceState.getSerializable("VariableName");
}
}
You can set the current scroll position and tab position in activity A's on overriding onSaveInstance(Bundle savedInstanceState) method. When return to activity you can get onRestoreInstanceState(Bundle savedInstanceState) to restore it.
Hope it helps :)
Because NavUtils.navigateUpFromSameTask() just calls startActivity() and if android:launchMode="standard" the activity will be instantiated and created again and that is why can not remember the previous selected tab. To solve this issue you can override onNavigateUp() and inside that setCurrentItem(index) the index of tab you want to be displayed.
#Override
public boolean onNavigateUp() {
myViewPager.setCurrentItem(position, true);
return true;
}
Edit
You can use another solution to solve the problem by setting android:launchMode="singleTop" on activity but this solution may not applicable in all the application.
When you start an Activity, the first page will be opened! But when the back button is pressed, it navigates between the saved state of the activityTo simulate the back button pressed, you can try this:
#Override
public void onBackPressed() {
finish(); //your choice, thought not needed as super.onBackPressed(); is called if nothing is assigned here
}
or on toolbar back button clicked click:
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
I have two Activities: MainActivity and OtherActivity. A fragment in MainActivity launches the OtherActivity, but when I press the back button at the top, it returns me to the MainActivity instead of the fragment that launched the OtherActivity.
The end result is the enduser is sent back to the main screen instead of the fragment that they were using.
This is my manifest. I have set MainActivity to be the parent of OtherActivity:
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".OtherActivity"
android:parentActivityName="com.example.test.MainActivity" >
</activity>
In MainActivity, when a user clicks on a button, it loads a List fragment:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ...
button.findViewById(R.id.events).setOnClickListener(new View.OnClickListener() {
Fragment ef = new MyItemsFragment();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.content, ef, "my_fragment");
fragmentTransaction.commit();
});
}
public void callOtherActivity() {
Intent i = new Intent(this, OtherActivity.class);
this.startActivity(i);
}
When an item is clicked in the List Fragment, it launches OtherActivity. A lot of the code for this was auto-generated by android studio. I have changed some of it. In MyItemsRecyclerViewAdapter:
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mItem = mValues.get(position);
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (null != mListener) {
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mListener.onEventFragmentInteraction(holder.mItem);
MainActivity ma = (MainActivity) holder.mView.getContext();
ma.callOtherActivity();
}
}
});
}
Notice it calls ma.callOtherActivity(), which is defined in MainActivity and will launch OtherActivity when an item is clicked in the list fragment.
This is OtherActivity:
public class OtherActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other);
}
}
Now, when I click on the back arrow button in OtherActivity, the app will just show MainActivity, and not the List fragment that the user last saw.
How can I make sure that on return from OtherActivity, the user will see the list fragment again for better user experience?
EDIT: There seems to be confusion about the 'back' button. Maybe they are the same, but I am talking about the one when switching Activities. It is not the back button used to exit the application. See image
When you start a new activity, the existing one is stacked so you can retrieve it later such as when you press the Back key.
On pressing the Back key, the Activity is restarted. This is the important part. It is not just brought back exactly as it was when it was last used. This means that you as the developer must take care to restore the Activity back to the state that you want it to be in. Any fragments will already be in the correct state but you must take care to not overwrite that state when your Activity restarts.
In your case, I suspect that your MainActivity code is indiscriminately re-initialising your fragments instead of checking whether fragments already exist for that particular activity before conditionally initialising them only if they don't.
It is difficult to say for sure as you do not include any of that code in your question. Check the code that displays the fragments in your MainActivity. Before you display them, are you checking whether there are already fragments visible? If not, you should be.
For example, the code below in an Activity, first checks whether a fragment is already displayed before it adds a new one. Essentially, the first time this is run, there will be no Fragments and therefore existing will be null and a new Fragment will be created and displayed.
After you have started a new OtherActivity etc and then returned to this activity with the Back key, existing will no longer be null as the Fragment system will have restored any existing fragments back into your container. Therefore we actually just do nothing.
#Override
protected void onCreate(Bundle b) {
super.onCreate(b);
Fragment existing = getSupportFragmentManager().findFragmentById(R.id.content);
if (existing == null) {
Fragment newFragment = new MyFragment();
getSupportFragmentManager().beginTransaction()
.replace(R.id.content, newFragment)
.commit();
}
}
Hope this is clear.
Just delete this line fragmentTransaction.addToBackStack(null);
you can use getSupportFragmentManager().getBackStackEntryCount(); method in MainActivity's onBackPressed Method.
OnClick bottom System back button.
follow below method.
#Override
public void onBackPressed() {
int backstack = getSupportFragmentManager().getBackStackEntryCount();
if (backstack > 0) {
getSupportFragmentManager().popBackStack();
} else {
super.onBackPressed();
System.exit(0);
}}
In fragment, press the back button at the top.
try this,
in onCreate method or onCreateView method of Fragment call this default method
setHasOptionsMenu(true);
and then override below method:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
getFragmentManager().popBackStack();
break;
}
return super.onOptionsItemSelected(item);
}
You can use Activity for result for this start Other Activity and as soon as you want to finish OtherActivity just do setResult, MainActivity would receive this result and there do the following
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
}
The code would go like this in MainActivity
public void callOtherActivity() {
Intent i = new Intent(this, OtherActivity.class);
startActivityForResult(i, 1);
}
and in OtherActivity's onBackPress call below method.
Intent returnIntent = new Intent();
returnIntent.putExtra("result",result);
setResult(Activity.RESULT_OK,returnIntent);
finish();
and now in MainActivity onActivityresult
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
}
}
}
I might be late but in my case error was coming because of the LoadFragment Method in OnStart method of MainActivity
I have an Activity with a ListView (ItemsActivity) which its contents come from a JSON API. When I press in one item in the ListView it loads another Activity with the details information (DetailActivity) . The problem is, when I press the Back Button, ItemsActivity reload the ListView again.
I don't know where I can find more information about this. I came from iOS where the previous screen is not reload every time.
I want to keep the ListView data between activities. I tested to call loadListItems() method from onResume() but same result.
Here is and brief sample of my code. Any help and suggestions will be really appreciated.
/* ItemsActivity.java */
public class ItemsActivity extends AppCompatActivity {
private ListView listItemView;
private Movie[] movies;
private ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler);
listItemView = (ListView) findViewById(R.id.listItemView);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
loadListItems();
}
private void loadListItems(){
// Http call
...
// Iterate JSON and saving to movies array
...
progressBar.setVisibility(INVISIBLE);
ListAdapter adapter = new ListAdapter(ItemsActivity.this, movies);
listItemView.setAdapter(adapter);
}
/* Adapter Class */
#Override
public void onClick(View v) {
Intent i = new Intent(this, DetailActivity.class);
i.putExtra("item_id", 1);
startActivity(i);
}
}
I just tested with a new Project with 2 Activities, ActivityOne and ActivityTwo. ActivityOne have a button, when a pressed its load ActivityTwo and when I press the back button, in ActivityOne the method onCreate() is called again.
You mentioned that "I tested to call loadListItems() method from onResume() but same result." This onResume() code is culprit.
OnResume() will get called whenever your activity gets focus again. If you are calling loadListItems() in onResume() then it will get called everytime you come back from your second activity to this activity.
http://developer.android.com/reference/android/app/Activity.html#onResume()
A solution is to use StartActivityForResult and not StartActivity. Then in the second activity, override the onBackPressed method and finish() the second activity within this method. Override the onActivityResult method in your first activity and this activity will be called and not the onCreate method and the ListView will not be reloaded.
The problem was only when I pressed the back button from Action Bar and I fix it with onOptionsItemSelected method.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
My Custom adapter class -
public class CAdapter extends BaseAdapter {
private Context context;
private final String[] values;
public int[] clicked;
public int[] allVisited;...
if clicked is one - the item is yellow - indicating this item in gridview has been clicked at least once
if allVisited is one - the item is red - indicating a condition linked to this item in the subactivity which is triggered on item click.
the item is an imageview + textview whose background color is being set in onitemclick in gridview activity oncreate or getview in custom adapter class.
How to keep track of these values between the activation and deactivation of the activity.
Do we need to do this thru passing values between activities in databundles and even then it is not obvious.
Also is it better to use the back button of the device here or a button click from the activity to go back to another activity.
Apart from this - is it possible to stop running an app completely when a custom button presented for this (like Exit) is clicked in the main activity, and how?
Please help. I am new in Android. Thanks, Sanjay.
First off to exit the Main activity just call the finish method.
This method closes the activity it is called on, so you can also use it for closing secondary activities. It basically simulates the back key.
To keep the background colors just open the activities from the main activity and close them with the finish method when you're done with them. It should restore the last layout on returning to the main activity.
Start your activity like this:
startActivityForResult(activity, REQUESTED_RETURN_RESULT);
In your main activity you override the OnActivityResult method:
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
switch (requestCode)
{
case REQUESTED_RETURN_RESULT:
handleStuff(data);
break;
case SOME_OTHER_REQUEST:
handleSomethingElse(data);
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
In your secondary activity change the finish() method to include:
Intent _result = new Intent();
_result.setData(DATA_TO_RETURN_TO_THE_MAIN_ACTIVITY);
setResult(Activity.RESULT_OK, _result);
finish();
you could also check if it is the correct data by returning and checking the resultCode
I have an Activity named A,
in this, a ListView and one button are there.After clicking on this button,List View is shown and from this list view, by clicking on a its items, I can move to Activity B.
Now the problem is this when I come back from Activity B -> Activity A then, I see the Button only not the list view.
because I am calling intent of Activity A..
Code
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
Intent i;
i = new Intent(B.this, A.class);
startActivity(i);
finish();
super.onBackPressed();
}
In Activity B, I have the above implementation and i am using finish() in On Pause() condition also.
I want to see the List View with buttons.
Do i need to call whole code again to show the ListView or is there any other way to resolve this problem??
Is there any way to save the previous activity view?
Its because you are finishing Activity A before switching to Activity B. If you want your ListView as it is then do not finish Activity A and then try. If still your data does not visible then bind your listview again in onResume() of Activity A.
//removed finish().
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
Intent i = new Intent(B.this, A.class);
startActivity(i);
super.onBackPressed();
}
You are creating your activity aagain since u hv called the finish
method and when u go back it calls onCreate rather it should call
onResume method of lifecycle.
Just do one thing.rmove finish() from your code
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
Intent i;
i = new Intent(B.this, A.class);
startActivity(i);
super.onBackPressed();
}
onResume called when activity start or when you return from another activity as per life cycle of Activity, its better to keep your code inside onResume, which will refill your listview with data.
SO when you called activity B from A (in Activity A fill your listview inside onResume method) and when you press back, its again callon onResume and fill your listview.
Instead# doing code inside onBackPressed of activity B.