Navigating to another activity using databinding in mvvp structure - android

I am learning data binding library and I am totally new to this. My question is how to navigate to another activity on data binding.
Can I do it just like we do it in MVC or I have to put that code in ViewModel. Please help me.
Here is my code.
Activity:
public class SplashActivity extends AppCompatActivity implements Observer {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initDataBinding();
initViews();
}
private void initViews() {
findViewById(R.id.guest_button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(SplashActivity.this,GameActivity.class));
}
});
}
private void initDataBinding() {
ActivitySplashBinding activitySplashBinding = DataBindingUtil.setContentView(this, R.layout.activity_splash);
SplashViewModel splashViewModel = new SplashViewModel();
activitySplashBinding.setSplashViewModel(splashViewModel);
splashViewModel.addObserver(this);
}
#Override
public void update(Observable observable, Object data) {
}
}
XML:
<?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"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.sevenbits.android.mvvmsample.view.SplashActivity">
<data>
<variable name="splashViewModel"
type="com.sevenbits.android.mvvmsample.viewmodel.SplashViewModel"/>
</data>
<android.support.constraint.ConstraintLayout
android:id="#+id/parent1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/splash_bg">
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:gravity="center"
android:text="Login"
android:textColor="#color/white"
android:textSize="24sp"
android:id="#+id/login_button"
app:layout_constraintBottom_toTopOf="#+id/parent1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="#id/parent1"
app:layout_constraintVertical_bias="0.42"/>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:gravity="center"
android:text="Sign Up"
android:textColor="#color/white"
android:textSize="24sp"
android:id="#+id/sign_up_button"
app:layout_constraintBottom_toTopOf="#+id/parent1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="#id/parent1"
app:layout_constraintVertical_bias="0.58"/>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:textColor="#color/white"
android:textAllCaps="false"
android:textSize="18sp"
android:id="#+id/guest_button"
android:layout_marginBottom="20dp"
android:text="Play As a Guest User"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</android.support.constraint.ConstraintLayout>
</layout>
Do I need to put onclick code in view model? If yes, then How to do it?

Well, that really depends on the use case but ideally every action should go through ViewModel.
If you need to do some stuff before navigation like storing the data, your click action should go from ViewModel. If you just need to redirect, you can do it MVC way.
I generally do it in this way:
SplashViewModel.java
public static final int ACTION_NAVIGATE_TO_GAME = 1000;
public void navigateToGame() {
// You can do some work here before notifying the view about redirection
setChanged();
notifyObserver(ACTION_NAVIGATE_TO_GAME);
}
SplashActivity.java
#Override
public void update(Observable observable, Object data) {
if (data instanceof Integer) {
int value = (int) data;
switch(value) {
case SplashViewModel.ACTION_NAVIGATE_TO_GAME:
startActivity(new Intent(SplashActivity.this,GameActivity.class));
break;
}
}
}
and in layout file
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:textColor="#color/white"
android:textAllCaps="false"
android:textSize="18sp"
android:id="#+id/guest_button"
android:layout_marginBottom="20dp"
android:text="Play As a Guest User"
android:onClick="#{() -> splashViewModel.navigateToGame()}"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>

Related

What function should i use to open the activities of each button on android studio?

