Data binding "error: cannot find symbol class Models" - java

First, I need to acknowledge the clearly very similar but not duplicate issue here. None of the proposed solutions in that thread work.
My application file structure is as follows:
app
java
[mydomain].[myapplication]
Models
DataModel.java
MainActivity.java
res
layout
activity_main.xml
content_main.xml
my_inner_layout.xml
My app build.gradle contains
dataBinding {
enabled = true
}
In MainActivity.java I have
import [mydomain].[myapplication].Models.DataModel;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemsSelectedListener {
DataModel dataModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
... <other layout creation template code> ...
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
dataModel = new DataModel();
binding.setValues(dataModel);
}
<navigation and auto-generated methods>
}
My my_inner_layout.xml contains
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="values"
type="[mydomain].[myapplication].Models.DataModel" />
</data>
<android.support.constraint.ConstraintLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
>
<TextView
android:id="#+id/intro_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:text="#{values.valueOne}"/>
<TextView
android:id="#+id/buying_recommendation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/intro_text"
app:layout_constraintTop_toBottomOf="#id/intro_text"
android:text="#{values.valueTwo}"/>
</android.support.constraint.ConstraintLayout>
</layout>
I am passing bind:values="#{values}" through from activity_main to its included app_bar_main to its content_main to its my_inner_layout with that same <data> value in each. Android Studio is telling me "namespace 'bind' is not bound".
If I try to run this, I get "Compilation failed; see the compiler error output for details." Looking in the build output, I see:
In text, the errors are variously error: cannot find symbol class Models and error: package Models does not exist
If I move DataModel.java out of the Models package and directly in to [mydomain].[myapplication], then I get a different result. It does build and run in the emulator, but with much of the layout information failing to appear. No hamburger menu in the top left, no title text in the header, and no settings button in the top right values previously automatically included by the autogenerated code in Android Studio. I am unable to set the title in code using setTitle, either.
Swiping from the left does bring in the navigation drawer however.
I have tried invalidating caches and restarting, cleaning, rebuilding both with the model file in Models and separately.
What I want, chiefly, is to be able to use the project structure I want. To put my models classes in a models sub-package. Once that is complete, I want to make sure the full layout information comes through, including the hamburger menu icon, settings icon, and title. How can I achieve this?

Okay, I realised where the "class Models does not exist" thing comes from. I don't know whether to blame my own stupidity or the stupidly nitpicky way this binding is implemented on Android. The package needed to be called models with a lower case "m", not Models. The binding auto-name-conversion thing must have thought Models was a class, not a package.
To fix the layout, the onCreate method had to be changed to
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
dataModel = new DataModel();
cycleInformationBinding.setRecommendation(dataModel);
// set toolbar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Drawer layout setting
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
Specifically, things had to happen in the order:
setContentView to the main activity
Set up the data model binding
Layout concerns like drawer and toolbar.
Any other order would cause either the model binding to fail or the toolbar to not display correctly.

