I am building an Android app using Fragments. In the XML file for one of my Fragments I simply have one ListFragment and one Button, like this (the FilteredRecipesListFragment is extending ListFragment):
<?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.mycompany.myapp.gui.FilteredRecipesListFragment
android:id="#+id/filtered_recipes_list_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true" />
<Button
android:id="#+id/show_recipe_filter_dialog_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/show_recipe_filter_dialog_button"
android:onClick="showFilter"
/>
</LinearLayout>
Fairly simple stuff. Furthermore the class FilteredRecipesFragment that is to inflate this XML file looks like this:
public class FilteredRecipesFragment extends Fragment {
private FilteredRecipesListFragment mFilteredRecipesListFragment;
private Button mShowRecipeFilterButton;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.filtered_recipes_fragment, container, false);
mFilteredRecipesListFragment = (FilteredRecipesListFragment) getFragmentManager().findFragmentById(R.id.filtered_recipes_list_fragment);
mShowRecipeFilterButton = (Button) rootView.findViewById(R.id.show_recipe_filter_dialog_button);
showRecipeFilterButton.setOnClickListener(new RecipeFilterButtonListener());
return rootView;
}
}
Should also be straightforward. The problem is at the line inflating FilteredRecipesListFragment. Here I get NoSuchMethodException: FilteredRecipesListFragment(Context, AttributeSet), because I have not implemented that constructor in my FilteredRecipesListFragment class. I am not sure why I would need that, since calling super(Context, AttributeSet) is not an option in Fragments as in Views.
And this is probably where I am heading wrong; am I approaching the whole concept of Fragments wrong in this case? Is it better practice or does it make more sense to use a ListView instead of a custom ListFragment inside another Fragment? If this is ok using the FilteredRecipesListFragment(Context, AttributeSet) method, how should I use this to make the class inflatable?
Here is my FilteredRecipesListFragment for reference:
public class FilteredRecipesListFragment extends ListFragment
{
private FilteredRecipesListAdapter mRecipeAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
mRecipeAdapter = new FilteredRecipesListAdapter(getActivity(), null);
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
#Override
public void onPause()
{
super.onPause();
}
#Override
public void onListItemClick(ListView l, View v, int position, long id)
{
super.onListItemClick(l, v, position, id);
}
}
Try looking at this.
Look at how you should declare a fragment in XML:
<fragment android:name="com.example.android.fragments.HeadlinesFragment"
android:id="#+id/headlines_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Related
I have a Video Detail Fragment which I want to behave as a bottom sheet behaviour, but unfortunately, the dialog is getting displayed at the centre of the screen. I am unable to figure out the exact problem in the code. Below I am attaching the code and the layout file, in regard to the same.
This is my Video Detail fragment:
public class VideoDetailsFragment extends BottomSheetDialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AppCompatDialog dialog = new AppCompatDialog(getActivity());
dialog.setTitle(titleId);
return dialog;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View dialogView = inflater.inflate(R.layout.video_detail_fragment, container, false);
Button cancelButton = dialogView.findViewById(R.id.track_selection_dialog_cancel_button);
Button okButton = dialogView.findViewById(R.id.track_selection_dialog_ok_button);
return dialogView;
}
public static final class TrackSelectionViewFragment extends BottomSheetDialogFragment
implements TrackSelectionView.TrackSelectionListener {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.exo_track_selection_dialog, container, /* attachToRoot= */ false);
TrackSelectionView trackSelectionView = rootView.findViewById(R.id.exo_track_selection_view);
trackSelectionView.setShowDisableOption(true);
trackSelectionView.setAllowMultipleOverrides(allowMultipleOverrides);
trackSelectionView.setAllowAdaptiveSelections(allowAdaptiveSelections);
trackSelectionView.init(mappedTrackInfo, rendererIndex, isDisabled, overrides, /* listener= */ this);
return rootView;
}
}
}
The xml file for video_detail_fragment:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="270dp"
android:visibility="visible"
app:behavior_hideable="true"
app:behavior_peekHeight="0dp"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior"
>
<FrameLayout
android:id="#+id/child_fragment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end">
</LinearLayout>
</LinearLayout>
I went through many posts but almost all the posts were showing the solution as setting the app attribute app:layout_behavior="android.support.design.widget.BottomSheetBehavior". But it's not working in my case. Kindly help me understand as to where I am doing wrong?
I have an app am working on, the app is using leak canary to detect possible memory leaks. The app seems to be fine except for my extended floating action button, according to leak canary the button is leaking, I do not have an idea on how to rectify this.
Below is my XML
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.store.StoreFragment">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/small_margin"
app:cardElevation="#dimen/normal_elevation"
app:shapeAppearanceOverlay="#style/ShapeAppearanceOverlayLargeCutLeftTopCorner">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="#+id/swipeToRefresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<androidx.core.widget.NestedScrollView
android:id="#+id/nestScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadingEdge="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ViewStub
android:id="#+id/layoutCategories"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inflatedId="#+id/panel_layoutCategories"
android:layout="#layout/store_layout_categories" />
<ViewStub
android:id="#+id/layoutDeals"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inflatedId="#+id/panel_layoutDeals"
android:layout="#layout/store_layout_deals" />
<ViewStub
android:id="#+id/layoutCollections"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inflatedId="#+id/panel_layoutCollections"
android:layout="#layout/store_layout_collections" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="#+id/btnGoToCart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:text="#string/cart"
android:textColor="#android:color/white"
android:textStyle="bold"
app:backgroundTint="#color/colorAccent"
app:elevation="#dimen/large_elevation"
app:icon="#drawable/ic_shopping_cart_24px"
app:iconTint="#android:color/white"
app:layout_anchor="#id/nestScrollView"
app:layout_anchorGravity="bottom|end"
app:shapeAppearanceOverlay="#style/ShapeAppearanceOverlayLargeCutLeftTopCorner" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
And my Java code
public class StoreFragment extends Fragment implements View.OnClickListener {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_store, container, false);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ButterKnife.bind(this, view);
btnGoToCart.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
....
case R.id.btnGoToCart:
Navigation.findNavController(v).navigate(R.id.cartFragment);
break;
....
}
}
}
Below is a snippet from leak canary. At first the leak was pointing to the ID of the coordinator layout, I removed it, now it is pointing to the Extended floating action button.
Instead of having the Fragment implement OnClickListener why not just create a new OnClickListner inner class? From what I see you ar passing the fragment as the OnClickListener and the view later holds a reference to your fragment and that's probably the cause of the leak. Just do (new OnClickListener () {}); instead of implementing OnClickListener.
EDIT:
I've just noticed that you are using ButterKnife in a Fragment.
If your using ButterKnife in a Fragment you should use:
private Unbinder unbinder;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
unbinder = ButterKnife.bind(this, view);
// TODO Use fields...
return view;
}
#Override public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
BINDING RESET Fragments have a different view lifecycle than
activities. When binding a fragment in onCreateView, set the views to
null in onDestroyView. Butter Knife returns an Unbinder instance when
you call bind to do this for you. Call its unbind method in the
appropriate lifecycle callback.
I am working on a app and it runs just fine but there is an problem that it crashes when I dont write id in my fragment code but runs fine after using id attribute and the problem is that i have not used it's id anywhere in my app
Here is the xml file
<?xml version="1.0" encoding="utf-8"?>
<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:orientation="horizontal"
>
<fragment
class="com.hfad.workout.WorkoutList"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:id="#+id/listfrag"
/>
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="second text view"
android:layout_marginTop="20dp"
android:id="#+id/fragcont"
android:layout_weight="3"
/>
</LinearLayout>
workoutlist.jav
public class WorkoutList extends ListFragment {
MainActivity ma;
static interface WorkoutListListener{
void clickme(long at);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ArrayAdapter<Workout> arrayAdapter = new ArrayAdapter<Workout>(
inflater.getContext(), android.R.layout.simple_list_item_1,
Workout.workout);
setListAdapter(arrayAdapter);
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onAttach(Context ac){
super.onAttach(ac);
this.ma =(MainActivity) getActivity();
}
public void onListItemClick(ListView v, View vi, int position, long id){
ma.clickme(id);
}
}
Before an activity can talk to its fragment, the activity first needs
to get a reference to it. To get a reference to the fragment, you first
get a reference to the activity’s fragment manager using the
activity’s getFragmentManager() method. You then use its
findFragmentById() method to get a reference to the fragment:
findFragmentById() is a
bit like findViewById()
except you use it to get a
reference to a fragment
getFragmentManager().findFragmentById(R.id.fragment_id)
It's because if you do not specify fragment id, then FragmentManager cannot restore it after recreating.
You have to specify fragment id or tag.
I guess everybody knows the project that is created when you choose "master detail flow" when creating your project in eclipse.
Theres layouts for the left side, for the right side and a two_pane layout with a fragment and a Framelayout as a fragment container. This works fine.
Now I have a 'main' activity A with a viewpager, fragments etc., and i call the activity from a fragment with the Callback. From that activity A I start a new activity B. That activity B is set up exactly like that example activity from eclipse that I just talked about.
Now I have the problem that the app crashes with
ERROR/AndroidRuntime(8105): Caused by: java.lang.IllegalArgumentException: Binary XML file line #57: Duplicate id 0x7f080024, tag null, or parent id 0x0 with another fragment for FragmentNumber3
When I replace the fragment in the two_pane layout with another framelayout, it doesn't crash.
This problem is typical for nested fragments, but I don't have nested fragments here, right? I have an activity B that, at that point, doesn't have anything to do with my activity A.
What's the problem here?
Edit: This is my Activity B:
public class SucheActivity extends FragmentActivity implements
SearchboxFragment.SearchboxListener {
private boolean mTwoPane;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.searchbox);
getActionBar().setDisplayHomeAsUpEnabled(true);
if (findViewById(R.id.searchresult_container) != null) {
mTwoPane = true;
}
}
}
And thats the two_pane layout for the activity, the searchbox should be left, the searchresults right:
<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:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:baselineAligned="false"
android:divider="?android:attr/dividerHorizontal"
android:orientation="horizontal"
android:showDividers="middle" >
<fragment
android:id="#+id/searchbox_fragment"
android:name="com.example.layouttest.SearchboxFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<FrameLayout
android:id="#+id/searchresult_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3" />
</LinearLayout>
Heres the SearchboxFragment class:
public class SearchboxFragment extends Fragment {
SearchboxListener mCallback;
View v;
public interface SearchboxListener {
public void onSearchStarted();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.searchbox, container, false);
return v;
}
}
The searchresultfragment:
public class SearchResultFragment extends Fragment {
public SearchResultFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.searchresult, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
And the refs.xml in res/values-large:
<resources>
<item name="searchbox" type="layout">#layout/haussuche_twopane</item>
</resources>
Okay, so this is what I found out:
I cant set the layout of my Activity to searchbox.xml (and have it alias'd in refs.xml with two_pane.xml) AND set the Layout of SearchboxFragment to searchbox.xml.
I thought that searchbox.xml was never shown by the Activity in two-pane-mode, I could safely set it elsewhere, but that's wrong.
What I did was copy that layout and use a searchbox_onepane.xml and searchbox_twopane.xml.
I m trying to make a simple fragment example where one fragment will show an Article List and the other will show detailed article.
This is my main activity class-
public class ArticleFragment extends Activity{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}// end class
This is the main layout file-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="com.example.ArticleList"
android:id="#+id/list"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment android:name="com.example.ArticleDetails"
android:id="#+id/viewer"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
This is my two fragment class for ArticleList and ArticleDetails
public class ArticleList extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.articlelist, container, false);
}
public class ArticleDetails extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.articledetails, container, false);
}
}
I have also TWO XML layout files(containing a textview) for both articleList, ArticleDetails fragment. But the app has stopped working. What have I missed here? Pls help thanx.
Check your Package name inside the code
<fragment android:name="com.abc.def............./>
.Thanks to you I know that we can do it.