I'm having small problem on my project. I can't open the activities of each button after clicking it. I don't know if the codes I used are correct. please help me fix it. Thank you.
activity_main2.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity2"
android:background="#drawable/backgroundimg">
<Button
android:id="#+id/button"
android:layout_width="270dp"
android:layout_height="60dp"
android:backgroundTint="#android:color/holo_blue_dark"
android:text="Sleep"
android:textAllCaps="false"
android:textColor="#FFFFFF"
android:textSize="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.496"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.299" />
<Button
android:id="#+id/button1"
android:layout_width="270dp"
android:layout_height="60dp"
android:backgroundTint="#android:color/holo_blue_dark"
android:text="Stress Reliever"
android:textAllCaps="false"
android:textColor="#FFFFFF"
android:textSize="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.503"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.433" />
<Button
android:id="#+id/button2"
android:layout_width="270dp"
android:layout_height="60dp"
android:backgroundTint="#android:color/holo_blue_dark"
android:text="Calm"
android:textAllCaps="false"
android:textColor="#FFFFFF"
android:textSize="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.503"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.57" />
<Button
android:id="#+id/button3"
android:layout_width="270dp"
android:layout_height="60dp"
android:backgroundTint="#android:color/holo_blue_dark"
android:text="Motivational Quotes"
android:textAllCaps="false"
android:textColor="#FFFFFF"
android:textSize="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.503"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.701" />
<TextView
android:id="#+id/goodday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Good Day,"
android:textColor="#color/white"
android:textSize="20pt"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.078"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.04" />
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Melana!"
android:textColor="#color/white"
android:textSize="17pt"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.059"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.112" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity2.java
package com.example.serenityapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity2 extends AppCompatActivity {
Button butt1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
butt1=(Button) findViewById(R.id.button);
butt1.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
setContentView(R.layout.activity_stress);
}
});
}
}
This is what the app looks like and the four buttons should open their respective activities
This is just an example. As someone answered here, you could just search how to start a new activity.
butt1.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
Intent navigateToAnotherActivity = new Intent(this, SleepActivity.class);
startActivity(navigateToAnotherActivity);
}
});
to navigate from one activity to another intent is used
Intent intent = new Intent(this, TargetActivity.class)
startActivity(intent)
As I can see in the screenshot you provided. You have created 4 different activities. You just need to open them using the below code.
This code goes inside the onCreate() method of MainActivity2
public class MainActivity2 extends AppCompatActivity {
private Button bt_Sleep, bt_Stress_Reliever, bt_Calm, bt_Motivational_Quotes;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
bt_Sleep = findViewById(R.id.button);
bt_Stress_Reliever = findViewById(R.id.button1);
bt_Calm = findViewById(R.id.button2);
bt_Motivational_Quotes = findViewById(R.id.button3);
bt_Sleep.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent sleep = new Intent(MainActivity2.this, sleep.class);
startActivity(sleep);
}
});
bt_Stress_Reliever.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent stressReliever = new Intent(MainActivity2.this, stress.class);
startActivity(stressReliever);
}
});
bt_Calm.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//calm change with your actual activity name
Intent calmIntent = new Intent(MainActivity2.this, calm.class);
startActivity(calmIntent);
}
});
bt_Motivational_Quotes.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//motivational_quotes change with your actual activity name
Intent mq = new Intent(MainActivity2.this, motivational_quotes.class);
startActivity(mq);
}
});
}
}
This code should work.
Still facing problem comment here.

call another java activity from fragment class