Just convert your existing layouts to data binding layouts (Don't forget to add variable in your xml with your activity mentioned in type)
Example:
<variable name="navdrawer" type="com.example.sampleapp.HomeScreenActivity" />
This will generate a data binding class for NavigationHeaderView in this format(May differ) NavHeaderYourActivityName.
When you bind your parent activity, you will use that binding instance to get DrawerLayout and your NavigationView, respectively.
A sample code to reduce the boilerplate for initializing views in your code:
NavHeaderHomeScreenBinding navHeaderHomeScreenBinding =
DataBindingUtil.setContentView(this, R.layout.nav_header_home_screen);
AppBarHomeScreenBinding appBarHomeScreenBinding =
DataBindingUtil.setContentView(this, R.layout.app_bar_home_screen);
ActionBarDrawerToggle toggle =
new ActionBarDrawerToggle(this, binding.drawerLayout, appBarHomeScreenBinding.toolbar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close);
binding.drawerLayout.addDrawerListener(toggle);
toggle.syncState();
binding.navView.setNavigationItemSelectedListener(this);
I hope this helps someone! Thank you!

First try to remove redurant setContentView(R.layout.activity_main);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
Second add to end of "onCreate" function
binding.included.setValues(dataModel);
binding.executePendingBindings();
if you use include than you may add to your include id for example
<include
android:id="#+id/included"
layout="#layout/content_main"
app:values="#{DataModel}"/>
and use
binding.included.setValues(dataModel);
research about using databinding with included layouts

Related

I have a Navigation Drawer and want open another isolated fragment

I have a navigation drawer and when i click on one button i want to go to other fragment where i can't access to the navigation drawer and anything else. I just want have a black arrow in the top-left to go back and return to the navigation drawer with all the fragments.
I tried somethings but don't works like i want normally navigator continues accessible and see bot layouts one over the other.
MAIN FRAGMENTS CONTROLLER
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
DrawerLayout drawerLayout=findViewById(R.id.drawer);
NavigationView navigationView=findViewById(R.id.nav_view);
setSupportActionBar(toolbar);
appBarConfiguration= new AppBarConfiguration.Builder(R.id.nav_home,
R.id.nav_user_data,R.id.nav_join_group,
R.id.nav_user_groups,R.id.nav_search_documents)
.setDrawerLayout(drawerLayout).build();
navController = Navigation
.findNavController(this,R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this,navController,appBarConfiguration);
NavigationUI.setupWithNavController(navigationView,navController);
}
#Override
public boolean onSupportNavigateUp() {
return NavigationUI.navigateUp(navController,appBarConfiguration)
|| super.onSupportNavigateUp();
}
I'm trying with a botton on my ActionBar, when i click it should go to my new fragment (with a generic app back but with one back button)
You simply should specify your action in navigation.xml file like others.
It will change hamburger icon by itself because you synchronize your navigation controller with NavDrawer in this two lines of code:
NavigationUI.setupActionBarWithNavController(this,navController,appBarConfiguration);
NavigationUI.setupWithNavController(navigationView,navController);
We need to add one fragment in our navigation.xml (the file where we define our fragments associated with the Fragment and the layout) for the Fragment where we want to go. Add there an action with a unique id and where we want to go in the fragment where we are.
Sorry, i know it's a little bit confused.
NAVIGATION
We go from there
<fragment
android:id="#+id/nav_user_data"
android:name="com.example.androidapplication_reto2.project.activities.navigationfragments.SeeAndModifyUserDataFragment"
android:label="User Data"
tools:layout="#layout/fragment_see_and_modify_user_data"
>
<action
android:id="#+id/action_nav_user_data_to_nav_modify_data"
app:destination="#+id/nav_modify_data" />
</fragment>`
To there
<fragment
android:id="#+id/nav_modify_data"
android:name="com.example.androidapplication_reto2.project.activities.navigationfragments.ModifyUserDataFragment"
android:label="Modify User Data"
tools:layout="#layout/fragment_modify_user_data"
/>
With the action that we defined in the origen fragment.
ORIGEN FRAGMENT
And in the Fragment when you click on one button just happen this.
Navigation.findNavController(getView()).navigate(R.id.action_nav_user_data_to_nav_modify_data);

Android ActionBar does not show title that was set in code

First, I know there are a lot of SO that address similar issues. I've scoured them all, and none of the provided answers are helping to solve my issue.
I cannot get the title (or back button) to appear on my android.support.v7.widget.Toolbar component. No matter what I've tried.
I have an Android activity that that looks like (my_activity.xml):
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="infos" type="com.mycompany.orm.adapters.ListViewAdapter"/>
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="10">
<android.support.v7.widget.Toolbar
android:id="#+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/buttonBackground"
android:elevation="4dp"
android:logo="#drawable/ic_close_white_24dp" />
<ListView
android:id="#+id/my_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#color/windowBackground"
bind:items="#{infos.list}"/>
</RelativeLayout>
</layout>
And the activity onCreate as (MyActivity.java):
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
Toolbar toolbar = (Toolbar) findViewById(R.id.my_toolbar);
if (toolbar != null) {
toolbar.setTitle("My Name Here"); // Never shows up
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setTitle("Hello World!"); // Never shows up
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.show();
}
}
}
But using this code, I only see a blank toolbar. I never see the text (either My Name Here or Hello World!. However, if I add the line bind:title="Testing" to the Toolbar element of the XML, I see the title appearing as Testing. However, I want to be able to manipulate the look of the toolbar/actionbar, so I would like to be able to do it in code.
Does anyone see where this might be going wrong?
Try to set label in your AndroidManifest.xml like that
<activity
android:name="yourpackagename.Activity"
android:label="My Name Here"/>
Otherwise if you want to set as programmatically
If You using extends AppCompatActivity class use
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setTitle("My Name Here");
this.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
If You using extends Activity class use
ActionBar ab = getActionBar();
ab.setTitle("My Name Here");
I suggest to try to use above solution its work for me .
I had faced the same issue and this worked for me.
setSupportActionBar(toolbar);
getSupportActionBar().setTitle(""My Name Here"");

How to set a temporary fragment to my "home screen" Android studio

I have started coding and I really like it, I have been on/off on diffrent project (to learn diffrent things) But now i got a problem, I "app"reciate all the help i can get.
I am using the navigation drawer and got three fragments installed. I can navigate through the navigation drawer and select a fragment and it loads on my screen. But when i start my app the screen is just white and the navigation drawer is on the left and i can pick a fragment. Is it possible to have a fragment on my "home screen" so when I start the app there is a fragment already placed on the screen BUT! when i chosse another fragment in the navigation drawer i would like to have my fragment who loaded at the beginning to disappear. Otherwise both fragments will show on eachother (Text on text). Maybe to have the temporary fragment to "finish" itself somehow. Please look at my imgur image to get my idea.Imgur image press here to view
Here is a generic solution on how to use the FragmentManager. It should give a good idea on how to display a Fragment. Besides that you could include a static Fragment in your layout. It's up to you how to approach it.
So the FragmentManager solution looks like this:
YourActivity.java
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fragmentManager = getFragmentManager();
Fragment fragment = AnyFragment.instantiate(this, AnyFragment.class.getName());
fragmentManager.beginTransaction().add(R.id.fragment_placeholder, fragment).addToBackStack(null).commit();
}
The target id is defined in your activity layout.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"
android:orientation="vertical">
<FrameLayout
android:id="#+id/fragment_placeholder"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"></FrameLayout>
</LinearLayout>
Later if you want to replace the current Fragment you can use the remove and add method of the FragmentManager (the replace method is kinda buggy).
Fragment currentFragment = fragmentManager.findFragmentById(R.id.fragment_placeholder))
fragmentManager.beginTransaction().remove(currentFragment).add(R.id.fragment_placeholder, yourNewFragment).addToBackStack(null).commit();

Moving Logo on action bar Android Studio

I have put an image from my drawable folder and added it onto my action bar and would now like to move it left over beside the back arrow. Anyone any ideas on how to do this in Android Studio. Thanks
My Code is as fallows
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayUseLogoEnabled(true);
getSupportActionBar().setLogo(R.drawable.mainlogo);
Try using a Toolbar, the new way to make AppBars. It is more easily customized and reused, among other advantages.
Android's docs make it seem a lot harder than it really is. They use Toolbar but connect it to the AppBar API's still. If you use a lot of ActionBar utility methods like ActionBar.hide(), then it makes sense to call
setSupportActionBar(myToolbar);
But it can actually be significantly easier.
Why you don't need to setSupportActionBar
According to the article above, if we don't use the AppBar API's we don't need the custom theme, onCreateOptionsMenu(), or any of the AppBar mess.
Here is how to do Toolbars simply:
Get v7 appcompat
I think it is neccessary still to make your Activity extend AppCompatActivity
Add the following code:
At to the top of your layout resource file, inside the top level Layout of course:
<android.support.v7.widget.Toolbar
android:id="#+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light">
</android.support.v7.widget.Toolbar>
In your activity:
protected void onCreate(Bundle savedInstanceState) {
...
//Get the toolbar
Toolbar toolbar = ((Toolbar)findViewById(R.id.my_toolbar));
//Set up the toolbar's navigation icon and behavior
toolbar.setNavigationIcon(R.drawable.ic_close_white_24dp);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//whatever you want to happen on click
}
});
}
Optionally you can do things like:
toolbar.inflateMenu(R.menu.save_menu);
toolbar.setTitle("Hey");
Heres where the custom behavior you wanted comes in. If you want an ImageView in the toolbar, you simply add it to the layout resource:
<android.support.v7.widget.Toolbar
android:id="#+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/my_logo"/>
</android.support.v7.widget.Toolbar>
In fact, if you want a title with custom styles, instead of banging your head against the wall trying to figure out Toolbar styling, simply add a TextView where the ImageView is. You can modify that however you want, and make it your title!

I want my Android Fragment to cover the MainActivity screen (I don't want to see any MainActivity text, buttons, etc.)

This seems to be such a fundamental question that I'm embarrassed to ask it, but I'm so frustrated by my Fragment learning curve that I'll expose my ignorance.
An example in a textbook that cuts a lot of corners that make expanding them difficult, if they even work, had no button to click; MainActivity simply loaded FragmentA. OK, keep it basic. I get that.
So I added a button to MainActivity to click to load FragmentA, but the button shows on the FragmentA screen, sort of like this (not an actual screen shot, but close):
How do I prevent that? Should I use a second Activity instead of a Fragment? Since this endeavor is to be utilized in a much larger project, I don't want to do anything considered not best practice. I realize that the main use of Fragment is to enable side-by-side "screens" on devices that are large enough. That's not what I want to do, but it IS possible to accomplish what I want with a Fragment, isn't it?
MainActivity.java
public class MainActivity extends Activity {
#Override protected void onCreate(Bundle savedInstanceState)
{
super.onCreate( savedInstanceState);
setContentView(R.layout.activity_main);
}
public void btnLoadFragmentAByClick(View view)
{
FragmentA fragmentA;
fragmentA = new FragmentA();
FragmentTransaction ft ;
ft = getFragmentManager().beginTransaction();
ft.replace(R.id.layout_container, fragmentA);
ft.addToBackStack("example");
ft.commit();
}
}
FragmentA.java
public class FragmentA extends Fragment
{
#Override
public View onCreateView(LayoutInflater _inflater,
ViewGroup _container,
Bundle _savedInstanceState)
{
return _inflater.inflate(R.layout.fragment_a,
_container,
false);
}
}
activity_main.xml
<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"
tools:context =".MainActivity" >
<LinearLayout
android:id ="#+id/layout_container"
android:orientation ="vertical"
android:layout_width ="wrap_content"
android:layout_height="wrap_content"
>
</LinearLayout>
<Button
android:id ="#+id/btnLoadFragmentA"
android:text ="Load Fragment A"
android:onClick="btnLoadFragmentAByClick"
android:layout_width ="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
fragment_a.xml
<RelativeLayout
xmlns:android ="http://schemas.android.com/apk/res/android"
android:layout_width ="match_parent"
android:layout_height ="match_parent" >
<TextView
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:text ="Layout for fragment A"
android:textAppearance ="?android:attr/textAppearanceLarge"
>
</TextView>
</RelativeLayout>
EDIT
I realize that I could hide the MainActiviy button (and any other objects) before loading FragmentA and show them after returning, but I was hoping for a one-or-two-line "fix".
How do I prevent that?
Well, to some extent, you don't, insofar as this has nothing to do with fragments.
Your activity_main.xml has the Button floating over top of the LinearLayout (???) that you are using for your fragment container. If you do not want the Button floating over top of the fragment container, then fix the layout file to not have the Button floating over top of the fragment container.
I realize that I could hide the MainActiviy button (and any other objects) before loading FragmentA and show them after returning, but I was hoping for a one-or-two-line "fix".
The typical solution for full-UI replacement using fragments is to have everything in fragments. Your replace() would replace your original fragment with a replacement. So, in this case, your Button would be managed by one fragment, and clicking the Button would replace() that fragment with another fragment. Given that your FragmentTransaction has addToBackStack(), pressing BACK would get rid of the replacement fragment and return you to your Button fragment.

Categories