I have a listFragment to display a list,
when we click on the list I want to display a Fragment with the details of the clicked element. I'm doing this with dynamic fragment.
My Problem is about the displaying of my detailsFragment. (cf picture).
I'm supposed to have the "designation" and other information .
I only have a part of my DetailsFragment XML.
However I checked the bundle with the debug mode and the communication is OK.
So Why is there a problem for the displaying of this fragment?
Principal Host Activity
public void onListItemClick(int id) {
F_Outils_details detail_frag = (F_Outils_details)
getFragmentManager().findFragmentById(R.id.listFragment2);
if (detail_frag != null) {
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
detail_frag.setDetails((int)id);
}
else {
// If the frag is not available, we're in the one-pane layout and must swap frags...
F_Outils_details detail_frag_new = new F_Outils_details();
Bundle args = new Bundle();
args.putInt("outil",(int) id);
detail_frag_new.setArguments(args);
FragmentTransaction transaction =getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container1, detail_frag_new);
transaction.addToBackStack(null);
transaction.commit();
}
DetailFragmentActivity
public class F_Outils_details extends Fragment {
ArrayList detail_outils=new ArrayList();
Outil outil;
TextView id_outil;
TextView designation;
TextView date_location;
View a;
ArrayList liste_outils;
int mCurrentPosition=-1;
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
return inflater.inflate(R.layout.f_outils_details, container, false);
}
#Override
public void onStart() {
super.onStart();
// During startup, check if there are arguments passed to the fragment.
// onStart is a good place to do this because the layout has already been
// applied to the fragment at this point so we can safely call the method
// below that sets the article text.
Bundle args = getArguments();
//si il y a pas d'arguments
if (args != null) {
setDetails(args.getInt("outil"));
} else if (mCurrentPosition != -1) {
System.out.println("mccurent posit");
// Set article based on saved instance state defined during onCreateView
setDetails(mCurrentPosition);
}
}
//methode qui va changer le texte !
public void setDetails(int id){
if(id==-1){
designation.setText("");
date_location.setText("");
}
else{
//on recupere l'outil
DB_Locoutils dbLocoutils=DB_Locoutils.getInst();
liste_outils=dbLocoutils.getOutils();
outil =(Outil) liste_outils.get((int) id);
System.out.println("**************"+outil.getDesignation());
//id_outil=(TextView) getView().findViewById(R.id.id_outil);
designation=(TextView) getActivity().findViewById(R.id.designation);
date_location=(TextView) getActivity().findViewById(R.id.date_location);
if(designation!=null){
System.out.println("DESIGNATION OK");
}
//id_outil.setText(outil.getIdOutil());
designation.setText(outil.getDesignation());
date_location.setText(outil.getDateLocation());
}
}
}
XML detailFragment
<?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="vertical" >
<TextView
android:id="#+id/titre"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textStyle="bold"
android:textSize="20dp"
android:text="Details" />
<TextView
android:id="#+id/id_outil"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:text="id outil"
/>
<TextView
android:id="#+id/designation"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:text="designation"
/>
<TextView
android:id="#+id/refClient"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:text="ref Client"
/>
<TextView
android:id="#+id/date_location"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:text="date location"
/>
I think the problem is that you have all your TextViews with the height attributes to match_parent. This indicates that your first item take all the parent height and the others stay behind. Try to use this layout instead:
<?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="vertical" >
<TextView
android:id="#+id/titre"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textStyle="bold"
android:textSize="20dp"
android:text="Details" />
<!-- as the item above, set the height to wrap_content -->
<TextView
android:id="#+id/id_outil"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="id outil"
/>
<TextView
android:id="#+id/designation"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="designation"
/>
<TextView
android:id="#+id/refClient"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="ref Client"
/>
<TextView
android:id="#+id/date_location"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="date location"
/>
</LinearLayout>
Hope this helps and you will have the expected result.
Related
This question already has answers here:
Fragment won't launch
(2 answers)
Closed 5 years ago.
I am pretty new to android development, so please don't flame me for stupid questions/mistakes!
I have a listview inside my activity, but i want to open up a fragment when a frame in the listview is clicked on. I have the onclick working, but it is not launching the new activity.
I'll include my code below.
This is the oncreate
protected void onCreate (Bundle savedInstanceState)
{
//Fragment fragment_blank2=new SomeFragment();
e = myBadData.getData();
super.onCreate(savedInstanceState);
setContentView(R.layout.event_list);
events=(ListView) findViewById(R.id.dayList);
ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,e);
events.setAdapter(adapter);
events.setOnItemClickListener(this);
}
this is the onclick
public void onItemClick(AdapterView<?> adapterView, View view, final int i, long l)
{
myBadData.setId(i);
Fragment fr = new event_description();
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.add(R.id.eventdescription, fr);
}
this is the XML of the fragment
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id = "#+id/eventdescription"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="layout.BlankFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="137dp"
android:text="#string/event_name"
android:textSize="26sp"
android:layout_gravity="top"
android:gravity="top|center"
android:paddingTop="10dp"
android:id="#+id/textView"
android:background="#android:color/holo_orange_light"
android:textColor="#android:color/black"
android:layout_weight="1.08" />
<TextView
android:text="#string/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/date"
android:layout_marginTop="#dimen/activity_top_margin"
android:layout_marginLeft="#dimen/activity_side_margin"
android:textSize="18sp"
android:drawableTint="#android:color/background_dark" />
<TextView
android:text="#string/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/time"
android:layout_marginTop="70dp"
android:layout_marginLeft="#dimen/activity_side_margin"
android:textSize="18sp" />
<TextView
android:text="#string/cost"
android:layout_gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/cost"
android:layout_marginTop="#dimen/activity_top_margin"
android:layout_marginRight="70dp"
android:textSize="18sp"/>
<TextView
android:text="#string/address"
android:layout_gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/address"
android:layout_marginTop="70dp"
android:layout_marginRight="60dp"
android:textSize="18sp" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="135dp"
android:layout_marginLeft="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:weightSum="1">
<TextView
android:id="#+id/tv_long"
android:paddingTop="10dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="#string/sample_text"
android:textSize="18sp"
android:layout_weight="1.08">
</TextView>
</LinearLayout>
</ScrollView>
<Button
android:text="#string/add_to_calendar"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:id="#+id/button2"
android:layout_gravity="center_horizontal"
android:layout_marginTop="95dp"/>
</FrameLayout>
here is the class of the fragment
public class event_description extends Fragment
{
#Nullable
//#Override
public View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate (R.layout.event_description, container, false);
Bundle args = getArguments();
String arg = args.getString(eventList.KEY_NAME);
//return super.(R.layout.event_description, container, false);
return view;
}
public View getView() {
return getView();
}
}
For Your Activity XML
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/my_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- TODO: Update blank fragment layout -->
<ListView
android:id="#+id/dayList"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
</FrameLayout>
And Pass Activity's Container in FramgmentTransaction
public void onItemClick(AdapterView<?> adapterView, View view, final int i, long l)
{
myBadData.setId(i);
Fragment fr = new event_description();
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
//Your Container of Activity
fragmentTransaction.add(R.id.my_frame, fr);
fragmentTransaction.commit();
}
and Don't forgot to commint it.
No need to use framgment's FrameLayout as a container..
I am making an activity which has a section for comments based on addresses inputed by the user.
The user will add a new comments section by pressing a button. This is a non fixed number of sections, so I have initially added this section as a fragment in the xml.
I have an onClick function that adds another fragment to the linearlayout.
My problem is that the new fragments always add to the top of the linearlayout , i.e. above the existing fragment/fragments (i.e. the new fragment will push all the other fragments down).
How can I add the new fragment so that it displays below the existing fragment?
Code in .java file:
public class SpecialReportAdden extends ActionBarActivity {
int numOfFragments;
LinearLayout addenHolder;
TextView report;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_special_report_adden);
numOfFragments=1;
Button addenSave = (Button)findViewById(R.id.btnAddendumSave);
Button addenAddComment = (Button)findViewById(R.id.btnAddendumAddComment);
addenHolder =(LinearLayout)findViewById(R.id.AddenLinLayHolder);
addenSave.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//this should save all comments including those added in dynamically produced fragments
//save database
Intent i = new Intent (SpecialReportAdden.this, MenuPage.class);
startActivity(i);
}
});
addenAddComment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("number of Fragments at start of OnClick", Integer.toString(numOfFragments));
Fragment newAddenFrag = addNewfragment(numOfFragments);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.AddenLinLayInnerHolder, newAddenFrag);
ft.addToBackStack(null);
ft.commit();
numOfFragments++;
Log.i("number of Fragments updated", Integer.toString(numOfFragments));
}
});
}
public Fragment addNewfragment(int number) {
AddendumLinInputFragment adden = new AddendumLinInputFragment();
TextView tx = (TextView) findViewById(R.id.txtVAddendumFragReportNum);
tx.setText("Report "+number+" :");
tx.setTextColor(Color.BLACK);
TextView address = (TextView)findViewById(R.id.txtVAddendumFragAddress);
address.setText("A new address");
address.setTextColor(Color.BLUE);
return adden;
}
xml file for the .java activity
<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:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context="com.example.danielt.pestcontrol.SpecialReportAdden"
android:id="#+id/RellayAddenComments">
<TextView
android:id="#+id/txtVAddendumTitle" android:text="Service Report Addendum" android:textStyle="bold" android:layout_centerHorizontal="true" android:elegantTextHeight="true" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"/>
<TextView
android:id="#+id/txtVAddendumTechName"
android:layout_below="#+id/txtVAddendumTitle"
android:layout_marginTop="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Technician Name: "
android:textSize="18sp"
/>
<TextView
android:id="#+id/txtVAddendumDate"
android:layout_below="#+id/txtVAddendumTechName"
android:layout_marginTop="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Date: "
android:textSize="18sp"
/>
<ScrollView
android:id="#+id/scrlVAddendum"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/txtVAddendumDate">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/AddenLinLayHolder"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/AddenLinLayInnerHolder"
android:orientation="vertical">
<fragment
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:name="com.example.danielt.pestcontrol.AddendumLinInputFragment"
android:id="#+id/addendum1CommentsFragment"
android:layout_below="#+id/txtVAddendum1Date"
android:layout_marginTop="24dp"
tools:layout="#layout/fragment_addendum_lin_input" />
</LinearLayout>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add another Addendum Comment"
android:id="#+id/btnAddendumAddComment"
android:layout_below="#+id/scrlVAddendum"
android:layout_centerHorizontal="true"
android:layout_marginTop="36dp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Save / Update Comments"
android:id="#+id/btnAddendumSave"
android:layout_below="#+id/btnAddendumAddComment"
android:layout_centerHorizontal="true"
android:layout_marginTop="44dp" />
</LinearLayout>
</ScrollView>
I havent added the fragment code but I will if someone wants to see it.
Thanks for any help.
You don't need fragment to hold only comment view. Just inflate new comment view and add it to the parent view.
LayoutInflater inflater = LayoutInflater.from(context);
View inflatedLayout= inflater.inflate(R.layout.yourLayout, container, false);
container.addView(inflatedLayout);
Where container is a view that hold all comments.
Regarding adding fragments, according to Fragments documentation:
If you're adding multiple fragments to the same container, then the
order in which you add them determines the order they appear in the
view hierarchy
Therefore if it's behave different, it could be related to OS version or bug :)
I am new to android developing and I am currently stumped at this situation.
Is there a way to change a particular child view of a fragment?
For example, I have a TextView and Button in a Fragment. Now after inflating this fragment and committing it, I would like to only change the text of the TextView based on the user input.
EDIT: The same layout is used to create multiple fragments. I would like to just change the TextView of a particular Fragment.
MainActivity Code:
public class MainActivity extends Activity {
Button bt;
EditText et;
LinearLayout ly;
String m;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt=(Button) findViewById(R.id.badd);
ly=(LinearLayout) findViewById(R.id.lay_ver);
et=(EditText) findViewById(R.id.etadd);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// multiple fragments are created
MyFragment f=new MyFragment();
FragmentManager fm=getFragmentManager();
FragmentTransaction t=fm.beginTransaction();
t.add(R.id.sv1, f, "hi");
t.commit();
et.setText("");
}
});
//would like to change the text of the textview of the fragment
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
Fragment Code:
public class MyFragment extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View v=inflater.inflate(R.layout.frag_lay, null);
return v;
}
}
activity_main XML :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/lay_ver"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<LinearLayout
android:id="#+id/lay_hor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<EditText
android:id="#+id/etadd"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="80"
android:hint="Enter Subject"
android:paddingTop="20dp" />
<Button
android:id="#+id/badd"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="20"
android:text="Add" />
</LinearLayout>
<ScrollView
android:id="#+id/sv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/sv1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</ScrollView>
Fragment XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layfrag"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.53"
android:text="HiHow"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.20"
android:text="Hello"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="#+id/button1"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<Button
android:id="#+id/button2"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
You can add a list of Fragments in your activity and each fragment to the list when you create them. Then you can get the fragment you want to change and do as cdblades said :
View parent = fragment.getView();
View childTextView = (TextView)parent.findViewById(R.id.myChildTextView);
But why are you adding the fragments in the same container?
The base View class has the findById() method that you can use to get a reference to child views like so:
View parent = fragment.getView();
View childTextView = (TextView)parent.findViewById(R.id.myChildTextView);
New android developer here. I am trying to create a dynamic UI that loads based on the users selection of a RadioGroup. Based on their selection, one of 3 possible fragments will be loaded into a LinearLayout section. This is my first attempt at my own sample problem that is not just a walk-through tutorial. Here is the main activity:
public class BaseConverter extends Activity {
RadioGroup convert;
Fragment toFragment;
RadioGroup toRadioGroup = null;
TextView inputDisplay = null;
TextView outputDisplay = null;
TextView resultTitle = null;
#Override
public void onCreate(Bundle sIS) {
super.onCreate(sIS);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.setContentView(R.layout.base_converter);
convert = (RadioGroup) this.findViewById(R.id.bc_convert_group);
convert.setOnCheckedChangeListener(new ConvertListener());
FragmentManager fm = getFragmentManager();
FragmentTransaction converterFragment = fm.beginTransaction();
ConvertEmptyFragment emptyTo = new ConvertEmptyFragment();
converterFragment.replace(R.id.bc_converter_fragment, emptyTo);
converterFragment.commit();
FragmentTransaction toFragment = fm.beginTransaction();
ConvertEmptyFragment emptyConverter = new ConvertEmptyFragment();
toFragment.replace(R.id.bc_to_fragment, emptyConverter);
toFragment.commit();
}
#Override
public void onResume() {
convert.clearCheck();
super.onResume();
}
#Override
public void onPause() {
convert.clearCheck();
super.onPause();
}
// I put a little null check so you can see how I'm trying to access the TextViews and what results
public void updateUIComponents(){
View converterView = this.findViewById(R.id.bc_converter_fragment);
inputDisplay = (TextView)converterView.findViewById(R.id.bc_display_input);
outputDisplay = (TextView)converterView.findViewById(R.id.bc_display_output);
if (inputDisplay == null){
Log.d("BaseConverter", "inputDisplay == null");
} else {
Log.d("BaseConverter", "inputDisplay != null");
}
}
class ConvertListener implements OnCheckedChangeListener {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
Fragment toFragment;
Fragment converterFragment;
switch (checkedId) {
case R.id.bc_convert_binary:
toFragment = new ConvertRBFragmentBinary();
converterFragment = new ConverterFragmentBinary();
break;
case R.id.bc_convert_decimal:
toFragment = new ConvertRBFragmentDecimal();
converterFragment = new ConverterFragmentDecimal();
break;
case R.id.bc_convert_hex:
toFragment = new ConvertRBFragmentHex();
converterFragment = new ConverterFragmentHex();
break;
default:
toFragment = new ConvertEmptyFragment();
converterFragment = new ConvertEmptyFragment();
break;
}
FragmentManager fm = getFragmentManager();
FragmentTransaction converterTransaction = fm.beginTransaction();
converterTransaction.replace(R.id.bc_converter_fragment, converterFragment);
converterTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
converterTransaction.commit();
FragmentTransaction toTransaction = fm.beginTransaction();
toTransaction.replace(R.id.bc_to_fragment, toFragment);
toTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
toTransaction.commit();
updateUIComponents();
}
}
So, based on what a user chooses, the proper fragments will be loaded into the respective LinearLayout sections. However, now I want to implement the business logic of the fragments (which is just integer base conversion; i.e. binary number to decimal...) but when I try to access the TextViews, as seen in the updateUIComponents method, I get null pointers. What am I missing?
Here's the ConverterFragmentBinary class for reference:
public class ConverterFragmentBinary extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sIS){
View v = inflater.inflate(R.layout.converter_fragment_binary, container, false);
return v;
}
}
and its respective xml layout for reference:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF000000"
android:gravity="center_horizontal"
android:orientation="vertical" >
<ImageView
android:id="#+id/bc_binary_converter_logo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dip"
android:maxHeight="30dip"
android:src="#drawable/binary_converter" />
<TextView
android:id="#+id/bc_display_input"
style="#style/input_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dip"
android:layout_marginLeft="15dip"
android:layout_marginRight="15dip"
android:layout_marginTop="5dip"
android:gravity="center_vertical|right"
android:lines="1"
android:minHeight="30sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FF000000"
android:gravity="center_horizontal"
android:orientation="horizontal" >
<Button
android:id="#+id/button_num_0"
style="#style/op_button_land"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:gravity="center"
android:onClick="num0"
android:text="#string/num_0" />
<Button
android:id="#+id/button_num_1"
style="#style/op_button_land"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:gravity="center"
android:onClick="num1"
android:text="#string/num_1" />
</LinearLayout>
<TextView
android:id="#+id/bc_result_title"
style="#style/radio_button_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_marginTop="10dip"
android:gravity="left"
android:text="#string/choose_convert" />
<TextView
android:id="#+id/bc_display_output"
style="#style/display_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dip"
android:layout_marginRight="15dip"
android:layout_marginTop="5dip"
android:gravity="center_vertical|right"
android:lines="1"
android:minHeight="30sp" />
</LinearLayout>
and then heres the main activity it gets loaded into:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/base_conversion_layout"
style="#style/layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="5"
android:baselineAligned="false"
android:gravity="center_vertical|left"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="2"
android:orientation="vertical" >
<TextView
style="#style/radio_button_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/convert" />
<RadioGroup
android:id="#+id/bc_convert_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:padding="5dip" >
<RadioButton
android:id="#+id/bc_convert_binary"
style="#style/radio_button"
android:text="#string/binary" />
<RadioButton
android:id="#+id/bc_convert_decimal"
style="#style/radio_button"
android:text="#string/decimal" />
<RadioButton
android:id="#+id/bc_convert_hex"
style="#style/radio_button"
android:text="#string/hex" />
</RadioGroup>
</LinearLayout>
<LinearLayout
android:id="#+id/bc_to_fragment"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="3"
android:orientation="vertical" >
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="#+id/bc_converter_fragment"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="13"
android:orientation="vertical" >
</LinearLayout>
</LinearLayout>
Thanks in advance and sorry for the long code blocks but I figured it was better to include more than less.
Also, you should inflate your Fragments layout to bring it from your XML to your Java code instead of simply referring it using findViewById() method.
So instead of doing this,
View converterView = this.findViewById(R.id.bc_converter_fragment);
Do this inside your onCreateView method of the fragment,
View converterView = infalter.inflate(R.id.bc_converter_fragment,null);
updateUIComponents(converterView);//call this methid and pass your view
new method looks like this,
public void updateUIComponents(View converterView){
inputDisplay = (TextView)converterView.findViewById(R.id.bc_display_input);
outputDisplay = (TextView)converterView.findViewById(R.id.bc_display_output);
if (inputDisplay == null){
Log.d("BaseConverter", "inputDisplay == null");
} else {
Log.d("BaseConverter", "inputDisplay != null");
}
}
Preamble: I am using ActionBarSherlock, Target SDK is 17 (Android 4.2), Min SDK is 5 (Android 2.0)
Situation:
I've got a fragment in my app, which presents some kind of login. It allows the user to have several user accounts on device (because Android < 4.2 didn't have system support for that and our users seem to use that due to device sharing).
The fragment layout consists of a listview and on large-landscape also a button to add new accounts (otherwise via overflow menu available).
The listview is attached to a BaseAdapter-Derivate called "AccountAdapter", which gets the accounts from a database and creating corresponding child views per account via layoutinflater. There are 3 Possibilities: User provided both Login and Password / User provided only login / User provided nothing. Therefore, there are 3 different Layouts for those cases, where the missing data is requested via EditText-Elements and stored data is shown via TextView. Also, the layouts with missing data provide a checkbox for store the missing data and a submit-button. If all data is provided, the onclicklistener for the missing submit button gets directly attached to the account root view.
The onclicklistener messages the entered data to the network code class and modifys the adapter mode; after that, the adapter only shows the selected entry, but with the "progress" view, to visualize the current action to the user ("User XXX is being logged in, please stand by...").
This already works well.
Problem:
On orientation changes, all entered data gets lost. Entered login data, passwords, information about if the login data should be stored.
Layouts:
<!-- layout/main.xml -->
<?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"
android:orientation="horizontal" >
<FrameLayout
android:id="#id/main_fragment_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<!-- layout-large-land/main.xml -->
<?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"
android:orientation="horizontal" >
<FrameLayout
android:id="#id/main_fragment_sidebar"
android:layout_width="#dimen/main_sidebar_width"
android:layout_height="match_parent" />
<FrameLayout
android:id="#id/main_fragment_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<!-- layout/fragment_login.xml -->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="#id/fragment_login_accountlist"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</RelativeLayout>
<!-- layout-large-land/fragment_login.xml -->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="#id/fragment_login_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="#string/string_fragment_login" />
<ListView
android:id="#id/fragment_login_accountlist"
android:layout_width="#dimen/fragment_login_accountlist_width"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" >
</ListView>
</RelativeLayout>
<!-- layout/view_login_account_new.xml -->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#id/view_login_account_profileimage"
android:layout_width="#dimen/view_login_account_profileimage_width"
android:layout_height="#dimen/view_login_account_profileimage_height"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:contentDescription="#string/string_view_login_account_profileimage_contentdescription"
android:scaleType="fitCenter"
android:src="#drawable/img_kb" />
<EditText
android:id="#id/view_login_account_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_toRightOf="#id/view_login_account_profileimage"
android:ems="10"
android:hint="#string/string_view_login_account_username_hint"
android:inputType="text" >
<requestFocus />
</EditText>
<EditText
android:id="#id/view_login_account_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#id/view_login_account_username"
android:layout_alignParentRight="true"
android:layout_below="#id/view_login_account_username"
android:ems="10"
android:hint="#string/string_view_login_account_password_hint"
android:inputType="textPassword" />
<CheckBox
android:id="#id/view_login_account_storecredentials"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="#id/view_login_account_password"
android:layout_toRightOf="#id/view_login_account_profileimage"
android:text="#string/string_view_login_account_storecredentials_text" />
<Button
android:id="#id/view_login_account_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="#id/view_login_account_storecredentials"
android:text="#string/string_view_login_account_submit_text" />
</RelativeLayout>
<!-- layout/view_login_account_progress.xml -->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#id/view_login_account_profileimage"
android:layout_width="#dimen/view_login_account_profileimage_width"
android:layout_height="#dimen/view_login_account_profileimage_height"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:contentDescription="#string/string_view_login_account_profileimage_contentdescription"
android:scaleType="fitCenter"
android:src="#drawable/img_kb" />
<TextView
android:id="#id/view_login_account_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_toRightOf="#id/view_login_account_profileimage"
android:ems="10"
>
</TextView>
<TextView
android:id="#id/view_login_account_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#id/view_login_account_username"
android:layout_alignParentRight="true"
android:layout_below="#id/view_login_account_username"
android:ems="10"
android:text="#string/string_view_login_account_progress_text" />
</RelativeLayout>
<!-- layout/view_login_account_stored_password.xml -->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#id/view_login_account_profileimage"
android:layout_width="#dimen/view_login_account_profileimage_width"
android:layout_height="#dimen/view_login_account_profileimage_height"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:contentDescription="#string/string_view_login_account_profileimage_contentdescription"
android:scaleType="fitCenter"
android:src="#drawable/img_kb" />
<TextView
android:id="#id/view_login_account_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_toRightOf="#id/view_login_account_profileimage"
android:ems="10"
>
</TextView>
<TextView
android:id="#id/view_login_account_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#id/view_login_account_username"
android:layout_alignParentRight="true"
android:layout_below="#id/view_login_account_username"
android:ems="10"
android:text="#string/string_view_login_account_password_text"
/>
</RelativeLayout>
<!-- layout/view_login_account_stored_username.xml -->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#id/view_login_account_profileimage"
android:layout_width="#dimen/view_login_account_profileimage_width"
android:layout_height="#dimen/view_login_account_profileimage_height"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:contentDescription="#string/string_view_login_account_profileimage_contentdescription"
android:scaleType="fitCenter"
android:src="#drawable/img_kb" />
<TextView
android:id="#id/view_login_account_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_toRightOf="#id/view_login_account_profileimage"
android:ems="10"
android:hint="#string/string_view_login_account_username_hint" >
<requestFocus />
</TextView>
<EditText
android:id="#id/view_login_account_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#id/view_login_account_username"
android:layout_alignParentRight="true"
android:layout_below="#id/view_login_account_username"
android:ems="10"
android:hint="#string/string_view_login_account_password_hint"
android:inputType="textPassword" />
<CheckBox
android:id="#id/view_login_account_storecredentials"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="#id/view_login_account_password"
android:layout_toRightOf="#id/view_login_account_profileimage"
android:text="#string/string_view_login_account_storecredentials_text" />
<Button
android:id="#id/view_login_account_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="#id/view_login_account_storecredentials"
android:text="#string/string_view_login_account_submit_text" />
</RelativeLayout>
Code:
The code both doesn't implement onSaveInstanceState and onConfigurationChange yet.
(whole quotation would be too long imho, > 1.000 lines of code)
public class MessengerActivity extends SherlockFragmentActivity {
// -------------------------------------------------------------------------
FrameLayout fragmentSidebar = null;
FrameLayout fragmentContent = null;
Content content = null;
// -------------------------------------------------------------------------
boolean hasSidebar = false;
// -------------------------------------------------------------------------
public void onCreate(Bundle savedInstanceState) {
// ---------------------------------------------------------------------
super.onCreate(savedInstanceState);
// ---------------------------------------------------------------------
content = Content.getInstance(this);
// ---------------------------------------------------------------------
setContentView(R.layout.main);
// ---------------------------------------------------------------------
captureFragmentViews();
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
if (savedInstanceState == null) {
// -----------------------------------------------------------------
gotoLogin();
// -----------------------------------------------------------------
}
else {
// -----------------------------------------------------------------
// -----------------------------------------------------------------
}
// ---------------------------------------------------------------------
}
// -------------------------------------------------------------------------
// Disabled through android manifest at the moment
#Override
public void onConfigurationChanged(Configuration newConfig) {
// ---------------------------------------------------------------------
super.onConfigurationChanged(newConfig);
// ---------------------------------------------------------------------
Log.d(getClass().getSimpleName(), "onConfigurationChanged");
// ---------------------------------------------------------------------
}
// -------------------------------------------------------------------------
public void captureFragmentViews() {
// ---------------------------------------------------------------------
fragmentSidebar = (FrameLayout) findViewById(R.id.main_fragment_sidebar);
fragmentContent = (FrameLayout) findViewById(R.id.main_fragment_content);
// ---------------------------------------------------------------------
if ((fragmentSidebar != null) && (fragmentContent != null)) {
hasSidebar = true;
}
else {
hasSidebar = false;
}
// ---------------------------------------------------------------------
}
// -------------------------------------------------------------------------
public void gotoLogin() {
// ---------------------------------------------------------------------
Fragment fragment = SherlockFragment.instantiate(this,
LoginFragment.class.getName());
// ---------------------------------------------------------------------
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (hasSidebar) {
ft.add(R.id.main_fragment_content, fragment);
fragmentSidebar.setVisibility(View.GONE);
}
else {
ft.add(R.id.main_fragment_content, fragment);
}
// ---------------------------------------------------------------------
ft.commit();
getSupportFragmentManager().executePendingTransactions();
// ---------------------------------------------------------------------
}
// -------------------------------------------------------------------------
public void gotoSignup() {
// TODO Auto-generated method stub
}
// -------------------------------------------------------------------------
public void gotoContactList(int filterId) {
// TODO Auto-generated method stub
}
// -------------------------------------------------------------------------
public void gotoConversation(int userId) {
// TODO Auto-generated method stub
}
// -------------------------------------------------------------------------
public void gotoOnlineStatusList(int categoryId) {
// TODO Auto-generated method stub
}
// -------------------------------------------------------------------------
public void gotoSettings(int categoryId) {
// TODO Auto-generated method stub
}
// -------------------------------------------------------------------------
}
I check for whether savedInstanceState is set or not in the main activity, so my activity is already "prepared" in terms of fragment recreation.
Fragment checks for whether the adapter already exists or not before creating and attaching it to the listview.
But: As far as my understanding is, even if the "recreated" fragment use the same Adapter, "by default" all getViews() get recalled and therefore create a new instance of the view with "resetted" contents.
The AccountAdapter gets dedicated "Account"-Objects with user-id, username, password from the database. Also, "Account" could be extended to hold additional data, like to cache the view.
My idea was to implement a getView like this:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
// ---------------------------------------------------------------------
final Account account = (Account) getItem(position);
View view = null;
// ---------------------------------------------------------------------
if (account == null) {
return view;
}
// ---------------------------------------------------------------------
if (account.view != null) {
return account.view;
}
// ---------------------------------------------------------------------
[...]
}
But then I noticed, that the AccountAdapter didn't survive the recreation, Android re-instantiates the LoginFragment class.
What I need:
How to recover the data from the listview content formulars / how to preserve the AccountAdapter and its associated views
Tips on how to optimize and improve my architectural design
It is not clear from your code if you add a Fragment every time the onCreate() method of your Activity get's called.
You should add a Fragment or the first Fragment only when the Activity get's created for the first time .
if(savedInstanceState==null){
addFragment();
}
if this is not null your Activity gets re-created, and it will also re-add your previous Fragments. Evan if you have more Fragments in the backstack they will all be put back in your Activity.
To keep the data in your fragments, you should either use setRetainInstance(true); on your Fragments onCreate() method, or use onSaveInstanceState(Bundle bundle) to save the specific data.