Hey i have a simple question. i have a mobile_navigation that contain code to call a fragment class, and i have the fragment class but i want to call / pass to another java class. for example i have Inputdata.xml that when tap will go to fragment class nah i want when i tap the input xml it will instantly go to another java class not stuck in fragment class
here is the example code for mobile_navigation
<fragment
android:id="#+id/nav_pantuan"
android:name="com.joshua.r0th.crud2.ui.gallery.GalleryFragment"
android:label="#string/pantauan"
tools:layout="#layout/fragment_pantauan" />
and here is the GalleryFragment code
public class GalleryFragment extends Fragment {
private GalleryViewModel GalleryViewModel;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
GalleryViewModel =
ViewModelProviders.of(this).get(GalleryViewModel.class);
View root = inflater.inflate(R.layout.fragment_pantauan, container, false);
final TextView textView = root.findViewById(R.id.text_gallery);
GalleryViewModel.getText().observe(this, new Observer<String>() {
#Override
public void onChanged(#Nullable String s) {
textView.setText(s);
}
});
return root;
}
}
and this is the another java class that i willing to reach
public class pantauan extends AppCompatActivity {
database1 myDb;
EditText editNomorRumah,editJentikDalam,editJentikLuar;
Button btnAddData;
Button btnViewAll;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_pantauan);
myDb = new database1(this);
editNomorRumah = (EditText)findViewById(R.id.nomorrmh);
editJentikDalam = (EditText)findViewById(R.id.jentikdirumah);
editJentikLuar = (EditText)findViewById(R.id.jentikdiluarrumah);
btnAddData = (Button)findViewById(R.id.tambahdata);
btnViewAll = (Button)findViewById(R.id.lihatdata);
AddData();
viewAll();
}
//fungsi tambah
public void AddData() {
btnAddData.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean isInserted = myDb.insertData(editNomorRumah.getText().toString(),
editJentikDalam.getText().toString(),
editJentikLuar.getText().toString() );
if(isInserted == true)
Toast.makeText(pantauan.this,"Data Iserted",Toast.LENGTH_LONG).show();
else
Toast.makeText(pantauan.this,"Data Not Iserted",Toast.LENGTH_LONG).show();
}
}
);
}
//fungsi menampilkan data
public void viewAll() {
btnViewAll.setOnClickListener(
new View.OnClickListener(){
#Override
public void onClick(View v) {
Cursor res = myDb.getAllData();
if(res.getCount() == 0) {
// show message
showMessage("Error","Noting Found");
return;
}
StringBuffer buffer = new StringBuffer();
while (res.moveToNext() ) {
buffer.append("NomorRumah :"+ res.getString(0)+"\n");
buffer.append("JentikDalam :"+ res.getString(1)+"\n");
buffer.append("JentikLuar :"+ res.getString(2)+"\n");
}
// show all data
showMessage("Data",buffer.toString());
}
}
);
}
//membuat alert dialog
public void showMessage(String title, String Message){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setCancelable(true);
builder.setTitle(title);
builder.setMessage(Message);
builder.show();
}
}
and here is the Input.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#drawable/gradient"
android:orientation="vertical"
android:scrollbarAlwaysDrawVerticalTrack="true">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="70dp"
android:background="#drawable/gradient"
android:elevation="4dp"
android:orientation="vertical"
android:padding="20dp">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="30dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nomor Rumah" />
<EditText
android:id="#+id/nomorrmh"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/roundtext" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Jentik Di Dalam Rumah" />
<EditText
android:id="#+id/jentikdirumah"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/roundtext" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Jentik Di Luar Rumah" />
<EditText
android:id="#+id/jentikdiluarrumah"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/roundtext"
android:layout_marginBottom="10dp"/>
<LinearLayout
android:layout_width="wrap_content"
android:orientation="horizontal"
android:layout_height="match_parent"
android:layout_gravity="center">
<Button
android:id="#+id/tambahdata"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="#d67601"
android:text="Tambah Data"
android:textAllCaps="false"
android:textColor="#fff"
android:textSize="18sp" />
<Button
android:id="#+id/lihatdata"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="#d67601"
android:text="contoh lihat data"
android:textAllCaps="false"
android:textColor="#fff"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
<TextView
android:id="#+id/textviewadd"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="26dp"
android:gravity="center_horizontal"
android:text="Input Data"
android:textColor="#fff"
android:textSize="26sp"
android:textStyle="bold"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true" />
<TextView
android:id="#+id/text_gallery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</RelativeLayout>
My goal is to pass the fragment into the java class that i want, because i dont know how to put that input class to the fragment always get cannot be cast to androidx.fragment.app.Fragment when i replace the GalleryFragment with pantauan.java code. thank you

android recyclerview going through my edit text search filter

