Multiple Fragments in One Activity - android

The issue of many fragments in one activity has been covered here before, but I cannot seem to find a solution for my positioning problem.
I want a horizontal scroll bar on top of the screen and under it a custom ListFragment. The code I am posting below puts up the scroll bar and then the ListFragment overwrites it. When I try to modify the hosting FrameLayout to have two FrameLayouts I get runtime errors.
Simply, How can I position the listFragment under the scrollbar?
public class GoogleNewsMainActivity extends FragmentActivity{
public static Context c;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
c=this;
setContentView(R.layout.activity_fragment);
/* FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
if (fragment == null) {
Scroll_Menu_Fragment scrollFragment = new Scroll_Menu_Fragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, scrollFragment)
.commit();
GoogleNewsMainFragment f = new GoogleNewsMainFragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, f)
.commit();
} */
}
}
Here is the scroll bar fragment:
public class Scroll_Menu_Fragment extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
return inflater.inflate(R.layout.scrollbar_fragment, container, false);
}
#Override
public void onPause() {
// TODO Auto-generated method stub
super.onPause();
}
}
This is the ListFragment
public class GoogleNewsMainFragment extends ListFragment implements LoaderCallbacks<Cursor> {
private static final String COLUMN_ID = "id";
public final static String NEWSFROMSERVICE = "NEWSFROMSERVICE";
static ImageView thumbnail;
static String mSectionSelected;
private NewsCursor mCursor;
private ListView lv;
private NewsCursorAdapter adapter;
public static final String ID = "id";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
mSectionSelected = ""; // until they select one
getLoaderManager().initLoader(0, null, this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_google_news_main, container, false);
getActivity().setTitle(R.string.news_list_title);
return v;
}
And finally the hosting layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragmentContainer"
android:baselineAligned="false"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<fragment
android:id="#+id/scrollFragment"
android:layout_width="fill_parent"
android:layout_weight="10"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
class="com.gilchrist.android.googlenews.Scroll_Menu_Fragment" ></fragment>
<fragment
android:id="#+id/listFragment"
android:layout_width="fill_parent"
android:layout_weight="90"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
class="com.gilchrist.android.googlenews.GoogleNewsMainFragment" ></fragment>
</LinearLayout>

I just updated the activity layout. The problem was caused by the weight values I was using. By going to 90 and 10 I got exactly what I wanted. All of the code above now works.

Related

Sending data from Fragment to Fragment using Interface, by setting Fragment Layouts dynamically. Saved instance of Fragment NOT working

I am sending data from one fragment to another, using interface. This works absolutely fine. Now I am trying to use onSaveInstanceState() to save the value in
a Fragment and retrieving in onCreate(). however i'm getting null in Bundle of onCreate(). P.S. everything works fine when i set the Fragment directly into the activity layout in xml. but when i set the fragment through java code into the activity, the onSaveInstanceState is failing. It is not saving the last known value. Please help. Pasting the code below. You can try it out to know the exact issue.
Fragment_A :
public class Fragment_A extends Fragment implements View.OnClickListener {
Button btnAdd;
int counter = 0;
Communicator comm;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null){
counter = savedInstanceState.getInt("counter", 0);
}
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_a, container, false);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
comm = (Communicator) getActivity();
btnAdd = (Button) getActivity().findViewById(R.id.btnAdd);
btnAdd.setOnClickListener(this);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("counter", counter);
}
#Override
public void onClick(View v) {
counter++;
comm.sendData(counter);
}
}
interface Communicator{
void sendData(int i);
}
=====
Activity :
public class Activity_InterComm extends Activity implements Communicator{
FragmentManager manager;
FragmentTransaction transaction;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intercomm);
Fragment_A fragment_1 = new Fragment_A();
Fragment_B fragment_2 = new Fragment_B();
manager = getFragmentManager();
transaction = manager.beginTransaction();
transaction.add(R.id.frag_a, fragment_1, "Frag1");
transaction.add(R.id.frag_b, fragment_2, "Frag2");
transaction.commit();
}
#Override
public void sendData(int i) {
manager = getFragmentManager();
Fragment_B fragment_b = (Fragment_B) manager.findFragmentById(R.id.frag_b);
fragment_b.setData("Button has been clicked " + i + " times");
}
}
=====
Fragment_B :
public class Fragment_B extends Fragment {
TextView txtMessage;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_b, container, false);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
txtMessage = (TextView) getActivity().findViewById(R.id.txtMessage);
}
public void setData(String message){
txtMessage.setText(message);
}
}
activity_intercomm.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">
<!--<fragment
android:id="#+id/frag_a"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_weight="1"
android:name="android.learning.com.fragintercomm.Fragment_A"/>
<fragment
android:id="#+id/frag_b"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:name="android.learning.com.fragintercomm.Fragment_B"/>-->
<LinearLayout
android:id="#+id/frag_a"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_weight="1"
android:background="#color/colorAccent"
android:orientation="vertical"/>
<LinearLayout
android:id="#+id/frag_b"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_weight="1"
android:background="#color/colorPrimaryDark"
android:orientation="vertical"/>
</LinearLayout>
the soluion I found was using getView() instead of getActivity() while initializing the button in Fragment_A. use btnAdd = (Button) getView().findViewById(R.id.btnAdd); instead of btnAdd = (Button) getActivity().findViewById(R.id.btnAdd);.
However, you can't use getView() in Fragment_B. The Textview freezes and, onSaveInstanceStat() doesn't work. Please suggest a solution.

