I do have a very simple application with just a single CheckBox. I thought that when android does destroy my activity the state of this checkbox will be list. What actually happens is, that the checkbox keeps checked.
The onDestroy() is actually called (on rotation or when I switch to another app -> my emulator has this dev configuration).
So why does this work without using onRestoreInstanceState() and onSaveInstanceState()?
Android Target is 4.2 Jelly Bean.
Here my Activity:
public class CoffeeMixerActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_coffee_mixer);
}
protected void onDestroy() {
super.onDestroy();
Log.d("MyMessage", "Destroy my app");
}
}
Here my Layout file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".CoffeeMixerActivity" >
<CheckBox
android:id="#+id/checkBoxSprinkles"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sprinkles" />
</RelativeLayout>
Ok.. found the solution by myself:
Android CheckBox -- Restoring State After Screen Rotation
Description:
Every View does have the android:saveEnabled flag on true.. which means that when the View does have an ID the state is automatically saved when the view is freezed...
Here there attribute documentation:
http://developer.android.com/reference/android/R.attr.html#saveEnabled
Related
I have a simple activity named Test1.
This is the layout code.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/test"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:id="#+id/imageview1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:src="#drawable/load"
android:scaleType="fitXY" />
</RelativeLayout>
In my onDestory method, I release the mImageView resource and in Android profile, the memory of mImageView has really be recycled.
#Override
protected void onDestroy() {
super.onDestroy();
releaseImageViewResource(mImageView);
layout.removeView(mImageView);
mImageView.setVisibility(View.GONE);
mImageView.setImageDrawable(null);
mImageView = null;
}
But when I start other simple activity, the memory of mImageView cannot be recycled. Why and how to solve the problem?
To handle images, I suggest for you to use libraries like Glide or Picasso, they will handle everything for you. (memory leaks, caching, etc)
Not sure what you mean by "start other simple activity", but if you are going to another activity within the application, then your current activity (with the imageview) should be paused instead of destroyed. Either call finish() when you go to the other activity or just put that onDestroy() code in the onPause() method
I've made two XML files one for portrait mode and the other is for landscape
When i start the app it runs normally and after flipping the screen for the second time it crashes and gives this error:java.lang.IllegalStateException: Fragment has not been attached yet.
Eventhough the landscape xml file contains static fragments and the portriat one contains nothing(in order to add the fragments dinamically on further steps).Here is my XML File:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:name="com.example.alihaidar.fragmentlab.fragList"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:id="#+id/frag_list"
/>
<fragment
android:name="com.example.alihaidar.fragmentlab.fragContent"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="match_parent"
android:id="#+id/frag_content"
/>
</LinearLayout>
and this is mainActivity it contains nothing :
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
You need to make a validation to check if the Fragment is attached to its parent using isAdded() method:
if (!isAdded()){
return; //Not attached
}else{
//Attached!
}
isAdded() Return true if the fragment is currently added to its
activity.
Another option, define in your activity the property:
<activity
android:configChanges="orientation|keyboardHidden|screenSize">
to avoid the destruction of the parent activity when you rotate the device.
I have a list view that is populated through a string-array in the xml, not run time and I'm trying to set the background color of specific items in the list using:
listView.getChildAt(x).setBackgroundColor(Color.BLACK);
I need this to happen before it's visible, but it gives an error when I use it in onCreate() or onStart(), but works if I run it on a button press. I've tried searching for an answer but can't seem to find any event that happens late enough for it to work.
getView() would be the best place to do this, but you don't have access with the way you are doing this with android:entries=.... Instead, you can post a runnable to the message queue to change the color after layout occurs like the following:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.layout).post(new Runnable() {
#Override
public void run() {
findViewById(R.id.view).setBackgroundResource(android.R.color.holo_red_dark);
}
});
}
Here I have used a simple View for demonstration but the same technique should work for your ListView.
Here is the XML I used if you want to work with it:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<View
android:id="#+id/view"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#android:color/holo_blue_light" />
</LinearLayout>
Here's a link to post. The runnable kicks off before onStart(). So, if that's a requirement, then this way may not work for you.
I'm having issues with loading the PreferenceFragment in Android. At this point it's a really basic implementation, that I want to expand later on when it works.
The problem is that only the first preference is shown after navigating to the SettingsFragment.
I'm not getting any error, but logcat is showing me this:
W/PathParser: Points are too far apart 4.000000596046461
I googled on this, but without any useful solutions.
The code is the following:
MainActivity navigation through NavigationDrawer
navigate() is a generic function using the FragmentManager
case R.id.nav_settings:
navigate(new SettingsFragment(), "settingsFragment", false);
break;
SettingsFragment
public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
public SettingsFragment() { }
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
#Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { }
}
prefences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreference
android:key="switch_notifications"
android:title="Notifications"
android:summary="Receive notifications"
android:defaultValue="true" >
</SwitchPreference>
<CheckBoxPreference
android:key="switch_notifications2"
android:title="Notifications"
android:summary="Receive notifications"
android:defaultValue="true" >
</CheckBoxPreference>
</PreferenceScreen>
Screenshots
Left: Actual output | Right: Preview
Thanks in advance!
Niels
FOUND THE SOLUTION:
The NestedScrollView which contains my FrameLayout should have the setting android:fillViewport="true". Also the FrameLayout should have its height set to wrap_content.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/content_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="nmct.jaspernielsmichielhein.watchfriends.view.MainActivity"
tools:showIn="#layout/app_bar_main">
<android.support.design.widget.CoordinatorLayout
android:id="#+id/coordinator_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<android.support.v4.widget.NestedScrollView
android:id="#+id/frame_scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior" >
<FrameLayout
android:id="#+id/fragment_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior" >
</FrameLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
Sorry, this might not be an answer (not able to comment yet), more like an insight.
Just want to point out that it works as expected on my device (oneplus3) and also in the nexus 5 emulator seems to be showing correctly.
My guess: could it be that somehow the parent activity is limiting the output of the fragment? For example if I set a high enough paddingBottom on the parent, I get a similar result as in the picture on the left.
If not, it's probably some weird device specific bug. Maybe you could give more info about the device, screen size, android version etc.
I am using webview to create a basic web browser,
Currently I have one activity and multiple fragments :
-- Browser
-- something else
-- Something else
in Browser Fragment I have the webview :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".fragments.BrowserFragment">
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/webview_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true">
<include
android:id="#+id/button_layout"
layout="#layout/bottom_btn_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
<LinearLayout
android:id="#+id/web_page_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/button_layout"
android:orientation="vertical">
</LinearLayout>
<WebView
android:id="#+id/web_page"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/button_layout"/>
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
I am able to save the state of the webview on screen rotation , by using
#Override
public void onSaveInstanceState(Bundle outState) {
if(mWebView != null){
mWebView.saveState(outState);
}
super.onSaveInstanceState(outState);
}
and calling this OnActivityCreated :
mWebView = (WebView)getActivity().findViewById(R.id.web_page);
if (savedInstanceState != null){
mWebView.restoreState(savedInstanceState);
}else{
mWebView.loadUrl(makeUrl(url));
}
This works fine when screen rotates and activity is recreated.
But when I use navigation drawer and replace fragment in the same container and then try to come back to same fragment . The state of webview is lost.
I get the point that onSaveInstanceState() is not called when there is Fragment transaction. So I tried saving the webView state by calling onSaveInstanceState() from OnPause of the fragment. But in that case I get savedInstanceState as null in OnCreateView so I am not able to restore state.
I need to maintain state of multiple webviews and comeBack to them on click of a list.
I also tried saving webview, when onSave() is called in fragment, in a static HashMap in activity and try to assign it to webview of newFragment. But I get Blank screen in that case.
Could someone give me pointers how I can approach this.