I have a RecyclerView inside a fragment with a search filter edit text above it, and when I scroll the recyclerview go through the edit text, but I want the RecyclerView always to be under the edit text and leave the edit text on top like a header or something like that no matter how much I scroll. How can I achieve that?
code:
the layout
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical"
tools:context=".fragments.FoodListFragment">
<com.steelkiwi.library.view.BadgeHolderLayout
android:id="#+id/badge"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="center"
android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
android:elevation="100dp"
app:bhl_badge_radius="10dp"
app:bhl_default_badge_background="#color/five"
app:bhl_text_color="#android:color/white"
app:bhl_text_size="12sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/capsule_shopping_cart"
android:elevation="10dp"
app:srcCompat="#drawable/white_shopping_cart" />
</com.steelkiwi.library.view.BadgeHolderLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview_foodlist"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/food_list_search_input" />
<EditText
android:id="#+id/food_list_search_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:background="#drawable/search_input_style"
android:drawableStart="#drawable/search_icon"
android:drawablePadding="8dp"
android:ems="10"
android:hint="search"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
the class
public class FoodListFragment extends Fragment {
EditText etSearchInput;
private RecyclerView recyclerView;
private FoodListAdapter foodListAdapter;
private BadgeHolderLayout badgeHolderLayout;
private List<Food> foods;
public interface ListenerFoodListFragment {
void sendToCart(int value, int adapterPosition);
void cartClickListener();
}
private ListenerFoodListFragment listenerFoodListFragment;
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
listenerFoodListFragment = (ListenerFoodListFragment) context;
} catch (ClassCastException e) {
Log.d("FoodListFragment", "onAttach: " + e.getMessage());
}
}
public FoodListFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_food_list, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
recyclerView = view.findViewById(R.id.recyclerview_foodlist);
badgeHolderLayout = view.findViewById(R.id.badge);
etSearchInput = view.findViewById(R.id.food_list_search_input);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
foods = new ArrayList<>();
foods.add(new Food("Chicken", "99999$", R.drawable.chicken));
badgeHolderLayout.setOnClickListener(v -> listenerFoodListFragment.cartClickListener());
foodListAdapter = new FoodListAdapter(getActivity(), foods, listenerFoodListFragment);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setAdapter(foodListAdapter);
etSearchInput.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
foodListAdapter.getFilter().filter(s);
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
public void updateCartValue(int value) {
badgeHolderLayout.setCountWithAnimation(value);
}
}
Remove this android:layout_marginTop="?attr/actionBarSize" from your Recyclerview
and then Set android:layout_height of your RecyclerView to 0dp will works.
Further more add app:layout_constraintBottom_toTopOf="#id/recyclerview_foodlist" in search EditText or it may be due to background drawable file you added in search EditText
You are using a ConstraintLayout.
match_parent will ignore your constraints.
You need to replace the layout_height="match_parent" of the RecyclerView with layout_height="0dp". Same for its width.
Then it will be underneath the EditText as you expect.
i fixed it by changing my layout to this:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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/root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview_foodlist"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/food_list_search_input" />
<EditText
android:id="#+id/food_list_search_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:background="#drawable/search_input_style"
android:drawableStart="#drawable/search_icon"
android:drawablePadding="8dp"
android:ems="10"
android:hint="search"
android:inputType="textPersonName"
android:textColor="#fff"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.steelkiwi.library.view.BadgeHolderLayout
android:id="#+id/badge"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="center"
android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
android:elevation="100dp"
app:bhl_badge_radius="10dp"
app:bhl_default_badge_background="#color/five"
app:bhl_text_color="#android:color/white"
app:bhl_text_size="12sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/capsule_shopping_cart"
android:elevation="10dp"
app:srcCompat="#drawable/white_shopping_cart" />
</com.steelkiwi.library.view.BadgeHolderLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Change your recyclerview height to wrap_content
android:layout_height="wrap_content"
And remove all this code in recyclerview
android:layout_marginTop="?attr/actionBarSize"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/food_list_search_input"
At last paste this two line in recylerview
app:layout_constraintEnd_toEndOf="#id/food_list_search_input"
app:layout_constraintTop_toBottomOf="#+id/food_list_search_input"

ObservableField value inside ViewModel does not update UI with data binding