Layout for tablets using two fragments

I am doing a sample project as an excercise and want to display two fragments in the same activity when dealing with tablets(7' and 10').
So what I have so far is this.
As you can see I can display the data of my recyclerview in the left (static) fragment. However the right fragment is empty.
So I have two questions.
1) How to display by default in the right fragment the data of the first row of recyclerview?(ie image and article)
2) How to implement the click listener and update the right fragment?
Here is my code:
MainActivity
public class MainActivity extends AppCompatActivity {
private boolean mTwoPane;
private static final String DETAIL_FRAGMENT_TAG = "DFTAG";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(findViewById(R.id.detailed_match_reports)!=null) {
mTwoPane = true;
if (savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.detailed_match_reports, new DetailedActivityFragment(),DETAIL_FRAGMENT_TAG)
.commit();
}else{
mTwoPane = false;
}
}
}
}
layout/activity_main.xml
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/match_reports"
android:name="theo.testing.androidservices.fragments.MainActivityFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
tools:context="theo.testing.androidservices.activities.MainActivity"
tools:layout="#android:layout/list_content" />
layout-sw600dp/activity_main
<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"
android:baselineAligned="false"
android:divider="?android:attr/dividerHorizontal"
android:orientation="horizontal"
tools:context="theo.testing.androidservices.activities.MainActivity">
<fragment
android:id="#+id/match_reports"
android:name="theo.testing.androidservices.fragments.MainActivityFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
tools:layout="#android:layout/list_content" />
<FrameLayout
android:id="#+id/detailed_match_reports"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="4" />
</LinearLayout>
MainActivityFragment
public class MainActivityFragment extends Fragment {
public static final String TAG = "AelApp";
public static ArrayList<MyModel> listItemsList;
RecyclerView myList;
public static MatchReportsAdapter adapter;
public MainActivityFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
updateMatchReport();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
getActivity().setTitle("Match Report");
View rootView = inflater.inflate(R.layout.fragment_main_activity, container, false);
listItemsList = new ArrayList<>();
myList = (RecyclerView)rootView.findViewById(R.id.listview_match_reports);
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
myList.setHasFixedSize(true);
myList.setLayoutManager(linearLayoutManager);
adapter = new MatchReportsAdapter(getActivity(), listItemsList);
myList.setAdapter(adapter);
return rootView;
}
public void updateMatchReport(){
Intent i = new Intent(getActivity(), MatchReport.class);
getActivity().startService(i);
}
}
First let me answer the second question. To show a fragment on the right side of the screen add something like this (note how I'm using that id of the frame layout to replace the fragment):
Fragment fragment = new MyRightSideFragment();
FragmentManager fm = getFragmentManager();
fm.beginTransaction().replace(R.id.detailed_match_reports, fragment).commit();
Now, for the first question, you need to implement click listener, you can find an example here.
public class ReactiveAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = (Integer)v.getTag();
showDetail(position);
}
});
}
}
Notice that I'm using the tag of the view to identify the position (so somwhere in your onBindViewHolder code you must set this tag).
public function showDetail(int position) {
... show fragment por position
}
and finally, when your in your OnCreateView or somewhere in your setup code, call showDetail(0).

