I have a BaseActivity that contains this structure:
<!-- activity_base -->
<?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:id="#+id/container_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<include
layout="#layout/tool_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<include
layout="#layout/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/tool_bar"
android:layout_above="#id/bottom_navigation" />
<android.support.design.widget.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:menu="#menu/bottom_navigation_menu" />
</RelativeLayout>
In my BaseActivity I'm controlling the BottomNavigationView. And I created several Activities where I would like to take advantage of the include content and load only the contents of that activity.
Today the project is using butterknife Java. And the project is getting giant because it is replicating the top structure of the BaseActivity for each sub activity. I would like to refactor (in the best and quickest possible way) the project so that there is only one
activity_base.xml and other activities control only its content (content.xml).
I saw something using ViewStub and another describing <merge> but I did not understand how to apply the concepts easily in the project since many use activity and fragment, my project is only with activities.
I'm not completely happy with this solution but I ended up with something like that working on a similar case:
base_activity.xml
<...>
..... Whatever you want at the top
<.../>
<!-- Container where your child Activity layout will be inflated -->
<FrameLayout
layout="#+id/child_activity_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<...>
..... Whatever you want at the bottom
<.../>
BaseActivity
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base);
ViewGroup parent = findViewById(R.id.child_activity_container);
View childView = inflateChildLayout(LayoutInflater.from(this), parent);
// The child Activity can have no layout (for some reason)
if (childView != null) {
parent.addView(childView);
}
ButterKnife.bind(BaseActivity.this);
// ... the rest of your onCreate
}
#Nullable
protected abstract View inflateChildLayout(LayoutInflater inflater, ViewGroup parent);
ChildActivity
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(...); // Already managed by the base Activity so we don't need it
}
#Override
protected View inflateChildLayout(LayoutInflater inflater, ViewGroup parent) {
return inflater.inflate(R.layout.activity_child, parent, false);
}
The idea is the BaseActivity manage the inflation of the child layout inside its own layout and manage the call to ButterKnife. As the parent and the child are in reality the same instance (as ChildActivity extends BaseActivity) ButterKnife both the parent and the child Views. That's why it's called after the call to inflateChildLayout
Related
I am using a base activity as a parent of another activity "RecicpeActivity" as I have overridden the method setContentView in the base activity so that the child activity can use it and pass its layout to be inflated in the frame layout.
The Child activity "RecicpeActivity" uses DataBinding to set its views.
What I am doing is I am trying to inflate the layout of the child activity into a frame layout "container" in the base activity BUT the data binding is not being considered at all as I am having a white screen even though I have seen the layout of the child activity as a child of the frame layout while debugging.
I have tried two ways:
1- The first one I have tried to pass the layout of the child activity simply by calling setContentView and inflated the passed layout to the frame layout in the base activity.
2- The second on I have tried to use data binding in the base activity, But I don't think it would matter.
_ChildActivity
public class RecipeActivity extends BaseActivity {
private ActivityRecipeBinding mBinding;
private static final String RECIPE_INTENT_KEY = "recipe key";
private ScrollView mScrollView;
private RecipeViewModel recipeViewModel;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
recipeViewModel =
ViewModelProviders.of(this).get(RecipeViewModel.class);
mBinding = DataBindingUtil.inflate(
getLayoutInflater(),
R.layout.activity_recipe, null, false);
setContentView(R.layout.activity_recipe);
// This method is implemented in the BaseActivity.
showProgressBar(true);
recipeViewModel.getRecipe().observe(this, new Observer<Recipe>() {
#Override
public void onChanged(Recipe recipe) {
if (recipe != null){
if (recipe.getRecipe_id().equals(
recipeViewModel.getRecipeId())){
mBinding.setRecipe(recipe);
mScrollView.setVisibility(View.VISIBLE);
showProgressBar(false);
}
}
}
});
recipeViewModel.getRecipeById(getIncomingIntentRecipeId());
}
private String getIncomingIntentRecipeId(){
if (getIntent().hasExtra(RECIPE_INTENT_KEY)){
String recipe_id = getIntent().getStringExtra(RECIPE_INTENT_KEY);
return recipe_id;
}
return null;
}
_BaseActivity
public abstract class BaseActivity extends AppCompatActivity {
public ProgressBar mProgressBar;
#Override
public void setContentView(int layoutResID) {
RelativeLayout mRelativeLayout =
(RelativeLayout) getLayoutInflater().inflate(
R.layout.activity_base, null);
FrameLayout frameLayout = mRelativeLayout.findViewById(
R.id.activity_content);
mProgressBar = mRelativeLayout.findViewById(R.id.progress_bar)
/**
* True means layoutResID should be inflated and made a part of
parent frameLayout
*/
getLayoutInflater().inflate(layoutResID, frameLayout, true);
super.setContentView(mRelativeLayout);
}
public void showProgressBar(boolean visibility){
mProgressBar.setVisibility(visibility ?
View.VISIBLE : View.INVISIBLE);
}
_ChildActivity Layout "activity_recipe"
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="recipe"
type="com.mustafa.foodapp.models.Recipe" />
<import type="com.mustafa.foodapp.util.StringUtils" />
</data>
<ScrollView
android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/recipe_image"
android:layout_width="match_parent"
android:layout_height="#dimen/recipe_image_height"
android:scaleType="center"
app:imageUrl="#{recipe.image_url}" />
<TextView
android:id="#+id/recipe_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/recipe_image"
android:padding="7dp"
android:text="#{recipe.title}"
android:textColor="#000"
android:textSize="#dimen/recipe_title_text_size" />
<LinearLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/recipe_title"
android:orientation="horizontal"
android:padding="10dp"
android:weightSum="100">
<TextView
android:id="#+id/recipe_social_score"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="10"
android:gravity="center"
android:text="#{String.valueOf(
Math.round(recipe.social_rank))}"
android:textColor="#color/red"
android:textSize="#dimen/
recipe_publisher_text_size"/>
</LinearLayout>
<LinearLayout
android:id="#+id/ingredients_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/container"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{StringUtils.getStringIngredients(
recipe.ingredients)}" />
</LinearLayout>
</RelativeLayout>
</ScrollView>
</layout>
_BaseActivity Layout "activity_base"
<?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"
android:id="#+id/base_relative_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/activity_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<ProgressBar
android:id="#+id/progress_bar"
style="#style/Widget.AppCompat.ProgressBar"
android:layout_width="125dp"
android:layout_height="125dp"
android:layout_centerInParent="true"
android:visibility="gone" />
</RelativeLayout>
_BaseActivity with data-binding "2nd way"
public abstract class BaseActivity extends AppCompatActivity {
public ProgressBar mProgressBar;
public ActivityBaseBinding baseBinding;
#Override
public void setContentView(int layoutResID) {
baseBinding = DataBindingUtil.inflate(
getLayoutInflater(), R.layout.activity_base, null, false);
mProgressBar = baseBinding.progressBar;
/**
* True means layoutResID should be inflated and made a part of the
parent frameLayout
*/
getLayoutInflater().inflate(layoutResID, baseBinding.activityContent,
true);
super.setContentView(baseBinding.getRoot());
}
public void showProgressBar(boolean visibility){
mProgressBar.setVisibility(visibility ?
View.VISIBLE : View.INVISIBLE);
}
Call layout.requestLayout() after inflating so it can adjust to the changes made after inflating.
getLayoutInflater().inflate(layoutResID, baseBinding.activityContent, true);
mRelativeLayout.requestLayout();
super.setContentView(baseBinding.getRoot());
public void requestLayout ()
Call this when something has changed which has invalidated the layout of this view. This will schedule a layout pass of the view tree.
If you can see the child in view heirarchy while debugging, then this should fix the issue.
https://developer.android.com/reference/android/view/View.html#requestLayout()
PART 2: Binding Doesn't work
You are inflating view two times, once in your child activity, and once in your BaseActivity:
mBinding = DataBindingUtil.inflate(
getLayoutInflater(),
R.layout.activity_recipe, null, false);
setContentView(R.layout.activity_recipe);
mBinding You inflated once for databinding, then you passed layout id to setContentView where it inflated again:
getLayoutInflater().inflate(layoutResID, frameLayout, true);
So the one in Databinding is a different view from the one you added to base layout.
Create an Overloaded version of setContentView that accepts view instead of id.
I am trying to create image move transition from recycle view to fragment. But the problem is that after the transition image is displayed in the new the move animation doesn't happen it just fades in with the rest of the content. What could I be doing wrong. I was following this example:
http://mikescamell.com/shared-element-transitions-part-4-recyclerview/
I have recycle view item layout with image view:
<?xml ...?>
<layout ...>
<data>
<variable name="model" type="..."/>
</data>
<LinearLayout ...>
<FrameLayout ...>
<ImageView android:id="#+id/image" .../>
</FrameLayout>
<LinearLayout ...>
...
</LinearLayout>
</LinearLayout>
</layout>
And then I have a fragment layout to which I want to move the image from recycle view.
<FrameLayout ...>
<TextView .../>
<ImageView android:id="#+id/logo" >
</FrameLayout>
Here's recycle my view onBindViewHolder method
#Override
public void onBindViewHolder(RecycleViewAdapter.ViewHolder holder, int position) {
final T object = getItem(position);
holder.getBinding().setVariable(BR.model, object);
holder.getBinding().executePendingBindings();
ViewCompat.setTransitionName(holder.getBaseView().findViewById(R.id.logo), "wb_logo");
holder.getBaseView().setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onItemClickListener.onItemClick(view, object);
}
});
}
Here's recycle view item click handler in my main activity
#Override
public void onFragmentItemClick(View view, Object object) {
PreviewFragment fragment = PreviewFragment.newInstance(Object.imageId, "");
getFragmentManager()
.beginTransaction()
.addSharedElement(view.getRootView().findViewById(R.id.logo), "wb_logo")
.addToBackStack(null)
.replace(R.id.fragment_container, fragment)
.commit();
}
In my fragment class in which I wan't to animate image I have following setup:
#Override
public void onCreate(Bundle savedInstanceState) {
...
setSharedElementEnterTransition(
TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.move));
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ImageView imageView = view.findViewById(R.id.logo);
imageView.setTransitionName("wb_logo");
imageView.setImageResource(...);
}
I tried statically adding transitionName attribute to image views but the result was same.
Edit
Maybe there is something wrong with my general layout. My fragment container is in a DrawerLayout
<android.support.v4.widget.DrawerLayout ...>
<android.support.design.widget.CoordinatorLayout ...>
<android.support.design.widget.AppBarLayout ...>
<android.support.v7.widget.Toolbar ... />
</android.support.design.widget.AppBarLayout>
<FrameLayout android:id="#+id/fragment_container" .../>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView .../>
</android.support.v4.widget.DrawerLayout>
Or fragment class I am using I am using
android.app.Fragment
instead of
android.support.v4.app.Fragment
within
android.support.v7.app.AppCompatActivity
I figured out what was my problem: I had multiple items in recycle view which all had ImageView inside them with android:transitionName="wb_logo".
I somehow missed the point that each shared item in recycle view must have a unique transitionName. when I modified transitionName to include id suffix it started working as intended.
android:transitionName="wb_logo_1"
android:transitionName="wb_logo_2"
Try setting the transition name in xml rather than JAVA side. I think it might not be working because you are setting it when the view is already created.
<ImageView
android:id="#+id/ivItem"
android:transitionName="wb_logo"
android:layout_width="match_parent"
android:background="#android:color/holo_blue_bright"
android:scaleType="centerCrop"
android:layout_height="wrap_content" />
The above would be in your item in your recycler view.
<ImageView
android:id="#+id/wb_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:transitionName="wb_logo" />
The above would then be in your fragment
Your start fragment code is correct
I'm using StarWarsEaxmple from MvvmCross repository and I can't make it work. The output of MvvmCross ,The problem in my opinion is either in different versions of MvvmCross or in Presenter. In Samples version is 5.1.1 and in my project is 5.4.2. And demonstrates weird behavior.
I can see empty drawer when I don't involve MvvmCross NavigationService. However, when I navigating to both ViewModels sequently (as in the example) I can see only Menu Page without drawer and other page frame is even doesn't invoked.
Reference to MvvmCross Sample
Main Activity
[Activity(Icon = "#drawable/icon",
Theme = "#style/AppTheme", LaunchMode = LaunchMode.SingleTop,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : MvxCachingFragmentCompatActivity<MainViewModel>
{
public DrawerLayout DrawerLayout;
//This method is invoked
protected override void OnCreate(Bundle bundle)
{ base.OnCreate(bundle);
SetContentView(Resource.Layout.activity_main);
DrawerLayout = FindViewById<DrawerLayout>(Resource.Id.drawerLayout);
ViewModel.ShowDefaultMenuItem();
}
....
Menu Fragment
[MvxFragment(typeof(MainViewModel), Resource.Id.navigationFrame)]
[Register("VacationManager.Droid.Activities.MenuFragment")]
public class MenuFragment : MvxFragment<MenuViewModel>, NavigationView.IOnNavigationItemSelectedListener
{
private NavigationView _navigationView;
private IMenuItem _previousMenuItem;
//This method is invoked too
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
var view = this.BindingInflate(Resource.Layout.menu_view, null);
_navigationView = view.FindViewById<NavigationView>(Resource.Id.navigation_view);
_navigationView.SetNavigationItemSelectedListener(this);
return view;
}
}
Main Part of Page
[MvxFragment(typeof(MainViewModel), Resource.Id.bodyFrame, false)]
[Register("VacationManager.Droid.Activities.VacationRequestListFragment")]
public class VacationRequestListFragment : BaseFragment<VacationRequestListViewModel> // You can find BaseFragment in sample
{
protected override int FragmentId => Resource.Layout.fragment_list;
//It is never invoked
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
return this.BindingInflate(Resource.Layout.fragment_list, container, false);
}
}
MainPage Layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/warning">
<!-- Center Side -->
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/mainFrame">
<include layout="#layout/toolbar" />
<FrameLayout
android:id="#+id/bodyFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"/>
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="16dp"
android:src="#drawable/bullseye"
local:layout_anchor="#id/bodyFrame"
local:layout_anchorGravity="bottom|right|end" />
</android.support.design.widget.CoordinatorLayout>
<!-- Left Side -->
<FrameLayout
android:id="#+id/navigationFrame"
android:layout_height="match_parent"
android:layout_width="240dp"
android:layout_gravity="left|start"
android:clickable="true" />
</android.support.v4.widget.DrawerLayout>
MainPage Layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.NavigationView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="#+id/navigation_view"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_gravity="start"
android:fitsSystemWindows="true"
android:theme="#style/ThemeToolbarNavigationView"
android:background="#color/colorPrimary"
local:itemTextColor="#color/light_gray"
local:itemIconTint="#color/light_gray"
local:headerLayout="#layout/navigation_header"
local:menu="#menu/navigation_drawer" />
Main ViewModel
public void ShowDefaultMenuItem()
{
NavigationService.Navigate<VacationRequestListViewModel>();
NavigationService.Navigate<MenuViewModel>();
}
Seems I'm losing small detail... Any help would be appreciated.
The problem was first of all in namespaces of attributes over the activities. They should be MvvmCross.Droid.Views.Fragments . And also instead of MvxFragmentAttribute we need to use MvxFragmentPresentationAttribute. Then it works.
I tried changing the background color of a fragment, but a small problem occurred.
public class MainActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
So, shown above is the code I had for my main class that calls the XML file for the fragment.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<fragment
android:id="#+id/fragment1"
android:name="com.northreal.practice.FirstFragment"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#CBA" />
</LinearLayout>
Above is the main.xml layout that is called by the main class (MainActivity).
public class FirstFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.main, parent, false);
}
}
Above the XML file with the fragment calls this class.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
>
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="BLAHHHH"
android:layout_gravity="center_vertical" />
</LinearLayout>
This layout above is inflated by the class FirstFragment
So, why doesn't this actually change the color of the background of my fragment?
Fragments don't inherit from View and thus don't have a set background method.
Any easy fix is to just grab the root view of fragment and set its background
fragment.getView().setBackgroundColor(Color.WHITE);
The reason why that doesn't work is because fragment is treated similar to an activity. It is a container that is the child of the main activity, and is used to display other items.
You need to put the android:background="#CBA" in the actual layout that holds the TextView and NOT the fragment itself.
Like so:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#CBA"
android:orientation="horizontal" >
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="BLAHHHH" />
</LinearLayout>
Get the fragment object like:
Fragment fragment = (Fragment) getFragmentManager().findFragmentById(R.id.fragmentId);
Change it's background like:
fragment.getView().setBackgroundColor(Color.WHITE);
In AndroidX you can use a FragmentContainerView instead of a Fragment to set a background:
<androidx.fragment.app.FragmentContainerView
...
android:background="#FFFFFF"/>
I have faced the same problem but my requirement was to set or change background drawable image of fragment. As Adam answered the approach is right and I would like to show the connection from fragment to activity.
The best practice is to use an interface named 'Connector'(or any name).Then from your fragment:
Connector connector = (Connector) getActivity();
connector.setIt(this);
Then in your activity which will implement 'Connector' interface and have the method.
#Override
public void setIt(Fragment fragment){
FirstFragment firstFrag = (FirstFragment) getSupportFragmentManager().findFragmentByTag("first");
firstFrag.getView().setBackgroundDrawable(getResources().getDrawable(R.drawable.app_background));
//or for color set
firstFrag.getView().setBackgroundColor(Color.WHITE);
}
This is related to several posts, but I don't see anything that explains the order of view creation in the view hierarchy (static - xml and dynamic - in code).
I have a FragmentActivity hosting an Activity and a Fragment. I'm getting a runtime error from a view not being created for the fragment before the fragment's onCreateView is called. It's difficult to determine what the calling method is that can't find the view as the debugger can't seem to find the right line-numbers during step-through.
I can't get the source to attach correctly to see inside FragmentManager as there seems to be a mismatch between the dl'd source and .jar
I placed a Log.i entry in StreamingActivity.onCreateView and the error occurs before that.
Here is the relevant LogCat:
07-19 10:13:36.091: I/StreamingActivity(9886): onCreate
07-19 10:13:42.271: W/dalvikvm(9886): threadid=1: thread exiting with uncaught exception (group=0x40020560)
07-19 10:13:42.281: E/AndroidRuntime(9886): FATAL EXCEPTION: main
07-19 10:13:42.281: E/AndroidRuntime(9886): java.lang.RuntimeException: Unable to start activity
ComponentInfo{kesten.fragmentstestbed/kesten.fragmentstestbed.FragmentsMainActivity}:
java.lang.IllegalArgumentException: No view found for id 0x7f05002e for fragment
StreamingActivity{4052f810 #0 id=0x7f05002e}
caused by
java.lang.IllegalArgumentException: No view found for id 0x7f05002e for fragment
StreamingActivity{40530948 #0 id=0x7f05002e}
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:865)
my java file snippets:
public class FragmentsMainActivity extends FragmentActivity {
public final static int STARTUP_ACTIVITY_RESULT=0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragments_main);
if(savedInstanceState == null) {
Intent intentStartupActivity = new Intent(this, StartupActivity.class);
if(intentStartupActivity != null)
startActivityForResult(intentStartupActivity, STARTUP_ACTIVITY_RESULT);
// get an instance of FragmentTransaction from your Activity
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
//add a fragment
StreamingActivity streamingActivity = new StreamingActivity();
if (streamingActivity != null) {
fragmentTransaction.add(R.id.streamingactivity, streamingActivity);
fragmentTransaction.commit();
}
}
}
my Fragment:
public class StreamingActivity extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("StreamingActivity","onCreate")
}
my layout files:
"res/layout/main.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"
>
<FrameLayout
android:id="#+id/streamingactivity"
android:layout_width="0px"
android:layout_height="match_parent">
</FrameLayout>
<!-- IMU -->
<TextView
android:id="#+id/imu_label"
style="#style/Label.Title"
android:text="#string/imu"
/>
<kesten.fragmentstestbed.ImuView
android:id="#+id/imu_values"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/imu_label"
android:text=""
/>
<!-- Accelerometer -->
<TextView
android:id="#+id/accelerometer_label"
style="#style/Label.Title"
android:text="#string/accelerometer"
android:layout_below="#+id/imu_values"
/>
<!-- Filtered -->
<kesten.fragmentstestbed.CoordinateView
android:id="#+id/accelerometer_filtered_coordinates"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/accelerometer_label"
android:text="#string/filtered"
/>
</RelativeLayout>
and "activity_fragments_main.xml" for my FragmentActivity
<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" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:padding="#dimen/padding_medium"
android:text="#string/hello_world"
tools:context=".FragmentsMainActivity" />
</RelativeLayout>
Possible causes of id not found error gleaned from other Stackoverflow threads:
wrong layout in setContentView() of the onCreate() method of the FragmentActivity.
I checked and my xml files are all there. Maybe there's a syntax error or missing linked resource, but i can't see it. I understand the HierarchyViewer would be a useful tool to debug the UI, but i can't get it working.
the id passed into FragmentTransaction.add must be a child of the layout specified in setContentView.
my FragmentActivity's onCreate
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragments_main);
my Fragment's onCreateView
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.i("StreamingActivity","onCreateView");
View view = inflater.inflate(R.layout.main, container, false);
I presume that the LayoutManager passes the correct value for container, i.e., the one set in FragmentActivity's setContentView(). But we never make it there anyway. The error in the logCat occurs before we enter onCreateView().
The only thing i can think of atm is that the startupActivity (which is closed third party) called after setContentView and before StreamingActivity sets the content view to something besides R.layout.activity_fragments_main which is not a parent of my fragment's view.
The problem seems to stem from the fact that while Activity has setContentView which can be called whenever, Fragment only has onCreateView() which gets called after fragment transactions that start the fragment.
Why and what is trying to access the fragment's view before onCreateView() is called?
darKoram
The TextView in activty_fragments_main has no id. I ran into a similar error, and added an id, and all of a sudden things started working...
the following FrameLayout should be in activty_fragments_main
<FrameLayout
android:id="#+id/streamingactivity"
android:layout_width="0px"
android:layout_height="match_parent">
</FrameLayout>
the below function adds a fragment inside the layout provided in the first aurgument:
fragmentTransaction.add(R.id.streamingactivity, streamingActivity);
So try changing:
<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" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:padding="#dimen/padding_medium"
android:text="#string/hello_world"
tools:context=".FragmentsMainActivity" />
</RelativeLayout>
to:
<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" >
<FrameLayout
android:id="#+id/streamingactivity"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</RelativeLayout>
In FragmentMainActivity you are adding fragment to to id streamingactivity
fragmentTransaction.add(R.id.streamingactivity, streamingActivity);
and "activity_fragments_main.xml" for my FragmentMainActivity
<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" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:padding="#dimen/padding_medium"
android:text="#string/hello_world"
tools:context=".FragmentsMainActivity" />
</RelativeLayout>
//your layout must contains a FrameLayout with id streamingactivity .you Activity must contains
<FrameLayout
android:id="#+id/streamingactivity"
....
..>
And your StreamingActivity which is a Fragment must import android.support.v4.Fragment. And must implement onCreateView
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.main, container, false);
}
Or One more problem may be . Your have interchanged the LayoutId of Fragment and Activity. As your names look like