ObservableField<Marker> value inside ViewModel class value is changed using EditText in layout however value is not propagated to TextView tv_summary.
This is the layout
<?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>
<import type="com.example.tutorial5livedata_mvvm_room_recyclerview.util.BindingUtils"/>
<variable
name="viewModel"
type="com.example.tutorial5livedata_mvvm_room_recyclerview.viewmodel.AddMarkerViewModel"/>
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Title"
android:textColor="#FC7100"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="#+id/guideline_left"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="#+id/et_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:ems="10"
android:hint="Title"
android:inputType="textPersonName"
android:text="#={viewModel.markerObservableField.title}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="#+id/guideline_left"
app:layout_constraintTop_toBottomOf="#+id/tv_title" />
<TextView
android:id="#+id/tv_latitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Latitude"
android:textColor="#FC7100"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="#+id/guideline_left"
app:layout_constraintTop_toBottomOf="#+id/et_title" />
<EditText
android:id="#+id/et_latitude"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:ems="10"
android:hint="Latitude"
android:text="#={viewModel.markerObservableField.latitude}"
android:inputType="number"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="#+id/guideline_left"
app:layout_constraintTop_toBottomOf="#+id/tv_latitude" />
<TextView
android:id="#+id/tv_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text='#{viewModel.markerObservableField.title + " " + viewModel.markerObservableField.latitude}'
app:layout_constraintStart_toStartOf="#+id/guideline_left"
app:layout_constraintTop_toBottomOf="#+id/et_latitude" />
<android.support.constraint.Guideline
android:id="#+id/guideline_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="8dp" />
</android.support.constraint.ConstraintLayout>
</layout>
ViewModel class
public class AddMarkerViewModel extends AndroidViewModel {
private MarkerRepository mMarkerRepository;
public ObservableField<Marker> markerObservableField = new ObservableField<>();
public AddMarkerViewModel(#NonNull Application application) {
super(application);
AppDatabase appDatabase = AppDatabase.getInstance(application.getApplicationContext());
mMarkerRepository = MarkerRepository
.getsInstance(MarkerLocalDataSource.getInstance(appDatabase.markerDao(), new AppExecutors()));
if (markerObservableField.get() == null) {
Marker marker = new Marker();
marker.setTitle("New Title");
markerObservableField.set(marker);
}
}
public long addMarker(Marker marker) {
return mMarkerRepository.addMarker(marker);
}
}
onCreate method of Activity for adding marker to set values
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_add_marker);
mAddMarkerViewModel = ViewModelProviders.of(this).get(AddMarkerViewModel.class);
mBinding.setViewModel(mAddMarkerViewModel);
}
In order to listen to property changes, you will need to extend BaseObservable.
I think the problem here is that property change does not fire event, because you listen to Field change, that is marker object itself, that stays same.
Marker field Latitude is not observable, that means it's impossible to detect it's change.
You have two options.
If you want to detect changes, you can create observable field for Latitude.
public ObservableField<String> latitudeObservableField = new ObservableField<>();
You can listen to field Changes and update marker object.
latitudeObservableField.addOnPropertyChangedCallback(() -> {
// Update marker object
})
Another approach would be to make Marker extend BaseObservable, like explained in attached reference.
Please check out official documentation on observable objects.

How to request or remove the focus on edittext using data binding

