[CLOSED]
I have a two activity called A and B.
ActivityA (Launcher) shows list data (RecyclerView) and data is downloaded from the WebService.
ActivityB shows list item detail when i press list item.
The problem is:
When i press back button from ActivityB, ActivityA's onCreate() method working and re-downloading already downloaded datas like relaunching app. I don't want to re-download or re-call onCreate() method.
I tested two device has pre Marshmallow OS:
Samsung Galaxy S5 (OS version 4.4.4)
Sony Xperia (OS version 4.1.2)
and the result is:
When i press back button from ActivityB, ActivityA is not re-downloading. ActivityA already shows lastly positioned list. I want this in Marshmallow.
My Marshmallow device is Nexus 5 (OS version 6.0.1)
How can i solve this problem?
[SOME CODE BELOW]
// This is ActivityA
public class MainView extends AppCompatActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_view);
...
if (NetworkChecker.isNetAvailable(context)) {
mDataSet = update(); // this method calling WebService
} else {
mDataSet = Database.getDatas(); // this method reading datas from sqlite.
}
createListView(mDataSet);
...
}
private void createListView(List<NamecardEntity> mDataSet) {
mRecyclerView = (RecyclerView) findViewById(R.id.itemsRecyclerView);
mRecyclerView.setHasFixedSize(true);
RecyclerView.ItemDecoration itemDecoration =
new DividerItemDecorator(getContext(), LinearLayoutManager.VERTICAL);
mRecyclerView.addItemDecoration(itemDecoration);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getContext());
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new ListAdapter(getActivity(), getActivity().getApplicationContext(), mDataSet);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.addOnScrollListener(onScrollListener);
}
...
}
public class ListAdapter extends RecyclerSwipeAdapter<ListAdapter.SimpleViewHolder> {
...
#Override
public void onBindViewHolder(final SimpleViewHolder viewHolder, final int position) {
Entity item = mDataset.get(position);
...
viewHolder.front.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
activity.startActivity(new Intent(mContext, DetailView.class));
}
});
...
}
}
// This is ActivityB
public class DetailView extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.detail_view);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setTitle("");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
...
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_activity_filter, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
case R.id.action_filter:
// TODO filter
return true;
}
return true;
}
}
// In Manifest.xml
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainView"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".DetailView"
android:screenOrientation="portrait"
android:theme="#style/AppTheme.NoActionBar" />
</application>
[EDITED] I FOUND REASEN
I put some Log into ActivityA Lifecycle, and the result is:
When i run the application on the Xperia. (pre Marshmallow test result):
ActivityA state log is:
onCreate
onStart
onResume
then select list item and starting ActivityB
ActivityA state log is:
onPause
onStop
then i press back button from ActivityB and navigate back to A
ActivityA state log is:
onRestart
onStart
onResume
When i run the application on the Nexus 5. (Marshmallow test result):
ActivityA state log is:
onCreate
onStart
onResume
then select list item and starting ActivityB
ActivityA state log is:
onPause
onStop
onDestroy <- this is the reason, why this method called in Marshmallow
then i press back button from ActivityB and navigate back to A
ActivityA state log is:
onCreate <- onCreate() called, cause onDestory() called already, this is the problem
onStart
onResume
ACTIVITY LIFECYCLE IS WORKS DIFFERENT IN MARSHMALLOW, WHY? THAT IS THE WHY I GETTING PROBLEM. PLS HELP
Android Marshmallow is working fine. You have this problem because you didn't correctly adhere to the activity lifecycle.
Note that it is up to Android to destroy the Activity or not. You have to take account on that. Turns out in your case on previous Android versions your Activity was destroyed, so when you navigated back it passed through onCreate(). Now it does not destroy it, so it doesn't go through onCreate().
The correct way to refresh data is to always do it on the onResume() method to make sure it will be called no matter if Android destroys the Activity or not.
Related
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.
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.
I am setting Activity Theme to Theme.NoDisplay but When it open but on press back button Activity not closing/destroying. It should close/destroy on back press.
Guys help me why this is so and any solution to resolve this.
public class MainActivity extends Activity {
// Tag of the Activity
private static String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DatabaseManager.init(this);
NFCIItem mNFCItem = new NFCIItem();
mNFCItem.setSerialNumber(1);
DatabaseManager.getInstance().addWishList(mNFCItem);
final List<NFCIItem> wishLists = DatabaseManager.getInstance().getAllNFCSerialNumber();
Log.v(TAG, wishLists.toString());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
AndroidManifest.xml
<activity
android:name="com.example.appdemo.MainActivity"
android:label="#string/app_name"
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>
I imagine it is closing but you see no evidence of this because it is 'NoDisplay'. An Activity using this theme has no visible UI (hence it is not logical for such an Activity to process UI events) and should not be kept alive. See this question for example:
how to completely get rid of an activity's GUI (avoid a black screen)
If you do want this Activity's layout to be visible and to handle events, you should use a different theme. If on the otherhand this is an invisible Activity that just does some background processing, call finish() in onCreate to close it when that processing is done.
You can override the back button event to manually close the activity
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
YourActivity.this.finish();
return true;
}
}
You can override the back button to launch the main activity and instantly close it without animation. This will appear as a single action to the user.
#Override
public void onBackPressed() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
overridePendingTransition(R.anim.slide_in_right,
R.anim.slide_out_right);
}
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.
My application gets killed each time that it comes back from the screen-off-state. I fetch all the information that my app does, but I can't find out why it calls onDestroy. It's the first time I'm seeing this behavior in my applications.
My main activity extends tabActivity because it contains a tabhost. I've read that it has to extend it or it will FC. I'm not sure if my issue is related to this?! Oh and it implements Observer but this should be no problem.
Here are the logs:
07-21 09:57:53.247: VERBOSE/###(13180): onResume
07-21 09:57:53.267: VERBOSE/###(13180): onPause
07-21 09:57:59.967: VERBOSE/###(13180): onResume
07-21 09:58:00.597: VERBOSE/###(13180): onPause
07-21 09:58:00.597: VERBOSE/###(13180): onDestroy
07-21 09:58:00.637: VERBOSE/###(13180): onCreate
The crazy thing is that it calls the onDestroy the most times after the screen goes on again, and sometimes it has enough time to do this before the screen goes off. But after it goes on again it does the same again...
I hope that someone has a tip for me or any information on how to resolve this issue.
I'm not sure if this is important, but I use the android 2.1-update1 sdk for my application.
EDIT:
The application gets tested on a real Android Device.
Here is some basic code with all unnecessary lines and information removed:
package;
imports;
public class WebLabActivity extends TabActivity implements Observer{
#declerations
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v("###", "onCreate");
setContentView(R.layout.main);
# initialize some basic things
}
#Override
public void onResume() {
super.onResume();
Log.v("###", "onResume");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.v("###", "onDestroy");
}
#Override
public void onRestart() {
Log.v("###", "onRestart");
super.onRestart();
}
#Override
public void onPause() {
Log.v("###", "onPause");
super.onPause();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
Log.v("###", "onConfigurationChanged");
super.onConfigurationChanged(newConfig);
}
#Override
public void update(Observable observable, Object data) {
Log.v("###", "notifyManager.getWho() + " made an Update");
}
private void initializeSidebarTabhost() {
TabSpec 1 = tabHost.newTabSpec("1");
TabSpec 2 = tabHost.newTabSpec("2");
TabSpec 3 = tabHost.newTabSpec("3");
TabSpec 4 = tabHost.newTabSpec("4");
1.setIndicator("###");
2.setIndicator("###");
3.setIndicator("###");
4.setIndicator("###");
addIntents
tabHost.addTab(1); //0
tabHost.addTab(2); //1
tabHost.addTab(3); //2
tabHost.addTab(4); //3
tabHost.getTabWidget().setCurrentTab(2);
}
}
EDIT2:
Ok, I've tested my application without initializing anything, then with only extending activity, or without implementing observer, but my changes had no effect. Every time I set my phone to sleep, then wake it up, onDestroy() get's called?!
EDIT3:
Ok, I found out something interesting.
First here's my AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tundem.###"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="7" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".###" android:label="#string/app_name" android:screenOrientation="landscape" android:theme="#android:style/Theme.Light.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
As soon as I remove the screenOrientation="landscape", the application won't be destroyed each time that I wake up my device. I tried it more than 10 times but no more calls to onDestroy()
So I think that I will have to set this in code?! Any tips or pieces of code?
If you want to stop the destroy/create issue that is the default in android because of an orientation change and lock in one orientation then you need to add code and xml
In your activites code (notes about the xml)
// When an android device changes orientation usually the activity is destroyed and recreated with a new
// orientation layout. This method, along with a setting in the the manifest for this activity
// tells the OS to let us handle it instead.
//
// This increases performance and gives us greater control over activity creation and destruction for simple
// activities.
//
// Must place this into the AndroidManifest.xml file for this activity in order for this to work properly
// android:configChanges="keyboardHidden|orientation"
// optionally
// android:screenOrientation="landscape"
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
}
I had same issue. From ActivityA I called ActivityB. When I closed ActivityB, I expected ActivityA to be shown but it wasn't - it was destroyed. This issues was caused by following attributes of ActivityA in AndroidManifest.xml:
android:excludeFromRecents="true"
android:noHistory="true"
Because of them ActivityA was destroyed after ActivityB was started.
mikepenz,in your case if you realy need a android:setorientation = "landscape" means ,you dont need to remove it, just add these set of attribute android:configchanges = "orientation|Screensize" this wont destroy your activity... hope this helps you.