I have a Main activity with two master detail Fragments.I am trying to implement like "Multiple fragments, multiple activities" method.
layout folder
activity_main.xml
<FrameLayout 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"
tools:context=".MoneyActivity"
android:id="#+id/fragment_container" >
<fragment class="com.mysite.money.AFragment"
android:id="#+id/AFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
layout-large folder activity_main.xml
<LinearLayout 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"
tools:context=".MoneyActivity"
android:id="#+id/fragment_container"
android:orientation="horizontal" >
<fragment class="com.mysite.money.AFragment"
android:id="#+id/AFragment"
android:layout_width="#dimen/action_bar_title_text_size"
android:layout_height="match_parent"/>
<fragment class="com.mysite.money.BFragment"
android:id="#+id/BFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
I got error like below(when run on tablet-layout-large):
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mysite.money/com.mysite.money.MoneyActivity}: android.view.InflateException: Binary XML file line #15: Error inflating class fragment
I checked class names of fragments properly.
I think i got error BFragment
BFragment:
public class BFragment extends SherlockFragment {
String selectedItem="";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int size = getArguments().size();
if(size>0)
{
selectedItem = getArguments().getString("position").toString();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
TextView textView=new TextView(inflater.getContext());
textView.setText("Selected Item->"+selectedItem);
return textView;
}
}
OnItemSelected in my mainActivity(Associated with fragment A)
**#Override
public void onItemSelected(String id) {
BFragment displayFrag = (BFragment) getSupportFragmentManager().findFragmentById(new BFragment().getId());
if (displayFrag == null) {
// DisplayFragment (Fragment B) is not in the layout (handset layout),
// so start DisplayActivity (Activity B)
// and pass it the info about the selected item
Intent intent = new Intent(this, BActivity.class);
intent.putExtra("position", id);
Log.i("innodea", "position->"+id);
startActivity(intent);
} else {
// DisplayFragment (Fragment B) is in the layout (tablet layout),
// so tell the fragment to update
//displayFrag.updateContent(id);
}
}**
AFragment:
public class AFragment extends SherlockListFragment {
private View inflate;
private Callbacks mCallbacks = sDummyCallbacks;
private int mActivatedPosition= ListView.INVALID_POSITION;
private static final String STATE_ACTIVATED_POSITION = "activated_position";
public interface Callbacks {
public void onItemSelected(String id);
}
/**
* A dummy implementation of the {#link Callbacks} interface that does
* nothing. Used only when this fragment is not attached to an activity.
*/
private static Callbacks sDummyCallbacks = new Callbacks() {
public void onItemSelected(String id) {
}
};
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Activities containing this fragment must implement its callbacks.
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException(
"Activity must implement fragment's callbacks.");
}
mCallbacks = (Callbacks) activity;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter<DummyContent.DummyItem>(getActivity(),android.R.layout.simple_list_item_activated_1,android.R.id.text1, DummyContent.ITEMS));
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Restore the previously serialized activated item position.
if (savedInstanceState != null
&& savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
setActivatedPosition(savedInstanceState
.getInt(STATE_ACTIVATED_POSITION));
}
}
#Override
public void onDetach() {
super.onDetach();
// Reset the active callbacks interface to the dummy implementation.
mCallbacks = sDummyCallbacks;
}
#Override
public void onListItemClick(ListView listView, View view, int position,long id) {
super.onListItemClick(listView, view, position, id);
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mCallbacks.onItemSelected(DummyContent.ITEMS.get(position).id);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mActivatedPosition != ListView.INVALID_POSITION) {
// Serialize and persist the activated item position.
outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
}
}
/**
* Turns on activate-on-click mode. When this mode is on, list items will be
* given the 'activated' state when touched.
*/
public void setActivateOnItemClick(boolean activateOnItemClick) {
// When setting CHOICE_MODE_SINGLE, ListView will automatically
// give items the 'activated' state when touched.
getListView().setChoiceMode(
activateOnItemClick ? ListView.CHOICE_MODE_SINGLE
: ListView.CHOICE_MODE_NONE);
}
private void setActivatedPosition(int position) {
if (position == ListView.INVALID_POSITION) {
getListView().setItemChecked(mActivatedPosition, false);
} else {
getListView().setItemChecked(position, true);
}
mActivatedPosition = position;
}
}
The exception android.view.InflateException: Binary XML file line: #... Error inflating class fragment might happen if you manipulate with getActivity() inside your fragment before onActivityCreated() get called. In such case you receive a wrong activity reference and can't rely on that.
For instance the next pattern is wrong:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
final View view = inflater.inflate(R.layout..., container, false);
Button button = getActivity().findViewById(R.id...);
button.setOnClickListener(...); - another problem: button is null
return view;
}
Adding Unique ID for the Static Fragment is required. I found it after carefully looking in Logs for error. CLick on below link to see error details:
Error Inspection in logs
No need for FragmentActivity as suggested in many posts. AppCompatActivity is fine.
So, code like below works just fine.
<?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="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:text="Customize your Android: " />
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.example.android.android_me.ui.MasterListFragment"
android:id="#+id/StaticFragment"/>
</LinearLayout>
Your fragment code is most likely broken and simply crashes on creation which ends in failure of inflation. Plant breakpoints on each fragment onCreateView() and related methods called in during fragment creation or try to instantiate the fragment by hand (new AFragment()) and attaching it to The Layout to see where exactly if fails.
You need to import the Fragment class from android.support.v4.app.Fragment instead of android.app.Fragment.
import android.support.v4.app.Fragment;
And in the XML file of the activity where you intend to use this fragment, you need to use:
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/map_fragment"
name="yourpackagname.yourfragmentclass"/>
//package name here, is the name of folder which is in java directory.
Related
I have an app that I desperately need to convert from using the old ActivityGroup class to Fragments. I'm not sure how to go about it though. Below is a sample of the code I use now. Could anyone provide some insight into what steps I should take to start switching it over to use Fragments / FragmentManager instead?
Main.java
public class Main extends TabActivity implements OnTabChangeListener {
public static TextView txtViewHeading;
public static Button btnBack;
public static ImageButton btnShare;
public static Main mainActivity;
public static Boolean isVisible = false;
private GoogleCloudMessaging gcm;
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mainActivity = this;
NotificationsManager.handleNotifications(this, NotificationSettings.SenderId, PushHandler.class);
registerWithNotificationHubs();
//reference headings text & button for access from child activities
txtViewHeading = (TextView) findViewById(R.id.txtViewHeading);
btnBack = (Button) findViewById(R.id.btnBack);
btnShare = (ImageButton) findViewById(R.id.btnShare);
// Update the font for the heading and back button
Typeface arialTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/arial.ttf");
Typeface myriadTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/myriad.ttf");
txtViewHeading.setTypeface(myriadTypeface);
btnBack.setTypeface(arialTypeface);
Resources res = getResources();
TabHost tabsNavigation = getTabHost();
// Set up the views for each tab - custom view used for Badge icon
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Set up my tabs...each one looks similar to this
View statusTabView = inflater.inflate(R.layout.tab, null);
ImageView statusTabIcon = (ImageView) statusTabView.findViewById(R.id.tabIcon);
statusTabIcon.setImageResource(R.drawable.tab_first);
TextView statusTabText = (TextView) statusTabView.findViewById(R.id.tabText);
statusTabText.setText("Status");
statusTabText.setTypeface(arialTypeface);
statusTabBadge = (TextView) statusTabView.findViewById(R.id.tabBadge);
statusTabBadge.setTypeface(arialTypeface);
tabsNavigation.addTab(tabsNavigation.newTabSpec(getResources().getString(R.string.main_tab_status))
.setIndicator(statusTabView)
.setContent(new Intent(this, StatusGroupActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)));
//Set default tab to Status
tabsNavigation.setCurrentTab(0);
tabsNavigation.setOnTabChangedListener(this);
}
/* Set txtViewHeading text to selected tab text */
#Override
public void onTabChanged(String tabId) {
// TODO Auto-generated method stub
txtViewHeading.setText(tabId);
}
/* Set code to execute when onDestroy method is called */
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
/* Set code to execute when onPause method is called */
#Override
protected void onPause() {
super.onPause();
isVisible = false;
}
/* Set code to execute when onResume method is called */
#Override
protected void onResume() {
super.onResume();
isVisible = true;
}
/* Set code to execute when onStop method is called */
#Override
protected void onStop() {
super.onStop();
isVisible = false;
}
/**
* Check the device to make sure it has the Google Play Services APK. If
* it doesn't, display a dialog that allows users to download the APK from
* the Google Play Store or enable it in the device's system settings.
*/
private boolean checkPlayServices() {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (apiAvailability.isUserResolvableError(resultCode)) {
apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST)
.show();
} else {
ToastNotify("This device is not supported by Google Play Services.");
finish();
}
return false;
}
return true;
}
public void ToastNotify(final String notificationMessage) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(Main.this, notificationMessage, Toast.LENGTH_LONG).show();
}
});
}
public void registerWithNotificationHubs()
{
if (checkPlayServices()) {
// Start IntentService to register this application with GCM.
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
}
}
TabGroupActivity.java
public class TabGroupActivity extends ActivityGroup
{
private ArrayList<String> mIdList;
Button btnBack;
ImageButton btnShare;
TextView txtViewHeading;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
btnBack = Main.btnBack;
btnShare = Main.btnShare;
txtViewHeading = Main.txtViewHeading;
btnBack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
if (mIdList == null) mIdList = new ArrayList<String>();
}
/**
* This is called when a child activity of this one calls its finish method.
* This implementation calls {#link LocalActivityManager#destroyActivity} on the child activity
* and starts the previous activity.
* If the last child activity just called finish(),this activity (the parent),
* calls finish to finish the entire group.
*/
#Override
public void finishFromChild(Activity child)
{
try
{
btnShare.setVisibility(View.GONE);
LocalActivityManager manager = getLocalActivityManager();
int index = mIdList.size()-1;
if (index < 1)
{
finish();
return;
}
manager.destroyActivity(mIdList.get(index), true);
mIdList.remove(index);
index--;
String lastId = mIdList.get(index);
Intent lastIntent = manager.getActivity(lastId).getIntent();
Window newWindow = manager.startActivity(lastId, lastIntent);
setContentView(newWindow.getDecorView());
//Set Heading text to current Id
txtViewHeading.setText(getActivityHeading(lastId));
//Set Back button text to previous Id if applicable
btnBack.setVisibility(View.VISIBLE);
//Back button
String backId = "";
if(mIdList.size() > 1)
{
backId = mIdList.get(mIdList.size()-2);
btnBack.setVisibility(View.VISIBLE);
btnBack.setText(getActivityHeading(backId));
txtViewHeading.setPadding(10,0,0,0);
}
else
{
btnBack.setVisibility(View.GONE);
txtViewHeading.setPadding(0,0,0,0);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* Starts an Activity as a child Activity to this.
* #param Id Unique identifier of the activity to be started.
* #param intent The Intent describing the activity to be started.
*/
public void startChildActivity(String Id, Intent intent)
{
try
{
btnShare.setVisibility(View.GONE);
Window window = getLocalActivityManager().startActivity(Id,intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
if (window != null)
{
mIdList.add(Id);
setContentView(window.getDecorView());
txtViewHeading.setText(getActivityHeading(Id));
//Back button
String backId = "";
if(mIdList.size() > 1)
{
backId = mIdList.get(mIdList.size()-2);
btnBack.setVisibility(View.VISIBLE);
btnBack.setText(backId);
txtViewHeading.setPadding(5,0,0,0);
}
else
{
btnBack.setVisibility(View.GONE);
txtViewHeading.setPadding(0,0,0,0);
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* The primary purpose is to prevent systems before android.os.Build.VERSION_CODES.ECLAIR
* from calling their default KeyEvent.KEYCODE_BACK during onKeyDown.
*/
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
//preventing default
return true;
}
return super.onKeyDown(keyCode, event);
}
/**
* Overrides the default implementation for KeyEvent.KEYCODE_BACK
* so that all systems call onBackPressed().
*/
#Override
public boolean onKeyUp(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
onBackPressed();
return true;
}
return super.onKeyUp(keyCode, event);
}
/**
* If a Child Activity handles KeyEvent.KEYCODE_BACK.
* Simply override and add this method.
*/
#Override
public void onBackPressed ()
{
try
{
btnShare.setVisibility(View.GONE);
int length = mIdList.size();
if ( length > 1)
{
Activity current = getLocalActivityManager().getActivity(mIdList.get(length-1));
current.finish();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* Get the correct heading text and language based on activity id
*/
public String getActivityHeading(String id)
{
// method that returns the TEXT for my main heading TextView based on the activity we're on...
}
}
StatusGroupActivity
public class StatusGroupActivity extends TabGroupActivity
{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startChildActivity("Status", new Intent(this,Status.class));
}
}
... so basically when my app loads, I get my tabs at the bottom, my header at the top, and the "tab content" in the middle. In my Status activity, I can load another activity from it by using ...
Intent intent = new Intent(getParent(), SomeOtherActivity.class)
TabGroupActivity parentActivity = (TabGroupActivity)getParent();
parentActivity.startChildActivity("Some Other Activity", intent);
... and it loads the SomeOtherActivity activity into the content area. Hitting back takes me back to the Status screen.
Any pointers, examples and assistance with converting this over to use Fragments is so greatly appreciated. I will gladly donate 500 of my rep. points for a full example.
main.xml (Main Activity Layout file)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.app.FragmentTabHost xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
tools:ignore="ContentDescription,HardcodedText" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/imageSuccess"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:adjustViewBounds="true"
android:scaleType="matrix"
android:src="#drawable/bg_navbar_blank" />
<com.myproject.android.BgButtonStyle
android:id="#+id/btnBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="0dp"
android:background="#drawable/back_button"
android:text=""
android:textColor="#color/White"
android:textSize="12sp"
android:visibility="visible"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:padding="5dp"/>
<ImageButton
android:id="#+id/btnShare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:background="#null"
android:src="#drawable/icon_share"
android:visibility="visible"
android:adjustViewBounds="false"
android:scaleType="fitXY"/>
<com.myproject.android.AutoResizeTextView
android:id="#+id/txtViewHeading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingLeft="5dp"
android:text="Status"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="28sp"
android:textStyle="bold"
android:paddingRight="5dp"
android:layout_toEndOf="#id/btnBack"
android:layout_toStartOf="#id/btnShare"
android:layout_centerVertical="true"
android:lines="1"/>
</RelativeLayout>
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" >
</FrameLayout>
<TabWidget
android:id="#android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="-4dp"
android:layout_weight="0"
android:background="#drawable/bg_tabs">
</TabWidget>
</LinearLayout>
</android.support.v4.app.FragmentTabHost>
In my current TabGroupActivity class, in the finishFromChild and startChildActivity methods, I am able to call setText on the txtViewHeading TextView element in my main activity layout. Which is the current activities "title". If there is more than 1 activity in the group, the back button shows the previous title. How can I duplicate this in the examples below? The main activity layout there is much different than mine.
First you need to add Design Support Library and AppCompatLibrary into your Project
Add this code into your app gradle
compile 'com.android.support:appcompat-v7:24.0.0'
compile 'com.android.support:design:24.0.0'
layout for activity_main.xml (like main.xml in your code)
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="#dimen/appbar_padding_top"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/AppTheme.PopupOverlay">
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
In above layout ViewPager will provides horizontal layout to display tabs. You can display more screens in a single screen using tabs. You can swipe the tabs quickly as you can.
Root Fragment
<FrameLayout 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:id="#+id/root_frame" >
View for First Fragment
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:background="#ff0"
android:layout_height="match_parent" >
<TextView
android:id="#+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:text="#string/first_fragment" />
<Button
android:id="#+id/btn"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:text="#string/to_second_fragment"/>
</RelativeLayout>
View for Second and Individual(s) Fragment.
<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">
<TextView
android:id="#+id/section_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
Now add a MainActivity(like Main Activity in yours code) under which all this thing will handle.
public class MainActivity extends AppCompatActivity {
private TabGroupAdapter mTabGroupAdapter;
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ArrayList<Fragment> fragmentList = new ArrayList<Fragment>();
fragmentList.add(new RootFragment());
fragmentList.add(new IndividualFragment1());
fragmentList.add(new IndividualFragment2());
ArrayList<String> name = new ArrayList<String>() {
{
add("Root Tab");
add("Second Tab");
add("Third Tab");
}
};
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mTabGroupAdapter = new TabGroupAdapter(getSupportFragmentManager(),name, fragmentList,);
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mTabGroupAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
}
}
There is one FragmentPagerAdapter defined as mTabGroupAdapter inside MainActivity that will add a different tabs inside a single Layout.
First we bind the mTabGroupAdapter to mViewPager.
TabLayout will act like a TabHost under which Tab will be added by FragmentPagerAdapter.
mViewPager is bind to the Tablayout.
Under MainActivity TabLayout will display the name of Tabs.
TabGroupAdapter
public class TabGroupAdapter extends FragmentPagerAdapter {
private ArrayList<Fragment> fragmentList = new ArrayList<Fragment>();
private ArrayList<String> fragment_name;
public TabGroupAdapter(FragmentManager fm, ArrayList<String> name, ArrayList<Fragment> list) {
super(fm);
this.fragmentList = list;
this.fragment_name = name;
}
#Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
#Override
public int getCount() {
return fragmentList.size();
}
#Override
public CharSequence getPageTitle(int position) {
return fragment_name.get(position);
}
}
In TabGroupAdapter you would pass a List of fragments(or single fragment) and list of fragments name(or single name) as arguments in the Constructor.
IndividualFragment(s) will act like a individual Tab instead of Activity.
RootFragment will be acting as a container for other fragments( First Fragment and Second Fragment)
Root Fragment
public class RootFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.root_fragment, container, false);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.root_frame, new FirstFragment());
fragmentTransaction.commit();
return view;
}
}
First Fragment
public class FirstFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.first_fragment, container, false);
Button btn = (Button) view.findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
//use the "root frame" defined in
//"root_fragment.xml" as the reference to replace fragment
fragmentTransaction.replace(R.id.root_frame, new SecondFragment());
/*
* allow to add the fragment
* to the stack and return to it later, by pressing back
*/
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
}
}
Second Fragment
public class SecondFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
Individual(s) Fragment
public class IndividualFragment1 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
public class IndividualFragment2 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
In OnCreateView method you would set a layout of a Tab .
You won't have to use the getTabHost() method.
Let me know if you persist any problem.
Whenever you want to dynamically change or update the Tabs in View Pager just add or remove item from fragmentList and call this method mTabGroupAdapter.notifyDataSetChanged(); inside MainActivity.
Add these dependencies to your project:
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
First change your Main activity must be extended from AppCompatActivity.
Than change your main activity's layout like below:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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/coordinatorlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".Main">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbarlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<include
layout="#layout/toolbar_default"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:tabGravity="fill"
app:tabMaxWidth="0dp"
app:tabIndicatorHeight="4dp"
app:tabMode="fixed"
app:tabIndicatorColor="#android:color/white"
android:background="#color/AppPrimary"/>
</android.support.design.widget.AppBarLayout>
<?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:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".dashboard.DashboardActivity"
tools:showIn="#layout/activity_dashboard">
<android.support.v4.view.ViewPager
android:id="#+id/viewpager_main"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
And here's a toolbar layout example. You can customize however you want.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar_main"
style="#style/Widget.MyApp.Toolbar.Solid"
android:layout_width="match_parent"
android:layout_height="#dimen/abc_action_bar_default_height_material"
android:background="#color/AppPrimary"
app:contentInsetEnd="16dp"
app:contentInsetStart="16dp" />
Than you need to create fragments which you'll use in your tabs instead of activities which you use for tabs. In this case this'll your Status Activity if i'm not wrong.
Define a StatusFragment like below:
public class StatusFragment extends Fragment
{
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// this is your Status fragment. You can do stuff which you did in Status activity
}
}
Than you need to define a tabs adapter which you'll bind with your tabs and convert your TabHost to Fragment/Fragment manager type. Titles string array contains strings which you'll show in your tabs indicator. Such as "Status, My Assume Tab, My awesome tab 2
public class DashboardTabsAdapter extends FragmentPagerAdapter {
private String[] mTitles;
public DashboardTabsAdapter(FragmentManager fm, String[] titles) {
super(fm);
this.mTitles = titles;
}
#Override
public Fragment getItem(int position) {
return new StatusFragment();
// You can define some other fragments if you want to do different types of operations in your tabs and switch this position and return that kind of fragment.
}
#Override
public int getCount() {
return mTitles.length;
}
#Override
public CharSequence getPageTitle(int position) {
return mTitles[position];
}
}
And finally in your Main activity find your view pager, tabs create a new adapter and bind them.
final TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
final DashboardTabsAdapter dashboardTabsAdapter = new DashboardTabsAdapter(getSupportFragmentManager(), getResources().getStringArray(R.array.tab_titles));
mViewPagerMain = (ViewPager) findViewById(R.id.viewpager_main);
mViewPagerMain.setOffscreenPageLimit(3);
mViewPagerMain.setAdapter(dashboardTabsAdapter);
tabLayout.setupWithViewPager(mViewPagerMain);
Edit: You'll no longer need TabHost and TabActivity any more. Your tab grup activity will be your ViewPager which handles screen changes and lifecycle of fragments inside. If you need to get this activity from fragments you can use getActivity() method and cast it to your activity and use it's public methods.
I have 3 fragments that need to be in a ViewPager. These fragment will hold dynamic information retrieved from a database. I understand that on an orientation change, the activity and fragments are destroyed and recreated. But I was under the impression by its name, that the FragmentStatePagerAdapter will save the state of the fragment. Apparently, I was wrong because every time I did something to the fragment, then change orientation, the fragment is reverted back to how it was laid out in the layout xml file.
As I was debugging, I noticed that on orientation change, the Adapter's getItem() method was never invoked - meaning that it wasn't recreated. So then how come the fragment state reverted back to its original state?
How do I save the fragment state using the FragmentStatePagerAdapter?
Please note that I have been following this tutorial and used their version of the SmartFragmentStatePagerAdapter.java class to manage the fragment dynamically.
And the following are my sample codes.
PageLoader.java - This interface allows MainActivity to manage the loading of the fragment pages dynamically at run time.
public interface PageLoader {
void loadPage(int from, int target);
}
MainActivity.java
public class MainActivity extends AppCompatActivity implements PageLoader {
MyPagerAdapter adapter;
DirectionalViewPager pager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Get the ViewPager and set it's PagerAdapter so that it can display items
pager = (DirectionalViewPager) findViewById(R.id.vpPager);
adapter = new MyPagerAdapter(getSupportFragmentManager());
pager.setOffscreenPageLimit(5);
pager.setAdapter(adapter);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int position = pager.getCurrentItem();
if (position > 0) pager.setCurrentItem(position - 1);
return true;
}
#Override
public void loadPage(int from, int target) {
PageLoader fragment = (PageLoader) adapter.getRegisteredFragment(target);
fragment.loadPage(from, target);
}
}
MyPagerAdapter.java
public class MyPagerAdapter extends SmartFragmentStatePagerAdapter {
private static final int NUM_ITEMS = 4;
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_ITEMS;
}
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: // Fragment # 0 - This will show Frag1
return Frag1.newInstance(position, Frag1.class.getSimpleName());
case 1: // Fragment # 0 - This will show Frag1 different title
return Frag1.newInstance(position, Frag1.class.getSimpleName());
case 2: // Fragment # 1 - This will show Frag2
return Frag2.newInstance(position, Frag2.class.getSimpleName());
default:
return Frag3.newInstance(position, Frag3.class.getSimpleName());
}
}
// Returns the page title for the top indicator
#Override
public CharSequence getPageTitle(int position) {
return "Page " + position;
}
}
Frag1.java Frag2.java Frag3.java - these are all the same, except for the numbering.
public class Frag1 extends Fragment implements PageLoader {
// Store instance variables
private String title;
private int page;
private TextView txtView;
// newInstance constructor for creating fragment with arguments
public static Frag1 newInstance(int page, String title) {
Frag1 fragmentFirst = new Frag1();
Bundle args = new Bundle();
args.putInt("someInt", page);
args.putString("someTitle", title);
fragmentFirst.setArguments(args);
return fragmentFirst;
}
// Store instance variables based on arguments passed
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
page = getArguments().getInt("someInt", 0);
title = getArguments().getString("someTitle");
}
// Inflate the view for the fragment based on layout XML
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.frag1, container, false);
txtView = (TextView) view.findViewById(R.id.txt_frag1);
txtView.setText(page + " - " + title);
Button btn = (Button) view.findViewById(R.id.btn_frag1);
btn.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
PageLoader activity = (PageLoader) getActivity();
activity.loadPage(page, page+1);
}
});
return view;
}
#Override
public void loadPage(int from, int target) {
txtView.setText(txtView.getText() + "\nThis message was created from" + from + " to " + target);
}
}
activity_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="vertical">
<com.example.someone.smartfragmentstatepageradapter.custom.DirectionalViewPager
android:id="#+id/vpPager"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</com.example.someone.smartfragmentstatepageradapter.custom.DirectionalViewPager>
</LinearLayout>
frag1.xml frag2.xml frag3.xml - again these are all the same except for the numbering
<?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="vertical"
android:background="#cc2">
<TextView
android:id="#+id/txt_frag1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="txt_frag1"
/>
<Button
android:id="#+id/btn_frag1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="btn_frag1"
android:textSize="26dp" />
</LinearLayout>
PLEASE tell me how I can use the FragmentStatePagerAdapter to save the "State" of my fragments. I've been scouring the internet from 9am to 9pm today... 12 hours... I really need some help figuring this out. Thanks in advance!
EDIT Try this:
Add another instance variable to your fragment:
private String text; // this is part of saved state
Set this variable in loadPage:
#Override
public void loadPage(int from, int target) {
text = txtView.getText().toString() + "\nThis message was created from" + from + " to " + target;
txtView.setText(text);
}
Override onSaveInstanceState to save this variable:
#Override
public void onSaveInstanceState(Bundle outState);
outState.putString("text", text);
super.onSaveInstanceState(outState);
}
Then restore the the TextView state using this variable:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (savedInstanceState != null) {
// not null means we are restoring the fragment
text = savedInstanceState.getString("text");
} else {
text = "" + page + " - " + title;
}
View view = inflater.inflate(R.layout.frag1, container, false);
txtView = (TextView) view.findViewById(R.id.txt_frag1);
txtView.setText(text);
Button btn = (Button) view.findViewById(R.id.btn_frag1);
btn.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
PageLoader activity = (PageLoader) getActivity();
activity.loadPage(page, page+1);
}
});
return view;
}
Any time you want something in your fragment to stay the same when things like configuration changes occur, this is how you would track the state, then save and restore it.
This is where you would use onSaveInstanceState for fragments and activities.
This is the method you would override to save any necessary state. Anything you change in your fragment that you want to have recreated on configuration change must be saved and then restored during onCreate or onCreateView.
So if you're trying to restore the text created in loadPage, you would create a class-level String for the text, set it in loadPage, save that in the onSaveInstanceState override, and then restore in in onCreateView from the savedInstanceState parameter.
Now here's the kicker: You are noticing that getItem on your adapter isn't called after a config change. But did you notice that your fragment is still there (even though it wasn't how you left it)? Keep in mind that the activity has a FragmentManager that is managing the fragments and their transactions. When the activity goes to config change, it saves its state. The FragmentManager and all of the active fragments are part of that state. Then the fragments are restored in such a way that adapter.getItem isn't called.
Turns out, that SmartFragmentPagerAdapter isn't so smart. It can't recreate its registeredFragments array after a configuration change, so it's really not very useful. I would discourage you from using it.
So how do you send events to off-page fragments when the ViewPager has appropriated the fragment's tag for its own use?
The technique I use is to define event listener interfaces, and have the fragments register as listeners with the activity. When I fire an event, it's by calling a method on the activity that notifies its active listeners. I give a pretty complete example of this in this answer.
I have read this manual and also i'm reading this book. developer.android.com says i should implement communication through activity. But the book says i can use setTargetFragment() and call onActivityResult() by hand for target fragment from other fragment. Each approach works but which is right? What is setTargetFrament() for, if i can't use it for communication with other fragment?
setTargetFrament() and getTargetFrament() can be used in the context of one fragment that starts another fragment. The first fragment can pass its self as a reference to the second fragment:
MyFragment newFrag = new MyFragment();
newFrag.setTargetFragment(this, 0);
getFragmentManager().beginTransaction().replace(R.id.frag_one, newFrag).commit();
Now newFrag can use getTargetFrament() to retrieve the oldFrag and access methods from oldFrag directly.
This is not however something that is recommanded to be used on an usual basis.
The recommanded way of communication between fragments is to be done through the parent activity, as the docs mention:
Often you will want one Fragment to communicate with another,
for example to change the content based on a user event.
All Fragment-to-Fragment communication is done through the associated Activity.
Two Fragments should never communicate directly.
Here is a example of that:
the layout for the main activity:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="#+id/frag_one"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<FrameLayout
android:id="#+id/frag_two"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
the Activity:
public class MainActivity extends Activity
{
private MyFragment f1;
private MyFragment f2;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Bundle b1 = new Bundle();
b1.putString("name", "Fragment One");
f1 = MyFragment.createNew(b1);//we create a new fragment instance
f1.setOnReceiveListener(new MyFragment.ReceiveListener()//we create a new ReceiveListener and pass it to the fragment
{
#Override
public void recv(String str)
{
//f1 has sent data to the activity, the activity passes forward to f2
f2.send(str);
}
});
//we attach the fragment to the activity
getFragmentManager().beginTransaction().add(R.id.frag_one, f1, "frag_one").commit();
//we repeat the above process for the second fragment
Bundle b2 = new Bundle();
b2.putString("name", "Fragment Two");
f2 = MyFragment.createNew(b2);
f2.setOnReceiveListener(new MyFragment.ReceiveListener()
{
#Override
public void recv(String str)
{
f1.send(str);
}
});
getFragmentManager().beginTransaction().add(R.id.frag_two, f2, "frag_two").commit();
}
}
The fragment layout:
<?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/frag_btn"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_alignParentTop="true"/>
<TextView
android:id="#+id/frag_txt"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_below="#+id/frag_btn"
android:textSize="10sp"/>
</RelativeLayout>
The fragment class:
public class MyFragment extends Fragment
{
private ReceiveListener recv_list;
private Button btn;
private TextView txt;
//static factory function that creates new fragments
public static MyFragment createNew(Bundle b)
{
MyFragment f = new MyFragment();
f.setArguments(b);
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
btn = (Button) view.findViewById(R.id.frag_btn);
txt = (TextView) view.findViewById(R.id.frag_txt);
//we retrieve the passed arguments (in this case the name)
Bundle b = getArguments();
final String name = b.getString("name");
btn.setText(name);
btn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
if(null != recv_list)
{
//now we pass the data to the parent activity
recv_list.recv(name + " says hello!");
}
}
});
}
//the activity passes data to the fragment using this method
public void send(String s)
{
txt.append(s + "\n");
}
//helper method that will set the listener
public void setOnReceiveListener(ReceiveListener l)
{
recv_list = l;
}
//the declaration of the listener
public interface ReceiveListener
{
public void recv(String str);
}
}
I am using fragments,I have an edittext in fragment and I want to get value in main activity.
This is my fragment layout
<?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"
android:orientation="vertical"
android:background="#878787" >
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="dfgdfgdf"
android:textSize="20dp"
android:layout_centerInParent="true"
android:id="#+id/user_name"/>
<EditText
android:id="#+id/message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:text="Gönder"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="getFromUser"
android:layout_marginTop="40dp"
/>
</RelativeLayout>
I am loading fragment with this function:
public void startChat(JsonObject user) {
FrameLayout layout = (FrameLayout)findViewById(R.id.container);
layout.setVisibility(View.VISIBLE);
Bundle bundle = new Bundle();
bundle.putString("name", user.get("name").getAsString());
sendTo=user.get("username").getAsString();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ConversationFragment conv = new ConversationFragment();
conv.setArguments(bundle);
fragmentTransaction.add(R.id.container, conv);
fragmentTransaction.commit();
viewPager.setVisibility(View.GONE);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayHomeAsUpEnabled(true);
}
And this is my fragment class
public class ConversationFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String name = getArguments().getString("name");
View rootView = inflater.inflate(R.layout.fragment_conversation, container, false);
TextView username=(TextView)rootView.findViewById(R.id.user_name);
username.setText(name);
return rootView;
}
}
As you can see when press the button main activity runs "getFromUser" function.I want to get edittext value in this function.How can I do this ?
It's always the same procedure for these things. You can't access a fragment's views just like that. You need a callback method.
Add this code to ConversationFragment:
private OnGetFromUserClickListener mListener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnGetFromUserClickListener ) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnGetFromUserClickListener");
}
}
public void getFromUser(View v) {
if (mListener != null) {
EditText edit = (EditText)findViewById(R.id.message);
mListener.getFromUser(edit.getText().toString());
}
}
public interface OnGetFromUserClickListener {
void getFromUser(String message);
}
Make your MainActivity implement this interface. Replace getFromUser() inside MainActivity with:
public void getFromUser(String message) {
sendMessage(message);
}
Done.
Edit:
Actually, using the XML-onClick attribute is currently bugged (see onClick inside fragment called on Activity): It links to the activity instead of the fragment. You have to set the click listener programmatically to make sure the code won't break at some point in the future. So give the button an ID inside the XML (e.g. get_from_user) and add this code to onCreateView inside ConversationFragment:
v.findViewById(R.id.get_from_user).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (v.getId() == R.id.get_from_user) {
getFromUser(v);
}
}
});
Using this code vastly decouples the activity and the fragment from each other.
I resolved this problem.
public void getFromUser(View view) {
ConversationFragment fragment1 = (ConversationFragment)getSupportFragmentManager().findFragmentById(R.id.container);
View frag=fragment1.getView();
EditText editText1 =(EditText) frag.findViewById(R.id.message);
String message=editText1.getText().toString();
sendMessage(message);
}
Now I can get edittext value from fragment.
I am working on Fragment-ListView and having output showing in image.
every Click changes TextView of fragment2.till now ok.
fragmetn1 is for listView and fragment2 is for DifferentView.
now i want to change layout in fragment2 with click. e.g. as item2 is clicked,a layout with textView sets in fragment2. now with selection of item3, diferent layout with Button should be set to fragment2.
my getView code is here.
public void onListItemClick(ListView l, View v, int position, long id) {
DetailFrag frag = (DetailFrag) getFragmentManager().findFragmentById(R.id.frag_detail);
if (frag != null && frag.isInLayout()) {
frag.setText("item "+position+" selected");
}
}
is there other way to do this,plz also help that way.
any suggestion would be strongly appreciated.thanks in advance.
Try the following method
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
then you need to add your fragment to this fragmentTransaction with the following syntax.
fragmentTransaction.replace(R.id.detailFragment, layout1);
And finally you MUST commit your transaction. Otherwise changes will not persist.
fragmentTransaction.commit();
In my opinion you should use different fragments with different layout and using FragmentTransaction to replace the existing one.
Your approach likely works fine, but it is probably better to use a more loosely coupled approach where the ListFragment informs the hosting activity that an item has been clicked, and then the activity tells the "other" fragment to update.
No need to worry about constructing and replacing new fragments.
Sample activity
public class TestActivity extends Activity implements TestFragmentBListener {
private TestFragmentA mOtherFragment;
private TestFragmentB mListFrag;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
mListFrag = (TestFragmentB) getFragmentManager().findFragmentById(R.id.fragment_b_list);
mOtherFragment = (TestFragmentA) getFragmentManager().findFragmentById(R.id.fragment_a_text);
}
#Override
public void onTestFragmentBItemCLicked(int position) {
// Implemented from TestFragmentB.TestFragmentBListener
mOtherFragment.setText("item " + position + " selected.");
}
}
Sample FragmentA (contains text.. this is not functional, only an example)
public class TestFragmentA extends Fragment {
public void setText(String text) {
}
}
Sample ListFragment that defines an interface for the sample activity to implement
public class TestFragmentB extends ListFragment {
private TestFragmentBListener mListener = null;
public interface TestFragmentBListener {
void onTestFragmentBItemCLicked(int position);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (TestFragmentBListener) activity;
} catch (ClassCastException ccex) {
// activity does not implement our listener
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
if (mListener != null) {
mListener.onTestFragmentBItemCLicked(position);
}
}
}
and for the sake of completeness, here was my layout for the sample activity:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TestActivity" >
<fragment
android:id="#+id/fragment_a_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<fragment
android:id="#+id/fragment_b_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/fragment_a_text" />
</RelativeLayout>