I am learning mvvm structure and making an app using mvvm structure and data binding also.
Now, what I want to do is, I wanted to fetch a user from sharedpreference, If I am getting a user successfully then, I would set the name of usr to edittext1. In that case, I want to request focus on edittext2.
How to achieve that using databinding? (in such a way that i don't
have to use activity. The job should be done using view model and xml
only.)
I have tried that using following way.
StartGameViewModel
public class StartGameViewModel extends ViewModel {
public static String TAG="StartGameViewModel";
private Preference<User> preference;
public ObservableField<String> player1Name=new ObservableField<>("");
public ObservableField<String> player2Name=new ObservableField<>("");
public ObservableBoolean shouldRequestFocus=new ObservableBoolean(false);
StartGameViewModel(Preference preference){
this.preference=preference;
}
public void getPreference() {
preference.get(Constants.CURRENT_USER,User.class)
.subscribe(new Observer<User>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(User user) {
player1Name.set(user.name);
shouldRequestFocus.set(true);
}
#Override
public void onError(Throwable e) {
Log.i(TAG,"user is logged out");
}
#Override
public void onComplete() {
Log.i(TAG,"Completed Preference");
}
});
}
}
activity_start_game.xml
<?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"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".view.StartGameActivity">
<data>
<variable
name="startGameViewModel"
type="com.sevenbits.android.mvvmsample.viewmodel.StartGameViewModel" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/splash_bg">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Enter Players Name"
android:textSize="24sp"
android:textColor="#color/white"
app:layout_constraintVertical_bias="0.75"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toTopOf="#+id/input_layout"
app:layout_constraintTop_toTopOf="parent"
/>
<LinearLayout
android:id="#+id/input_layout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"
android:background="#color/white"
android:elevation="20dp"
android:orientation="vertical"
android:paddingBottom="40dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingTop="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.45"
tools:layout_editor_absoluteX="8dp">
<android.support.design.widget.TextInputLayout
android:id="#+id/til_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<android.support.design.widget.TextInputEditText
android:id="#+id/et_player1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Player1"
android:text="#{startGameViewModel.player1Name}"
app:addTextChangedListener="#{startGameViewModel.Player1Watcher}" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="#+id/til_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<android.support.design.widget.TextInputEditText
android:id="#+id/et_player2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Player2"
android:text="#{startGameViewModel.player2Name}"
app:addTextChangedListener="#{startGameViewModel.Player2Watcher}" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
<Button
android:id="#+id/start_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/bg_button"
android:elevation="20dp"
android:gravity="center"
android:paddingBottom="20dp"
android:paddingEnd="40dp"
android:paddingStart="40dp"
android:paddingTop="20dp"
android:text="Start"
android:textAllCaps="false"
android:textColor="#color/white"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/input_layout" />
</android.support.constraint.ConstraintLayout>
</layout>
StartGameActivity:
public class StartGameActivity extends AppCompatActivity {
ActivityStartGameBinding activityStartGameBinding;
StartGameViewModel startGameViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initDataBinding();
setStartGameListener();
}
private void initDataBinding() {
activityStartGameBinding = DataBindingUtil.setContentView(this, R.layout.activity_start_game);
StartGameViewModelFactory startGameViewModelFactory= Injection.provideStartGameViewModelFactory(this);
startGameViewModel = ViewModelProviders.of(this,startGameViewModelFactory).get(StartGameViewModel.class);
activityStartGameBinding.setStartGameViewModel(startGameViewModel);
startGameViewModel.getPreference();
if(startGameViewModel.shouldRequestFocus.get())
findViewById(R.id.et_player2).requestFocus();
}
private void setStartGameListener() {
findViewById(R.id.start_button).setOnClickListener(v -> {
Intent intent=new Intent(StartGameActivity.this,GameActivity.class);
intent.putExtra(Constants.PLAYER1_NAME,startGameViewModel.player1Name.get());
intent.putExtra(Constants.PLAYER2_NAME,startGameViewModel.player2Name.get());
startActivity(intent);
});
}
}
Very simple via binding adapter
#JvmStatic
#BindingAdapter("requestFocus")
fun requestFocus(view: TextView, requestFocus: Boolean) {
if (requestFocus) {
view.isFocusableInTouchMode = true
view.requestFocus()
}
}
<EditText
android:id="#+id/et_company"
android:layout_width="0dp"
android:layout_height="match_parent"
android:imeOptions="actionDone"
android:inputType="textCapSentences"
android:maxLength="32"
android:scrollbars="vertical"
app:requestFocus="#{company.requestFocus}" />
I know this is an old question, but I was not able to solve the issue with the current answer. Posting my answer here:
in XML:
<EditText
android:id="#+id/email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="#dimen/elevation15"
app:requestFocus="#{viewmodel.focus}"/>
And in the viewModel, I had a Boolean variable declared as
val focus = true
And the binding adapter is as follows:
companion object{
#BindingAdapter("requestFocus")
#JvmStatic fun requestFocus(editText: EditText, requestFocus: Boolean){
if(requestFocus){
editText.isFocusableInTouchMode = true
editText.requestFocus()
}
}
}
Basically what is happening here is, Since app:requestFocus is written inside the xml, it will invoke the binding adapter with the focus Boolean, which is given as the value for the attribute for app:requestFocus.
In my case, I didn't want to remove focus, that's why I used Boolean. If it needs to be changed, using a livedata and set the value, and update the binding adapter accordingly
Disclaimer: I am new to MVVM and Databinding, someone please correct me if I am wrong.

Categories

Resources