I try to develop a first app that download images from the net and show them in a gridview. The gridview is a fragment of a main Activity. The download process is made with an AsyncTask in the onCreate Function. In order not to download again the images while changing orientation, i set the android:configChanges="orientation|screenSize"
in the Android Manifest. Then the onCreate function is only call once and everything's good ... except that i've got to make a few changes in the layout for the gridview fragment in landscape mode. So i created 2 layout sheets : fragment_library.xml
and fragment_library_land.xml
in the layout/ folder. To make these changes work, i tryed to change the layout of the library fragment manually by using the onConfigurationChanged function. At runtime, the program evaluate the function and pass in the good case (portrait or landscape) but the layout used is still the one for portrait mode : fragment_library.xml
...
public class LibraryFragment extends Fragment {
public GridView gridview;
private Boolean isImageAdapterPopulated = false;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
GetLibraryTask getLibraryTask = new GetLibraryTask(this);
getLibraryTask.execute(Config.URL + "action=getLibrary");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null)
return null;
// gridview
View V = inflater.inflate(R.layout.fragment_library, container, false);
gridview = (GridView)V.findViewById(R.id.gridview);
if(this.isImageAdapterPopulated)
this.setGridAdapter();
return V;
}
@Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService( Context.LAYOUT_INFLATER_SERVICE );
inflater.inflate(R.layout.fragment_library_land, null);
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService( Context.LAYOUT_INFLATER_SERVICE );
inflater.inflate(R.layout.fragment_library, null);
}
}
public void setGridAdapter(){
this.isImageAdapterPopulated = true;
gridview.setAdapter(new ImageAdapter(getActivity()));
}
// ...
}
fragment_library.xml
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gridview"
android:cacheColorHint="@android:color/transparent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="200dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="20dp"
android:stretchMode="columnWidth"
android:gravity="bottom"
/>
fragment_library_land.xml
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gridview"
android:cacheColorHint="@android:color/transparent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="400dp"
android:numColumns="2"
android:verticalSpacing="50dp"
android:horizontalSpacing="50dp"
android:stretchMode="columnWidth"
android:gravity="bottom"
/>
Thanks for help :)
Use the following code line in the fragment where you want a specific (in this case portrait) orientation. getActivity(). setRequestedOrientation( ActivityInfo. SCREEN_ORIENTATION_PORTRAIT);
If you want to manually handle orientation changes in your app you must declare the "orientation" , "screenSize" , and "screenLayout" values in the android:configChanges attributes. You can declare multiple configuration values in the attribute by separating them with a pipe | character.
When you rotate your device and the screen changes orientation, Android usually destroys your application's existing Activities and Fragments and recreates them. Android does this so that your application can reload resources based on the new configuration.
First, add android:configChanges="orientation|screenSize|keyboard|keyboardHidden" so the app handles the config changes instead of android. Make two different layout for landscape and portrait.
It is not possible. A Fragment cannot update it's layout dynamically. You do have some other options however.
1. Not a fan of this, but you may have a Fragment's layout with both the portrait and the horizontal views at the same time and show and hide.
fragment_library.xml:
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gridview_portrait"
android:cacheColorHint="@android:color/transparent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="200dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="20dp"
android:stretchMode="columnWidth"
android:gravity="bottom"
/>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gridview_landscape"
android:cacheColorHint="@android:color/transparent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="400dp"
android:numColumns="2"
android:verticalSpacing="50dp"
android:horizontalSpacing="50dp"
android:stretchMode="columnWidth"
android:gravity="bottom"
android:visible="gone"
/>
Then some private member variables:
private GridView mGridViewPortrait;
private GridView mGridViewLandscape;
Then in onConfigurationChanged(Configuration newConfig)
:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
mGridViewPortrait.setVisibility(View.VISIBLE);
mGridViewLandscape.setVisibility(View.GONE);
}
else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
mGridViewPortrait.setVisibility(View.GONE);
mGridViewLandscape.setVisibility(View.VISIBLE);
}
}
Some points: Note that i left out the code to refer the both GridViews. I also changed your GridView to private and also changed the name to mGridView*. Private to keep it "data-encapsulated" and "m" because it is a member of the class, just convention. I also changed the if-else clause because I wanted the portrait check to come first.
This way is the fastest and easiest, however it might become heavy for the system if you have big layouts so do not use this if you have many things. Preferably do not use this approach at all.
2. The proper way is to let the Andorid take care of the orientation and also move your XML to a right directory. This however will recreate your Fragment (if you do not set setRetainInstance(true);
which you will not in this case; this will make the Fragment not recreate it's layout (actually looking up the retain method it does not mention onCreateView
so you may try to set this to true aswell and try)).
Move your fragment_library_land.xml to the directory layout-land instead of layout and name it fragment_library.xml. Note the bold, it will have the same name but stay in different directories. This way Android will know and take the right layout based on the orientation.
If I have understood why you will not want to recreate the Fragment because onCreate(Bundle savedInstanceState)
will be called again (with setRetainInstance(true);
it will not and to as regard to what I wrote earlier you may give it a try) thus creating a new instance of GetLibraryTask
and download the images again. This could be prevented if you used a database to store the images and if you had a boolean value that kept track if you had downloaded the image or not. In GetLibraryTask
you would then pick out the images which are not downloaded, be it the first time the task is run or if the orientation changed. You would also require to put in a stop check in the library task in the download loop that before each item checks if you are supposed to download the image or if the fragment is no longer available and thus quit the task.
Now when you change orientation the Activity will recreate the LibraryFragment and depending on the orientation either layout or layout-land will be used.
Some side notes in your code:
public GridView gridview
would be private GridView mGridView
and private Boolean isImageAdapterPopulated
would be private boolean mIsImageAdapterPopulated
onConfigurationChanged(Configuration newConfig)
you inflate an XML and it returns a View but you are not doing anything with itI wish you good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With