recreate view of fragment via button

I've got a FragmentActivity which show the correct fragment, using a ViewPager. I added a Fragment StatePagerAdapter to the ViewPager. If I push a button at a Fragment, it should be recreated (onCreateView should be called again). The fragments are articles and if the user is offline, I'll show him "please check your networkconnection" and a button to reload. The button called a method in the FragmentActivity, but I don't know how implement it. Maybe I can destroy and recreate the current Fragment?
here the important part of the FragmentActivity:
private ArrayList<Fragment> fragments;
protected void onCreate(Bundle savedInstanceState)
{
context = this;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_article_page_slider);
...
pages = datahandler.getCount(...);
viewPager = (ViewPager) findViewById(R.id.articlePager);
PagerAdapter pagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager());
viewPager.setAdapter(pagerAdapter);
viewPager.setCurrentItem(startPosition);
fragments = new ArrayList<Fragment>(pages);
}
public void reloadData(View v)
{
// TODO
((ArticlePageFragment)fragments.get(viewPager.getCurrentItem())).refresh();
}
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter
{
public ScreenSlidePagerAdapter(FragmentManager fm)
{
super(fm);
}
#Override
public Fragment getItem(int position)
{
Fragment fragment = new ArticlePageFragment();
Bundle args = new Bundle();
...
fragment.setArguments(args);
fragments.add(position, fragment);
return fragment;
}
public int getCount()
{
return pages;
}
}
and the Fragment itself:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
activity = getActivity();
ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.fragment_article_page, container, false);
CacheDataHandler cdh = new CacheDataHandler(activity);
cdh.open();
String htmlData = cdh.loadData();
rootView.findViewById(R.id.btn_reload_article_data).setVisibility(View.GONE);
webView = ((WebView) rootView.findViewById(R.id.articleFragment));
refresh();
...
return rootView;
}
public void refresh()
{
...
if (htmlData == null)
{
rootView.findViewById(R.id.btn_reload_article_data).setVisibility(View.VISIBLE);
webView.loadData(defaultdata,"text/html", "UTF-8");
}
else
{
webView.loadData(htmlData,"text/html", "UTF-8");
}
}
and the fragment_article_page.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<WebView
android:id="#+id/articleFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<Button
android:id="#+id/btn_reload_article_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:onClick="reloadData"
android:text="#string/btn_txt_reload_data"
android:visibility="gone" />
</RelativeLayout>
EDIT
added a private ArrayList<Fragment> fragments in FragmentActivity and transfer the code for manipulating the view in an extra refreshMethod, look ahead. All works fine, if I only click on the first or second Fragment (index 0 and 1). Otherwise I get an IndexOutOfBoundsException. How to initialize and fill the ArrayList?

Using findFragmentById with a ViewPager

