How to start an activity from another acitivity when using databinding - android
I am using data binding in my project but whenever i want to start a new activity from my current one, it throws an error. I tried all the methods i can find on stackoverflow but none of those are seem to be working for me.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.app.erp, PID: 12624
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.app.erp/com.app.erp.teacher_view.ActivityAfterTeacherLoginNavigationTakeAttendance}: java.lang.NullPointerException: null cannot be cast to non-null type java.util.ArrayList<kotlin.String>{ kotlin.collections.TypeAliasesKt.ArrayList<kotlin.String> }
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3308)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3457)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2044)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7560)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Caused by: java.lang.NullPointerException: null cannot be cast to non-null type java.util.ArrayList<kotlin.String>{ kotlin.collections.TypeAliasesKt.ArrayList<kotlin.String> }
at com.app.erp.teacher_view.ActivityAfterTeacherLoginNavigationTakeAttendance.onCreate(ActivityAfterTeacherLoginNavigationTakeAttendance.kt:86)
at android.app.Activity.performCreate(Activity.java:7894)
at android.app.Activity.performCreate(Activity.java:7881)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1307)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3283)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3457)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2044)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7560)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
My Activity -
class ActivityAfterTeacherLoginNavigation : AppCompatActivity() {
private val fragmentViewModel : ActivityAfterTeacherLoginNavigationViewModel by viewModels()
private val db = FirebaseFirestore.getInstance()
private lateinit var teacherAttendanceArrayListRecyclerView: ArrayList<FragmentTeacherAttendanceLogRecyclerViewDataClass>
private lateinit var binding: ActivityAfterTeacherLoginNavigationBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_after_teacher_login_navigation)
binding.addAttendance = this
teacherAttendanceArrayListRecyclerView = arrayListOf<FragmentTeacherAttendanceLogRecyclerViewDataClass>()
val navController = findNavController(R.id.fragmentContainerView)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragmentContainerView)!!
val navigator = KeepStateNavigator(this, navHostFragment.childFragmentManager, R.id.fragmentContainerView)
navController.navigatorProvider += navigator
navController.setGraph(R.navigation.teacher_activity_bottom_navigation)
binding.bottomNavigationView.setupWithNavController(navController)
navController.addOnDestinationChangedListener { _, destination, _ ->
when ((destination as FragmentNavigator.Destination).className) {
FragmentTeacherAttendanceLog::class.qualifiedName -> {
binding.fab.show()
binding.fab.text = "Add Attendance"
}
else -> {
binding.fab.hide()
}
}
}
loadTeacherInfo()
loadBatchData()
getAttendanceData()
}
fun navigateToTakeAttendance(view: View) {
startActivity(Intent(this#ActivityAfterTeacherLoginNavigation, ActivityAfterTeacherLoginNavigationTakeAttendance::class.java))
}
My XML file -
<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">
<data>
<variable
name="addAttendance"
type="com.app.erp.teacher_view.ActivityAfterTeacherLoginNavigation" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/parentFrameLayout"
tools:context=".teacher_view.ActivityAfterTeacherLoginNavigation">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/fragmentContainerView"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="#+id/fab"
android:stateListAnimator="#null"
app:elevation="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:onClick="#{addAttendance::navigateToTakeAttendance}"
app:layout_anchor="#id/bottomNavigationView"
app:icon="#drawable/ic_baseline_post_add_24"
app:layout_anchorGravity="end"
android:translationY="-20sp"
android:layout_marginEnd="20sp"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="0dp"
android:layout_gravity="bottom"
app:labelVisibilityMode="selected"
app:layout_behavior="#string/hide_bottom_view_on_scroll_behavior"
app:menu="#menu/teacher_activity_bottom_menu" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/secondaryFragmentContainerTeacher" />
</FrameLayout>
Let me know if any other information is required. I am new to Data binding and it's concepts so i apologize if my approach is not good.
The code of the activity i want to start
class ActivityAfterTeacherLoginNavigationTakeAttendance : AppCompatActivity() {
private val db = FirebaseFirestore.getInstance()
private val fragmentViewModel: ActivityAfterTeacherLoginNavigationTakeAttendanceViewModel by viewModels()
private lateinit var title: TextView
private lateinit var binding: ActivityAfterTeacherLoginNavigationTakeAttendanceBinding
private lateinit var tempArrayListSemesterInfo: ArrayList<String>
#SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_after_teacher_login_navigation_take_attendance)
binding.title.text = "Attendance Details"
binding.proceedBut.setOnClickListener {
checkInput()
}
supportFragmentManager.popBackStack()
binding.semesterSelect.setOnClickListener{
if(binding.batchSelect.text.toString().isBlank()){
binding.batchSelect.setError("Please select Batch first",null)
binding.batchSelect.requestFocus()
}
}
binding.dateSelect.setText(getCurrentDate(),null)
binding.timeSelect.setText(getCurrentTime(),null)
fragmentViewModel.teacherCodeData.value = intent.getStringExtra("teacherCodeTxt").toString()
binding.teacherCode.setText(intent.getStringExtra("teacherCodeTxt").toString(),null)
fragmentViewModel.teacherNameData.value = intent.getStringExtra("teacherTxt").toString()
binding.teacherSelect.setText(intent.getStringExtra("teacherTxt").toString(),null)
val batchArrayList: ArrayList<String> = intent.getStringArrayListExtra("batchTxt") as ArrayList<String>
val batchArrayAdapter = ArrayAdapter<String>(this,
R.layout.exposed_dropdown_menu_item_layout,batchArrayList)
binding.batchSelect.setAdapter(batchArrayAdapter)
val courseArrayList: ArrayList<String> = intent.getStringArrayListExtra("courseTxt") as ArrayList<String>
val courseArrayAdapter = ArrayAdapter<String>(this,
R.layout.exposed_dropdown_menu_item_layout,courseArrayList)
binding.courseSelect.setAdapter(courseArrayAdapter)
tempArrayListSemesterInfo = arrayListOf<String>()
binding.batchSelect.onItemClickListener = AdapterView.OnItemClickListener { parent, _, position, _ ->
if(binding.batchSelect.text.isNotEmpty()){
binding.batchSelect.error = null
}
binding.semesterSelect.text.clear()
tempArrayListSemesterInfo.clear()
val selectedItem = parent.getItemAtPosition(position).toString()
db.collection("BatchInfo").whereEqualTo("Name",selectedItem)
.addSnapshotListener(object: EventListener<QuerySnapshot> {
#SuppressLint("NotifyDataSetChanged")
override fun onEvent(value: QuerySnapshot?, error: FirebaseFirestoreException?) {
if(error != null){
Log.e("Firestore Error",error.message.toString())
return
}
for(dc : DocumentChange in value?.documentChanges!!){
if(dc.type == DocumentChange.Type.ADDED){
tempArrayListSemesterInfo.addAll(dc.document.data.getValue("Semester") as Collection<String>)
val addStudentSemesterSelectAdapter = ArrayAdapter(this#ActivityAfterTeacherLoginNavigationTakeAttendance,
R.layout.exposed_dropdown_menu_item_layout, tempArrayListSemesterInfo)
binding.semesterSelect.setAdapter(addStudentSemesterSelectAdapter)
}
break
}
}
})
}
binding.courseSelect.onItemClickListener = AdapterView.OnItemClickListener { parent, _, position, _ ->
if (binding.courseSelect.text.isNotEmpty()) {
binding.courseSelect.error = null
}
val selectedItem = parent.getItemAtPosition(position).toString()
db.collection("CourseInfo").whereEqualTo("CourseName",selectedItem).get()
.addOnCompleteListener { itAlt ->
if(itAlt.isSuccessful){
for (doc in itAlt.result!!){
binding.courseCode.setText(doc.data.getValue("CourseCode").toString(),null)
}
}
}
}
binding.proceedBut.setOnClickListener {
checkInput()
}
}
}
Inside the loop you are trying to read a value that might be null value?.documentChanges . So you must use safe cast operator
add ? after as
for(dc : DocumentChange in value?.documentChanges!!){
if(dc.type == DocumentChange.Type.ADDED){
tempArrayListSemesterInfo.addAll(dc.document.data.getValue("Semester") as? Collection<String>)
val addStudentSemesterSelectAdapter = ArrayAdapter(this#ActivityAfterTeacherLoginNavigationTakeAttendance,
R.layout.exposed_dropdown_menu_item_layout, tempArrayListSemesterInfo)
binding.semesterSelect.setAdapter(addStudentSemesterSelectAdapter)
}
break
}
Related
I got this bug while tryimg to run my app "Error in Inflating Class Fragment"
Caused by: android.view.InflateException: Binary XML file line #25 in com.androiddevs.mvvmnewsapp:layout/activity_news: Binary XML file line #25 in com.androiddevs.mvvmnewsapp:layout/activity_news: Error inflating class fragment Caused by: android.view.InflateException: Binary XML file line #25 in com.androiddevs.mvvmnewsapp:layout/activity_news: Error inflating class fragment Caused by: kotlin.UninitializedPropertyAccessException: lateinit property viewModel has not been initialized at com.androiddevs.mvvmnewsapp.ui.NewsActivity.getViewModel(NewsActivity.kt:15) at com.androiddevs.mvvmnewsapp.ui.fragments.BreakingNewsFragment.onCreateView(BreakingNewsFragment.kt:29) at These are the codes Involved My activity News Xml <FrameLayout android:id="#+id/flFragment" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintBottom_toTopOf="#+id/bottomNavigationView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <fragment android:id="#+id/newsNavHostFragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" app:defaultNavHost="true" app:navGraph="#navigation/news_nav_graph" /> </FrameLayout> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="#+id/bottomNavigationView" android:layout_width="match_parent" android:layout_height="56dp" app:menu="#menu/bottom_navigation_menu" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout> Breaking News Fragment class BreakingNewsFragment:Fragment() { lateinit var binding: FragmentBreakingNewsBinding lateinit var viewModel: NewsViewModel lateinit var newsAdapter:NewsAdapter val TAG = "BreakingNewsFragment" override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { binding = FragmentBreakingNewsBinding.inflate(layoutInflater,container,false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setupRecyclerView() viewModel = (activity as NewsActivity).viewModel viewModel.breakingNews.observe(viewLifecycleOwner, Observer { response -> when(response){ is Resource.Success -> { hideProgressBar() response.data?.let { newsResponse -> newsAdapter.differ.submitList(newsResponse.articles) } } is Resource.Error ->{ hideProgressBar() response.message?.let { message -> Log.e(TAG, "An error occured: $message") } } is Resource.Loading ->{ showProgressBar() } } }) } private fun hideProgressBar(){ binding.paginationProgressBar.visibility = View.INVISIBLE } private fun showProgressBar(){ binding.paginationProgressBar.visibility = View.VISIBLE } private fun setupRecyclerView(){ newsAdapter = NewsAdapter() binding.rvBreakingNews.apply { adapter = newsAdapter layoutManager = LinearLayoutManager(activity) } } } News Activity class NewsActivity : AppCompatActivity() { lateinit var viewModel: NewsViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_news) val newsRepository = NewsRepository(ArticleDatabase(this)) val viewModelProviderFactory = NewsViewModelProviderFactory(newsRepository) viewModel = ViewModelProvider(this, viewModelProviderFactory).get(NewsViewModel::class.java) val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomNavigationView) val newsNavHostFragment = findViewById<View>(R.id.newsNavHostFragment) bottomNavigationView.setupWithNavController(newsNavHostFragment.findNavController()) } }
API is fetching all the JSON data but my app displays only one in recycler view what should i do?
I am making a simple recipe search app using recipe search API but the problem is the app fetches all the data from API but my app displays only one in recycler view then what should I do? Please help MainActivity.kt class MainActivity : AppCompatActivity() { private lateinit var recipeViewModel: RecipeViewModel lateinit var mainBinding: ActivityMainBinding lateinit var recipeAdapter: RecipeAdapter lateinit var recipeItemList: ArrayList<Recipes> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mainBinding = ActivityMainBinding.inflate(layoutInflater) setContentView(mainBinding.root) recipeViewModel = ViewModelProvider( this, ViewModelProvider.AndroidViewModelFactory .getInstance(application) )[RecipeViewModel::class.java] recipeItemList = arrayListOf() mainBinding.recyclerView.layoutManager = LinearLayoutManager(this) recipeViewModel.recipeLiveData.observe(this, Observer { recipeItems -> recipeItemList.add(recipeItems) recipeAdapter = RecipeAdapter(this, recipeItemList) mainBinding.recyclerView.adapter = recipeAdapter Log.d("RESPONSE", recipeItems.toString()) Log.d("List size", recipeAdapter.itemCount.toString()) }) searchRecipeName() } private fun searchRecipeName() { mainBinding.searchRecipeFabBtn.setOnClickListener { val view = layoutInflater.inflate(R.layout.recipe_search_layout, null) val searchRecipeET = view.findViewById<EditText>(R.id.searchRecipeET) val searchRecipeBtn = view.findViewById<Button>(R.id.searchRecipeBtn) val bottomSheetDialog = BottomSheetDialog(this) bottomSheetDialog.apply { this.setContentView(view) this.show() } searchRecipeBtn.setOnClickListener { val recipeName = searchRecipeET.text.toString() searchRecipeName(recipeName, searchRecipeET, bottomSheetDialog) } } } private fun searchRecipeName( recipeName: String, searchRecipeET: EditText, bottomSheetDialog: BottomSheetDialog ) { if (recipeName.isEmpty()) { searchRecipeET.error = "Please enter recipe name" } else { recipeViewModel.getRecipes(recipeName) bottomSheetDialog.dismiss() } } } RecipeAdapter.kt class RecipeAdapter(val context: Context, val recipesList: ArrayList<Recipes> = arrayListOf()) : RecyclerView.Adapter<RecipeAdapter.RecipeViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecipeViewHolder { val layoutInflater = LayoutInflater.from(context) val view = layoutInflater.inflate(R.layout.recipe_items_layout, null, false) return RecipeViewHolder(view) } override fun onBindViewHolder(holder: RecipeViewHolder, position: Int) { val currentItem = recipesList[position] holder.recipeImageView.load(currentItem.hits[3].recipe.image) holder.recipeNameText.text = currentItem.hits[4].recipe.label } override fun getItemCount(): Int { return recipesList.size } class RecipeViewHolder(itemView: View) :RecyclerView.ViewHolder(itemView) { val recipeImageView: ImageView = itemView.findViewById(R.id.recipeImageView) val recipeNameText: TextView = itemView.findViewById(R.id.recipeNameText) } } RecipeViewModel.kt class RecipeViewModel() : ViewModel() { private val recipeRepository: RecipeRepository = RecipeRepository(RetrofitInstance.provideApiService) val recipeLiveData: LiveData<Recipes> get() = recipeRepository.recipeLiveData fun getRecipes(q:String) = viewModelScope.launch { recipeRepository.getRecipes(q) } } RecipeRepository.kt class RecipeRepository(private val apiService: ApiService) { private val recipeMutableLiveData: MutableLiveData<Recipes> = MutableLiveData() val recipeLiveData: LiveData<Recipes> get() = recipeMutableLiveData suspend fun getRecipes(q:String){ val response = apiService.getRecipes(q) recipeMutableLiveData.value = response.body() } } APIService.kt interface ApiService { #GET("/api/recipes/v2?type=public&app_id=${APP_ID.appId}&app_key=${API_KEY.apiKey}") suspend fun getRecipes(#Query("q") q:String): Response<Recipes> } Logs 2022-03-01 17:06:00.267 14222-14222/com.yash1307.digitalrecipebook D/RESPONSE: Recipes(hits=[Hit(recipe=Recipe(calories=308.34999999999997, dietLabels=[Low-Carb, Low-Sodium], healthLabels=[Sugar-Conscious, Low Potassium, Kidney-Friendly, Keto-Friendly, Vegetarian, Pescatarian, Paleo, Mediterranean, Dairy-Free, Gluten-Free, Wheat-Free, Peanut-Free, Tree-Nut-Free, Soy-Free, Fish-Free, Shellfish-Free, Pork-Free, Red-Meat-Free, Crustacean-Free, Celery-Free, Mustard-Free, Sesame-Free, Lupine-Free, Mollusk-Free, Alcohol-Free, No oil added, Sulfite-Free, FODMAP-Free, Kosher], image=https://www.edamam.com/web-img/20f/20f0c2553240a2c6bc639d64df3f9df4.jpg, label=Poached Eggs, totalNutrients=TotalNutrients(CA=CAX(label=Calcium, quantity=120.69999999999999, unit=mg), CHOCDF=CHOCDFX(label=Carbs, quantity=1.5499999999999998, unit=g), CHOLE=CHOLEX(label=Cholesterol, quantity=799.8, unit=mg), ENERC_KCAL=ENERCKCALX(label=Energy, quantity=308.34999999999997, unit=kcal), FAT=FATX(label=Fat, quantity=20.4465, unit=g), FE=FEX(label=Iron, quantity=3.764, unit=mg), K=KX(label=Potassium, quantity=296.8, unit=mg), MG=MGX(label=Magnesium, quantity=25.849999999999998, unit=mg), NA=NAX(label=Sodium, quantity=305.40000000000003, unit=mg), PROCNT=PROCNTX(label=Protein, quantity=27.004, unit=g)))), Hit(recipe=Recipe(calories=786.91, dietLabels=[Low-Carb], healthLabels=[Sugar-Conscious, Low Potassium, Kidney-Friendly, Vegetarian, Pescatarian, Peanut-Free, Tree-Nut-Free, Soy-Free, Fish-Free, Shellfish-Free, Pork-Free, Red-Meat-Free, Crustacean-Free, Celery-Free, Mustard-Free, Sesame-Free, Lupine-Free, Mollusk-Free, Alcohol-Free, Sulfite-Free, Kosher, Immuno-Supportive], image=https://www.edamam.com/web-img/943/943f98393348d0daf5f239e328c0bb5d.jpg, label=Moonstruck eggs, totalNutrients=TotalNutrients(CA=CAX(label=Calcium, quantity=142.34, unit=mg), CHOCDF=CHOCDFX(label=Carbs, quantity=28.896199999999997, unit=g), CHOLE=CHOLEX(label=Cholesterol, quantity=472.57000000000005, unit=mg), ENERC_KCAL=ENERCKCALX(label=Energy, quantity=786.91, unit=kcal), FAT=FATX(label=Fat, quantity=67.6459, unit=g), FE=FEX(label=Iron, quantity=3.5434, unit=mg), K=KX(label=Potassium, quantity=238.37999999999997, unit=mg), MG=MGX(label=Magnesium, quantity=37.84, unit=mg), NA=NAX(label=Sodium, quantity=424.57, unit=mg), PROCNT=PROCNTX(label=Protein, quantity=17.622700000000002, unit=g)))), Hit(recipe=Recipe(calories=451.61312499999997, dietLabels=[], healthLabels=[Sugar-Conscious, Low Potassium, Kidney-Friendly, Keto-Friendly, Vegetarian, Pescatarian, Mediterranean, Dairy-Free, Peanut-Free, Tree-Nut-Free, Soy-Free, Fish-Free, Shellfish-Free, Pork-Free, Red-Meat-Free, Crustacean-Free, Celery-Free, Mustard-Free, Sesame-Free, Lupine-Free, Mollusk-Free, Alcohol-Free, Sulfite-Free, Kosher], image=https://www.edamam.com/web-img/558/558ccc3d6e43aaf065322133ad6287b0.jpg, label=Poached Eggs, totalNutrients=TotalNutrients(CA=CAX(label=Calcium, quantity=197.9872197236699, unit=mg), CHOCDF=CHOCDFX(label=Carbs, quantity=29.56533125, unit=g), CHOLE=CHOLEX(label=Cholesterol, quantity=744.0, unit=mg), ENERC_KCAL=ENERCKCALX(label=Energy, quantity=451.61312499999997, unit=kcal), FAT=FATX(label=Fat, quantity=21.014962499999996, unit=g), FE=FEX(label=Iron, quantity=5.603875052450463, unit=mg), K=KX(label=Potassium, quantity=394.53073990789, unit=mg), MG=MGX(label=Magnesium, quantity=53.41204561348624, unit=mg), NA=NAX(label=Sodium, quantity=728.8926375, unit=mg), PROCNT=PROCNTX(label=Protein, quantity=31.436606249999997, unit=g)))), Hit(recipe=Recipe(calories=2863.0874999990874, dietLabels=[Low-Carb], healthLabels=[Sugar-Conscious, Peanut-Free, Tree-Nut-Free, Soy-Free, Fish-Free, Shellfish-Free, Crustacean-Free, Celery-Free, Mustard-Free, Sesame-Free, Lupine-Free, Mollusk-Free, Alcohol-Free, Sulfite-Free], image=https://www.edamam.com/web-img/48a/48ae883aa945c01b0b8c590d40e6fd34.jpg, label=Eggs Benedict, totalNutrients=TotalNutrients(CA=CAX(label=Calcium, quantity=584.8499999983388, unit=mg), CHOCDF=CHOCDFX(label=Carbs, quantity=89.18834999989487, unit=g), CHOLE=CHOLEX(label=Cholesterol, quantity=1377.6524999998987, unit=mg), ENERC_KCAL=EN App image Here is the image that displays only one item Recipe Items Layout <?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="wrap_content" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"> <com.google.android.material.card.MaterialCardView android:layout_width="match_parent" android:layout_height="wrap_content" app:cardCornerRadius="6dp" app:cardElevation="6dp" app:cardUseCompatPadding="true"> <ImageView android:id="#+id/recipeImageView" android:layout_width="140dp" android:layout_height="140dp" android:scaleType="centerCrop" android:src="#drawable/ic_baseline_search_24" /> <TextView android:id="#+id/recipeNameText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginStart="12dp" android:textSize="20sp" tools:text="Recipe Name" /> </com.google.android.material.card.MaterialCardView> </RelativeLayout> activity_main.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=".activities.MainActivity"> <androidx.recyclerview.widget.RecyclerView android:id="#+id/recyclerView" android:layout_width="409dp" android:layout_height="729dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="#+id/searchRecipeFabBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="true" app:layout_constraintBottom_toBottomOf="#+id/recyclerView" app:layout_constraintEnd_toEndOf="#+id/recyclerView" app:layout_constraintHorizontal_bias="0.957" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="#+id/recyclerView" app:layout_constraintVertical_bias="0.950" app:srcCompat="#drawable/ic_baseline_search_24" android:focusable="true" android:contentDescription="#string/search_recipes" /> </androidx.constraintlayout.widget.ConstraintLayout> Reicpes.kt (data class) data class Recipes( val hits: ArrayList<Hit>, ) Hit.kt (data class) data class Hit( val recipe: Recipe ) Recipe.kt (data class) data class Recipe( val calories: Double, val dietLabels: List<String>, val healthLabels: List<String>, val image: String, val label: String, val totalNutrients: TotalNutrients, )
in your Adapter you trying to get recipesList size which is contain only one item hits in it override fun getItemCount(): Int { return recipesList.size } I think you need to use recipesList.hits.size instead of recipesList.size override fun getItemCount(): Int { return recipesList.hits.size }
refresh data in a Firestore Paging Adapter using Swipe Refresh Layout
I am using FirestorePagingAdapter to show data in my app but when I use Swipe Refresh Layout did not work with FirestorePagingAdapter, swipe refresh layout.isVisible = true in LOAD_MORE when I don't scroll how to work with a Swipe Refresh Layout in FirestorePagingAdapter? ViewHolde.class: class ViewHolde(item: View) : RecyclerView.ViewHolder(item){ val username = item.findViewById(R.id.iduser) as TextView val title = item.findViewById(R.id.idtitle) as TextView val decription = item.findViewById(R.id.iddes) as TextView } User.class: class User { lateinit var userphoto: StorageReference lateinit var username:String lateinit var title:String lateinit var notes: String lateinit var id: String var isSelected:Boolean = false constructor(){ } constructor( id: String?,username:String?,title: String?, notes: String?) { this.title= title!! this.id= id!! this.username= username!! this.notes= notes!! } } RecyclerActivity.class: class RecyclerActivity : AppCompatActivity(),SwipeRefreshLayout.OnRefreshListener { var mylist=ArrayList<User>() var rv:RecyclerView? = null var currentuser = FirebaseAuth.getInstance().currentUser!!.uid val str= FirebaseStorage.getInstance().reference private var mAuthStateListener: FirebaseAuth.AuthStateListener? = null var db = FirebaseFirestore.getInstance(); private val notebookRef2 = db.collection("ProfileData") private val mQuery = notebookRef2.orderBy("title", Query.Direction.ASCENDING) val config = PagedList.Config.Builder() .setEnablePlaceholders(false) .setPrefetchDistance(2) .setPageSize(6) .build() val options = FirestorePagingOptions.Builder<User>() .setLifecycleOwner(this) .setQuery(mQuery, config, User::class.java) .build() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_recycler) rec() var swipeContainer = findViewById(R.id.swipeContainer)as SwipeRefreshLayout swipeContainer.setOnRefreshListener(this); swipeContainer = findViewById(R.id.swipeContainer)as SwipeRefreshLayout swipeContainer.setColorSchemeResources(android.R.color.holo_blue_bright, android.R.color.holo_green_light, android.R.color.holo_orange_light, android.R.color.holo_red_light); swipeContainer.setOnRefreshListener { rv?.invalidate(); swipeContainer.setRefreshing(false); } } override fun onRefresh() { Handler().postDelayed( Runnable() { swipeContainer.setRefreshing(false); }, 3000); } fun rec(){ rv=findViewById(R.id.idrecycler) as? RecyclerView rv!!.setHasFixedSize(true) rv!!.layoutManager = LinearLayoutManager(this) db.collection("ProfileData").orderBy("title", Query.Direction.DESCENDING) .addSnapshotListener { querySnapshot, firebaseFirestoreException -> if (querySnapshot != null) { for(da in querySnapshot) { val note = da.toObject(Note::class.java) var title = note.title var description = note.notes var username = note!!.username var id = note!!.id mylist.add(User(id!!,username!!, title!!, description!!)) } } } setupadapter() } fun setupadapter(){ rv=findViewById(R.id.idrecycler) as? RecyclerView var mAdapter = object : FirestorePagingAdapter<User, ViewHolde>(options) { override fun onLoadingStateChanged(state: LoadingState) { swipeRefreshLayout2.isVisible = false when (state) { LoadingState.LOADING_INITIAL -> { swipeRefreshLayout2.isVisible = true } LoadingState.LOADING_MORE -> { swipeRefreshLayout.isVisible = true } LoadingState.LOADED -> { swipeRefreshLayout.isVisible = false } LoadingState.ERROR -> { swipeRefreshLayout.isVisible = false } LoadingState.FINISHED -> { swipeRefreshLayout.isVisible = false } } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolde { var v = LayoutInflater.from(parent.context) .inflate(R.layout.iktem_list, parent, false) return ViewHolde(v) } override fun onBindViewHolder(holder: ViewHolde, position: Int, p2: User) { holder.username.text = mylist.get(position).username holder.title.text = mylist.get(position).title holder.decription.text = mylist.get(position).notes } } rv!!.adapter = mAdapter } } ActivityRecycler.xml: <?xml version="1.0" encoding="utf-8"?> <androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:id="#+id/iddrawer2" tools:context=".RecyclerActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> </LinearLayout> <androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_height="match_parent" android:layout_width="match_parent" > <androidx.appcompat.widget.Toolbar android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#4C00CF" android:id="#+id/idtoolbar2" tools:ignore="MissingConstraints"/> <androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="#+id/swipeContainer" android:layout_width="match_parent" android:layout_marginTop="50dp" android:layout_height="460dp"> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView android:id="#+id/idrecycler" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </ScrollView> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> <ProgressBar android:id="#+id/swipeRefreshLayout2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginBottom="340dp" android:visibility="gone" /> <ProgressBar android:id="#+id/swipeRefreshLayout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="450dp" android:visibility="gone" /> </androidx.coordinatorlayout.widget.CoordinatorLayout> <com.google.android.material.navigation.NavigationView android:layout_width="match_parent" android:layout_height="match_parent" app:headerLayout="#layout/header" android:id="#+id/idnavigatuonv2" android:layout_gravity="start" app:menu="#menu/draw_menu"/> </androidx.drawerlayout.widget.DrawerLayout >
So I'm using the adapter to show transaction history and I have a button to show the filtered transaction history which has status == success. On button click, I'm updating the adapter the following way: baseQuery = firestore.collection("transactions") .whereEqualTo("status", "success") .orderBy("__name__", Query.Direction.DESCENDING); options = new FirestorePagingOptions.Builder<ItemTxn>() .setLifecycleOwner(this) .setQuery(baseQuery, config, ItemTxn.class) .build(); adapter.updateOptions(options); https://github.com/firebase/FirebaseUI-Android/issues/1726#issuecomment-573033035
Cannot call method ViewModel from xml with dataBinding
I want to start increase the count by every second pass. When I want stop the counter by using method stopCount(), I can't call it by OnClick in xml. I got this error: e: [kapt] An exception occurred: android.databinding.tool.util.LoggedErrorException: Found data binding errors. . <data> <variable name="mainViewModel" type="com.ali.mvvm_livedata.MainViewModel"/> <variable name="count" type="String"/> </data> <android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="#={mainViewModel.liveData}" android:onClick="#{() -> mainViewModel.stopCount()}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"/> <EditText android:layout_width="0dp" android:layout_height="wrap_content" android:text="#={mainViewModel.liveData}" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent"/> </android.support.constraint.ConstraintLayout> Here my ViewModel class MainViewModel : ViewModel() { private val timer = Timer() private lateinit var timmer: TimerTask val liveData: MutableLiveData<String> = MutableLiveData() fun getTime(): MutableLiveData<String> { return liveData } fun count() { var tempCount = 0 timmer = object : TimerTask() { override fun run() { tempCount++ Log.i("currentCount", tempCount.toString()) } } timer.scheduleAtFixedRate(timmer, 1000, 1000) } internal fun stopCount() { timmer.cancel() } MainActivity code #Inject lateinit var mModelFactory: ViewModelFactory private lateinit var mainViewModel: MainViewModel override fun onCreate(savedInstanceState: Bundle?) { AndroidInjection.inject(this) super.onCreate(savedInstanceState) mainViewModel = ViewModelProviders.of(this, mModelFactory).get(MainViewModel::class.java) val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main) binding.mainViewModel = mainViewModel binding.lifecycleOwner = this mainViewModel.count() }
you have to remove the internal(front of the fun stopCount)
onClick not working in mvvm in android databinding
I am trying to implement mvvm and databinding in kotlin first time. I followed some tutorial and able to implement same. But now button click is not working which I have written in mvvm. Here is activity_login.xml <?xml version="1.0" encoding="utf-8"?> <layout xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="viewmodel" type="com.abc.abc.presentation.user.viewmodels.LoginViewModel"/> </data> <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=".presentation.user.views.LoginActivity" android:layout_margin="24dip"> <Button android:layout_width="match_parent" android:layout_height="40dip" android:background="#drawable/btn_user_create_account" android:layout_above="#+id/or_layout" android:layout_marginBottom="24dp" android:text="#string/create_account" android:id="#+id/btn_create_account" android:layout_marginEnd="12dip" android:layout_marginStart="12dip" android:gravity="center_horizontal|center_vertical" android:textColor="#color/text_color" android:textAllCaps="false" android:onClick="#{() -> viewmodel.redirectToRegisterActivity()}" android:fontFamily="#font/vollkron" android:textStyle="bold" /> <Button android:layout_width="match_parent" android:layout_height="40dip" android:background="#drawable/btn_user_login_reg" android:layout_above="#+id/btn_create_account" android:layout_marginBottom="12dp" android:text="#string/login" android:id="#+id/btn_login" android:layout_marginEnd="12dip" android:layout_marginStart="12dip" android:gravity="center_horizontal|center_vertical" android:textColor="#color/white" android:textAllCaps="false" android:onClick="#{() -> viewmodel.executeEmailLogin(context)}" android:fontFamily="#font/vollkron" android:textStyle="bold"/> </RelativeLayout> Here is my ViewModel code : class LoginViewModel(application: Application) : AndroidViewModel(application) { var email: ObservableField<String>? = null var password: ObservableField<String>? = null var progressDialog: SingleLiveEvent<Boolean>? = null var launchRegisterActivity: SingleLiveEvent<Boolean>? = null var userLogin: LiveData<User>? = null init { progressDialog = SingleLiveEvent<Boolean>() launchRegisterActivity = SingleLiveEvent<Boolean>() email = ObservableField("") password = ObservableField("") userLogin = MutableLiveData() } fun redirectToRegisterActivity() { launchRegisterActivity?.value = true } fun executeEmailLogin(context: Context) { progressDialog?.value = true val user = User( email = email.toString(), password = password.toString(), ) userLogin = UserRepository.getInstance().registerUserUsingEmail(context, user) } } Here is my Login Activity class LoginActivity : AppCompatActivity() { var binding: ActivityLoginBinding? = null var viewModel: LoginViewModel? = null var customProgressDialog: CustomProgressDialog? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) FacebookSdk.sdkInitialize(applicationContext); binding = DataBindingUtil.setContentView(this, R.layout.activity_login) customProgressDialog = CustomProgressDialog(this) viewModel = ViewModelProviders.of(this).get(LoginViewModel::class.java) observeViewModel(viewModel!!) } private fun observeViewModel(viewModel: LoginViewModel) { viewModel.progressDialog?.observe(this, Observer { if (it!!) customProgressDialog?.show() else customProgressDialog?.dismiss() }) viewModel.launchRegisterActivity?.observe(this, Observer { if (it!!) startActivity(Intent(this, RegisterActivity::class.java)) }) viewModel.userLogin?.observe(this, Observer { user -> // redirect user to home scree Toast.makeText(this, "welcome, ${user?.user_name}", Toast.LENGTH_LONG).show() }) } } Can you please help me to understand what things I am doing wrong here. Do I implemented mvvm correctly? Any button click is not working.
I think, You forgot to bind viewmodel to databinding. Add this in onCreate of LoginActivity : binding.lifecycleOwner = this binding.viewmodel = viewModel
Try adding binding.lifecycleOwner = this after inflating your layout.