My app has a list and detail view, where I allow the user to swipe between the different detail views, using a ViewPager in portrait. In landscape, I show both fragments on the screen.
I'm having an issue where, when the device is rotated, the icons are duplicating themselves over and over in the Actionbar. I've learned that I'm probably creating new fragments whenever the device is rotated and I should be checking if the fragment is in the FragmentManager and then create a new instance if it isn't.
I am able to do that easily using the landscape layout, however, I'm not sure how to check if the fragment exists in portrait mode, using the ViewPager. Do I do that in getItem() of the FragmentStatePagerAdapter?
This is the code I'm using:
public class Main extends SherlockFragmentActivity
{
private static List<Integer> mIds;
#Override
public void onCreate(final Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.main);
mViewPager = (ViewPager)findViewById(R.id.viewpager); //view pager exists, so we are using the portait layout
if (mViewPager != null)
{
mIds = new ArrayList<Integer>();
mIds.add(0);
mIds.add(1);
mIds.add(2);
}
else //in landscape
{
ListFragment lf = (ListFragment)getSupportFragmentManager().findFragmentById(R.id.fragmentList);
if (lf == null)
lf = new ListFragment();
DetailFragment df = (DetailFragment)getSupportFragmentManager().findFragmentById(R.id.fragmentDetail);
if (df == null)
{
df = new DetailFragment();
df.setArguments(getIntent().getExtras());
}
getSupportFragmentManager().beginTransaction().add(R.id.fragmentList, lf).commit();
getSupportFragmentManager().beginTransaction().add(R.id.fragmentDetail, df).commit();
}
}
private static class MyFragmentPagerAdapter extends FragmentStatePagerAdapter {
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
//can't use getSupportFragmentManager().findFragmentById() here because I get a "Cannot make a static reference to the non-static method" error
if (index == 0)
return ListFragment.newInstance();
else
return DetailFragment.newInstance(mIds.get(index-1));
}
#Override
public int getCount() {
return 4;
}
}
}
Main Layout (portrait)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="fill_parent"
android:layout_width="fill_parent">
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_height="match_parent"
android:layout_width="match_parent"
/>
</RelativeLayout>
Main Layout (landscape)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:weightSum="3"
>
<FrameLayout
android:id="#+id/fragmentList"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="fill_parent"
/>
<FrameLayout
android:id="#+id/fragmentDetail"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="fill_parent"
/>
</LinearLayout>
List Fragment
public class ListFragment extends SherlockListFragment implements DialogKeywordAddListener
{
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
public static ListFragment newInstance() {
return new ListFragment();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
return inflater.inflate(R.layout.listing, container, false);
}
}
Detail Fragment
public class DetailFragment extends SherlockListFragment
{
private int mId;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
public static DetailFragment newInstance() {
DetailFragment df = new DetailFragment();
Bundle bundle = new Bundle();
bundle.putInt("id", id);
df.setArguments(bundle);
return df;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
if (getArguments() != null)
mId = getArguments().getInt("id");
return inflater.inflate(R.layout.detail, container, false);
}
}
Well, this question's solution seemed to work for me. Just setting:
super.onCreate(null);
in onCreate of the Activity solved my fragment issue.

achartengine: How to add chart to fragment in Tabs

I want to show a Button and a PieChart below in a tab.
Thats the code I worked with: https://github.com/JakeWharton/ActionBarSherlock/blob/master/samples/fragments/src/com/actionbarsherlock/sample/fragments/FragmentTabs.java
Instead of the CountingFragment etc. I implemented my own.
I'm not sure what to
My xml:
fragment_graph_categories.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_graph_categories"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/button_filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/button_filter" />
</LinearLayout>
And that's my "Tab" attached to the TabManger
public class GraphCategories extends SherlockFragmentActivity {
GraphCategoriesFragment mCategoriesFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_graph_categories);
if (savedInstanceState == null) {
// Do first time initialization -- add initial fragment.
mCategoriesFragment = GraphCategoriesFragment.newInstance(1);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.fragment_graph_categories, mCategoriesFragment).commit();
} else {
//mStackLevel = savedInstanceState.getInt("level");
}
}
#Override
protected void onResume() {
if(mCategoriesFragment != null) {
//mCategoriesFragment.onResumeRedraw();
}
}
//notice Inner class
public static class GraphCategoriesFragment extends SherlockFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//View mChartView = inflater.inflate(R.layout.hello_world, container, false);
View rlayout = inflater.inflate(R.layout.fragment_graph_categories, container, false);
//? rlayout = new LinearLayout(getActivity());
return rlayout;
}
}
}
But im not sure what to inflate at the fragments onCreateView or if I need a FrameLayout in my xml?
I tried some options but don't figured it out.

Categories

Resources