Why did my button activity cannot run me to the other page? - kotlin

This is my button.
I not sure if that my button have the problem or the kotlin files have the problem. The Home fragment is using binding to bind with the home fragment. Maybe is the intent in the fragment have the problem?
<Button
android:id="#+id/registerbutton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="14dp"
android:text="#string/register"
android:textAllCaps="false"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/editText3"
app:layout_constraintWidth_percent=".8"
android:background="#drawable/btn_bg_design"
app:layout_constraintVertical_bias="0.6"
/>
This is my registration activity
class RegistrationActivity : AppCompatActivity() {
private lateinit var binding:ActivityRegistrationBinding
private lateinit var db: FirebaseFirestore
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityRegistrationBinding.inflate(layoutInflater)
setContentView(R.layout.activity_registration)
db = FirebaseFirestore.getInstance() // singleton
binding.registerbutton.setOnClickListener{
val fullName = binding.editText1.text.toString()
val email = binding.editText2.text.toString()
val password = binding.editText3.text.toString()
val register = Register(fullName,email, password)
// pass the User data obj to the firestore
db.collection("Register").document("$email").set(register)
intent = Intent(this, MainActivity:: class.java)
Intent(this, HomeFragment:: class.java).putExtra("email",email)
startActivity(intent)
}
}
fun login(view: View) {
intent = Intent(this, LoginActivity:: class.java)
startActivity(intent)
}
}
This is my homefragment
class HomeFragment : Fragment() {
//private lateinit var homeViewModel: HomeViewModel (delete)
private var _binding: FragmentHomeBinding? = null
private lateinit var db: FirebaseFirestore
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
val root: View = binding.root
db = FirebaseFirestore.getInstance()
val intent = Intent(activity,RegistrationActivity::class.java)
val email = intent.getStringExtra("email")
db.collection("Register").document("$email").get()
.addOnSuccessListener { doc->
binding.textViewName.text = doc.get("fullName").toString()
}
.addOnFailureListener {
Log.e("Firestore", "Error in loading file: ${it.toString()}")
}
return root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

Try to change the code in RegistrationActivity like this:
binding.registerbutton.setOnClickListener{
val fullName = binding.editText1.text.toString()
val email = binding.editText2.text.toString()
val password = binding.editText3.text.toString()
val register = Register(fullName,email, password)
// pass the User data obj to the firestore
db.collection("Register").document("$email").set(register)
val intent = Intent(this, MainActivity:: class.java)
intent.putExtra("email", email)
startActivity(intent)
}
Also, you should pass the data to the fragment using a Bundle:
val bundle = Bundle()
bundle.putString("email", email)
homeFragment.arguments = bundle
And retrieve it in the fragment using the arguments object:
val email = arguments?.getString("email") ?: ""

Related

E/RecyclerView: No adapter attached; skipping layout ERROR (FragmentHome)

I have a problem with RecyclerView in a Fragment. In FeedActivity. I want to show the RecyclerView in my first tab but I keep getting the following error:
I am getting this error when displaying recylerview inside home fragment.
recyclerview is not displayed on the screen at all.
I tried to run it under Oncreate() but it didn't work, how can I do it?
Can you help me how can I solve this?enter image description here
**class HomeFragment : Fragment() {**
private lateinit var auth : FirebaseAuth
private lateinit var db : FirebaseFirestore
private lateinit var binding: FragmentHomeBinding
val postArrayList : ArrayList<Post> = ArrayList()
var adapter : FeedRecyclerAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_home, container, false)
return view
** binding.recyclerView.layoutManager = LinearLayoutManager(activity)
adapter = FeedRecyclerAdapter(postArrayList)
binding.recyclerView.adapter = adapter**
auth = FirebaseAuth.getInstance()
db = FirebaseFirestore.getInstance()
getDataFromFirestore()
}
fun getDataFromFirestore() {
db.collection("Posts").orderBy("date",
Query.Direction.DESCENDING).addSnapshotListener { snapshot, exception ->
if (exception != null) {
Toast.makeText(context,exception.localizedMessage, Toast.LENGTH_LONG).show()
} else {
if (snapshot != null) {
if (!snapshot.isEmpty) {
postArrayList.clear()
val documents = snapshot.documents
for (document in documents) {
val comment = document.get("comment") as String
val useremail = document.get("userEmail") as String
val downloadUrl = document.get("downloadUrl") as String
//val timestamp = document.get("date") as Timestamp
//val date = timestamp.toDate()
val post = Post(useremail,comment, downloadUrl)
postArrayList.add(post)
}
adapter!!.notifyDataSetChanged()
}
}
}
}
}
}
**class FeedRecyclerAdapter(private val postList : ArrayList<Post>) : RecyclerView.Adapter<FeedRecyclerAdapter.PostHolder>() {**
class PostHolder(val binding: RecyclerRowBinding) : RecyclerView.ViewHolder(binding.root) {
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostHolder {
val binding = RecyclerRowBinding.inflate(LayoutInflater.from(parent.context),parent,false)
return PostHolder(binding)
}
override fun getItemCount(): Int {
return postList.size
}
override fun onBindViewHolder(holder: PostHolder, position: Int) {
holder.binding.recyclerEmailText.text = postList.get(position).email
holder.binding.recyclerCommentText.text = postList.get(position).comment
Picasso.get().load(postList[position].downloadUrl).into(holder.binding.recyclerImageView)
}
}
Here you should return the view at the ed of the function, after you set your recyclerView:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_home, container, false)
return view //here this should be at the end
** binding.recyclerView.layoutManager = LinearLayoutManager(activity)
adapter = FeedRecyclerAdapter(postArrayList)
binding.recyclerView.adapter = adapter**
auth = FirebaseAuth.getInstance()
db = FirebaseFirestore.getInstance()
getDataFromFirestore()
}
Must be like this:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_home, container, false)
** binding.recyclerView.layoutManager = LinearLayoutManager(activity)
adapter = FeedRecyclerAdapter(postArrayList)
binding.recyclerView.adapter = adapter**
auth = FirebaseAuth.getInstance()
db = FirebaseFirestore.getInstance()
getDataFromFirestore()
return view //should be here
}
The solution is like this :
To solve the problem, I took the val view to the end, and then I encountered a new error, which I understood while solving it.
binding = FragmentHomeBinding.inflate(layoutInflater)
val view = binding.root
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
binding = FragmentHomeBinding.inflate(layoutInflater)
val view = binding.root
binding.recyclerView.layoutManager = LinearLayoutManager(activity)
adapter = FeedRecyclerAdapter(postArrayList)
binding.recyclerView.adapter = adapter
auth = FirebaseAuth.getInstance()
db = FirebaseFirestore.getInstance()
getDataFromFirestore()
return view

MVVM Navigation fragments switch, but change is not visible

I am trying to build a simple app in Kotlin using MVVM architecture, and I'm struggling with switching fragments. I get it to "change" - on a button press it does nothing, and on a second press it crashes saying "Navigation action/destination MAIN_to_RESULT cannot be found from the current destination RESULT" - so it clearly changed the fragments from MAIN to RESULT, but I still see the MAIN fragment)
Here is my MAIN fragment:
class MainFragment : Fragment() {
private lateinit var viewModel: MainViewModel
lateinit var binding: FragmentMainBinding
companion object {
fun newInstance() = MainFragment()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = (activity as MainActivity).viewModel
binding.setVariable(myViewModel, viewModel)
viewModel.bnd = binding
binding.button2.setOnClickListener { viewModel.chng() }
binding.submitButton.setOnClickListener {
val controller = NavHostFragment.findNavController(this)
controller.navigate(R.id.action_mainFragment_to_resultFragment)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_main, container, false)
binding.setLifecycleOwner(this)
return binding.root
}
}
OTHER fragment:
class ResultFragment : Fragment() {
private lateinit var viewModel: MainViewModel
lateinit var binding: FragmentMainBinding
companion object {
fun newInstance() = ResultFragment()
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_main, container, false)
binding.setLifecycleOwner(this)
return binding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = (activity as MainActivity).viewModel
binding.setVariable(BR.myViewModel, viewModel)
binding.button2.setOnClickListener { viewModel.chng() }
viewModel.bnd = binding
}
}
MainViewModel:
class MainViewModel(application: Application) : AndroidViewModel(application) {
val rps = Repository()
lateinit var bnd : FragmentMainBinding
var changing = false
var SPEED_OF_CHANGING = 100L
var actualCountedCards = 0
var numberOfCardsToRotate = 0
var numberOfRotatedCards = 0
lateinit var actualCard : Card
var mainHandler: Handler = Handler(Looper.getMainLooper())
private val changeCard = object : Runnable {
override fun run() {
if (changing) {
actualCard = rps.Cards.random()
bnd.cardView.setImageResource(actualCard.image)
actualCountedCards += actualCard.power
numberOfRotatedCards += 1
Log.d("tagicek", "${numberOfRotatedCards}/${numberOfCardsToRotate}, ${actualCountedCards}")
if (numberOfRotatedCards >= numberOfCardsToRotate) {
chng()
bnd.editTextTextPersonName.visibility = View.VISIBLE
bnd.submitButton.visibility = View.VISIBLE
bnd.button2.visibility = View.INVISIBLE
}
mainHandler.postDelayed(this, SPEED_OF_CHANGING)
}
}
}
fun chng() {
if (changing == true) {
mainHandler.removeCallbacks(changeCard)
actualCountedCards = 0
numberOfRotatedCards = 0
bnd.cardView.setImageResource(R.drawable.bg)
changing = false
} else {
numberOfCardsToRotate = (1..51).random()
mainHandler.post(changeCard)
changing = true
}
}
}
MainActivity:
class MainActivity : AppCompatActivity() {
lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this)[MainViewModel::class.java]
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.container, MainFragment.newInstance())
.commitNow()
}
}
}
I am pretty sure the problem is with my bindings and views, but I can't wrap my head around it. I have tried probably every positioning of defining the NavController and the different views passed into it, but it still doesn't work.

RecyclerView with coroutines, using Fragment doesn't populate data Kotlin

I am trying to work wih courutines and recycler view. I've done everything necessary to send requests to the API, but I still can't get the list that should be inside the recycler view. I am using fragment to create list and bottom nav. When I go to the fragment where my list should be, then I get the error: RecyclerView: No layout manager attached; skipping layoutand nothing more. I googled about this error and it says I should define the layout manager in xml, but it alreadt has layuout manager in my fragment
<androidx.recyclerview.widget.RecyclerView 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/list_item"
app:layoutManager="LinearLayoutManager"
Also my adapter and fragment for recycler view look like this:
class MyItemRecyclerViewAdapter(
) : RecyclerView.Adapter<MyItemRecyclerViewAdapter.ViewHolder>() {
var userNameResponse = mutableListOf<UsersNameItem>()
fun setNamesList(names: List<UsersNameItem>) {
this.userNameResponse = userNameResponse.toMutableList()
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
FragmentItemBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = userNameResponse[position]
holder.idView.text = item.id
holder.contentView.text = item.name
}
override fun getItemCount(): Int = userNameResponse.size
class ViewHolder(binding: FragmentItemBinding) : RecyclerView.ViewHolder(binding.root) {
val idView: TextView = binding.itemNumber
val contentView: TextView = binding.content
}
}
Fragment:
class ItemFragment : Fragment() {
private var layoutManager: RecyclerView.LayoutManager? = null
private var adapter: RecyclerView.Adapter<MyItemRecyclerViewAdapter.ViewHolder>? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_item_list, container, false)
}
override fun onViewCreated(itemView: View, savedInstanceState: Bundle?) {
super.onViewCreated(itemView, savedInstanceState)
layoutInflater.apply {
layoutManager = LinearLayoutManager(activity)
adapter = MyItemRecyclerViewAdapter()
}
}
companion object {
fun newInstance() = ItemFragment()
}
}
And MainActivity where I set up courutines and trying to make a request:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
lateinit var nameviewModel: ListNamesViewModel
val adapter = MyItemRecyclerViewAdapter()
///trying to create http-request for lists
val retrofitService = BasicApiService.getInstance()
val mainRepository = MainRepository(retrofitService)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
nameviewModel = ViewModelProvider(
this,
MyViewModelFactory(mainRepository)
)[ListNamesViewModel::class.java]
nameviewModel.userName.observe(
this, Observer {
adapter.setNamesList(it)
})
nameviewModel.message.observe(this) {
Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
}
nameviewModel.loadUsers()
val navView: BottomNavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_activity_main)
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home,
R.id.navigation_dashboard,
R.id.navigation_notifications,
R.id.list_name_navig
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
}
Also I wanted to ask (I am very new to Kotlin nad just trying to make things work) if it is a good practice to leave request to API in the MainActivity ot I should do it in another way?
I see some confusion in your code, try to apply the next:
Why are you creating the layoutManager and adapter in the ItemFragment?
override fun onViewCreated(itemView: View, savedInstanceState: Bundle?) {
super.onViewCreated(itemView, savedInstanceState)
layoutInflater.apply {
layoutManager = LinearLayoutManager(activity)
adapter = MyItemRecyclerViewAdapter()
}
}
You need to move it and RecyclerView to your activity.
The using layoutInflater.apply {} doesn't make sense, it's doing nothing in your case. You need to set layoutManager and adapter to recyclerView then in the activity it should look like that (and rename list_item to recyclerView)
binding.recyclerView.apply {
layoutManager = LinearLayoutManager(this)
adapter = MyItemRecyclerViewAdapter()
}
Remove app:layoutManager="LinearLayoutManager" from XML.
It looks like you don't need to use ItemFragment for your purpose because you use it just like a view and binding in the ViewHolder
class ViewHolder(binding: FragmentItemBinding) : RecyclerView.ViewHolder(binding.root) {
val idView: TextView = binding.itemNumber
val contentView: TextView = binding.content
}
try changing in xml
app:layoutManager="LinearLayoutManager"
to
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"

Obtain a crash message-App keeps stopping

I get the following trace error java.lang.ClassCastException: com.example.myhouse.MainActivity cannot be cast to com.brsthegck.kanbanboard.TasklistFragment$Callbacks at com.brsthegck.kanbanboard.TasklistFragment.onAttach(TasklistFragment.kt:52)at androidx.fragment.app.Fragment.performAttach(Fragment.java:2672) at androidx.fragment.app.FragmentStateManager.attach(FragmentStateManager.java:263) at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1170) at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
enter image description here
Tasklist Fragment
private const val ARG_TASKLIST_TYPE = "tasklist_type"
private const val TASKLIST_TYPE_TODO = 0
private const val TASKLIST_TYPE_DOING = 1
private const val TASKLIST_TYPE_DONE = 2
class TasklistFragment : Fragment(){
private lateinit var visibleColorPaletteViewList : List<View>
lateinit var taskRecyclerView: RecyclerView
private var tasklistType : Int = -1
private var adapter : TaskViewAdapter? = TaskViewAdapter(LinkedList<Task>())
private var colorPaletteIsVisible : Boolean = false
private var callbacks: Callbacks? = null
//Callback interface to delegate access functions in MainActivity
interface Callbacks{
fun addTaskToViewModel(task: Task, destinationTasklistType: Int)
fun deleteTaskFromViewModel(tasklistType: Int, adapterPosition: Int)
fun getTaskListFromViewModel(tasklistType: Int) : LinkedList<Task>
}
//Attach context as a Callbacks reference to the callbacks variable when fragment attaches to container
override fun onAttach(context: Context) {
super.onAttach(context)
callbacks = activity as Callbacks? // error is here
}
//Detach context (assign to null) when fragment detaches from container
override fun onDetach() {
super.onDetach()
callbacks = null
}
//ItemTouchHelper instance with custom callback, to move task card view positions on hold
private val itemTouchHelper by lazy{
val taskItemTouchCallback = object : ItemTouchHelper.SimpleCallback(UP or DOWN, 0){
override fun onMove(recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder): Boolean {
val adapter = recyclerView.adapter as TaskViewAdapter
val from = viewHolder.adapterPosition
val to = target.adapterPosition
adapter.moveTaskView(from, to)
adapter.notifyItemMoved(from, to)
return true
}
//Make taskview transparent while being moved
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
super.onSelectedChanged(viewHolder, actionState)
if(actionState == ACTION_STATE_DRAG)
viewHolder?.itemView?.alpha = 0.7f
}
//Make taskview opaque while being
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
super.clearView(recyclerView, viewHolder)
viewHolder.itemView.alpha = 1.0f
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { /* Not implemented on purpose. */ }
}
ItemTouchHelper(taskItemTouchCallback)
}
//Get the fragment arguments, tasklist type to be precise, and assign it to the member of this fragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
tasklistType = arguments?.getInt(ARG_TASKLIST_TYPE) as Int
}
//Inflate view of fragment, prepare recycler view and it's layout manager, and update the UI
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View?{
//Inflate the layout of this fragment, get recyclerview ref, set layout manager for recycler view
val view = inflater.inflate(R.layout.tasklist_fragment_layout, container,false)
taskRecyclerView = view.findViewById(R.id.task_recycler_view) as RecyclerView
taskRecyclerView.layoutManager = LinearLayoutManager(context)
itemTouchHelper.attachToRecyclerView(taskRecyclerView)
//Fill the recyclerview with data from viewmodel
updateInterface()
//Return the created view
return view
}
//Populate recyclerview and set up its adapter
private fun updateInterface(){
val tasks = callbacks!!.getTaskListFromViewModel(tasklistType)
adapter = TaskViewAdapter(tasks)
taskRecyclerView.adapter = adapter
}
Kanban class
class Kanban : Fragment(), TasklistFragment.Callbacks{
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
private lateinit var viewPager: ViewPager2
private lateinit var tabLayout: TabLayout
private lateinit var taskViewModel: TaskViewModel
//When add action bar button is pressed
override fun onOptionsItemSelected(item: MenuItem) = when(item.itemId) {
R.id.action_new_task -> {
val currentTasklistType = viewPager.currentItem
val currentTasklist = when (currentTasklistType) {
TASKLIST_TYPE_TODO -> taskViewModel.todoTaskList
TASKLIST_TYPE_DOING -> taskViewModel.doingTaskList
TASKLIST_TYPE_DONE -> taskViewModel.doneTaskList
else -> throw Exception("Unrecognized tasklist type")
}
val currentFragment = (activity?.supportFragmentManager?.fragments?.get(currentTasklistType) as TasklistFragment)
addTaskToViewModel(Task(), currentTasklistType)
currentFragment.taskRecyclerView.scrollToPosition(currentTasklist.size - 1)
true
}
else -> super.onOptionsItemSelected(item)
}
//Inflate the action bar menu resource on options menu creation
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_action_bar, menu)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
//Get viewmodel
val view: View = inflater.inflate(R.layout.fragment_kanban2, container, false)
taskViewModel = ViewModelProvider(this).get(TaskViewModel::class.java)
//Read tasklist data from shared prefs and populate viewmodel lists with it
readSharedPrefsToViewModel()
//Get ref to viewpager and set up its adapter & attributes
viewPager = view.findViewById(R.id.view_pager)
val viewPagerAdapter = TasklistFragmentStateAdapter(this)
viewPager.apply {
adapter = viewPagerAdapter
offscreenPageLimit = 2
//Get ref to tablayout, set up & attach its mediator
tabLayout = view.findViewById(R.id.tab_layout)
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
tab.text = when (position) {
0 -> getString(R.string.tab_label_todo)
1 -> getString(R.string.tab_label_doing)
else -> getString(R.string.tab_label_done)
}
}.attach()
}
return view
}
override fun onStop() {
super.onStop()
writeViewModelToSharedPrefs()
}
//Adapter class for view pager
private inner class TasklistFragmentStateAdapter(fa: Kanban) : FragmentStateAdapter(fa){
override fun createFragment(position: Int): Fragment {
//Create argument bundle with task list type
val tasklistFragmentArguments = Bundle().apply{
putInt(ARG_TASKLIST_TYPE, position)
}
//Attach the argument bundle to new fragment instance and return the fragment
return TasklistFragment().apply{
arguments = tasklistFragmentArguments
}
}
override fun getItemCount(): Int = NUM_TASKLIST_PAGES
}
override fun addTaskToViewModel(task: Task, destinationTasklistType: Int) {
val destinationFragment = (activity?.supportFragmentManager?.fragments?.get(destinationTasklistType) as TasklistFragment)
val taskList = getTaskListFromViewModel(destinationTasklistType)
taskList.add(task)
destinationFragment.taskRecyclerView.adapter?.notifyItemInserted(taskList.size)
}
override fun deleteTaskFromViewModel(tasklistType: Int, adapterPosition: Int) {
val tasklistFragment = (activity?.supportFragmentManager?.fragments?.get(tasklistType) as TasklistFragment)
getTaskListFromViewModel(tasklistType).removeAt(adapterPosition)
tasklistFragment.taskRecyclerView.adapter?.notifyItemRemoved(adapterPosition)
}
override fun getTaskListFromViewModel(tasklistType: Int): LinkedList<Task> =
when(tasklistType){
TASKLIST_TYPE_TODO -> taskViewModel.todoTaskList
TASKLIST_TYPE_DOING -> taskViewModel.doingTaskList
TASKLIST_TYPE_DONE -> taskViewModel.doneTaskList
else -> throw Exception("Unrecognized tasklist type") }
private fun writeViewModelToSharedPrefs(){
val gson = Gson()
//Convert list to json string
val todoJSON = gson.toJson(taskViewModel.todoTaskList)
val doingJSON = gson.toJson(taskViewModel.doingTaskList)
val doneJSON = gson.toJson(taskViewModel.doneTaskList)
var sharedPref : SharedPreferences = requireActivity().getPreferences(Context.MODE_PRIVATE);
//Save json strings into shared preferences
activity?.getPreferences(MODE_PRIVATE)?.edit()?.apply {
putString(KEY_TODO_JSON, todoJSON)
putString(KEY_DOING_JSON, doingJSON)
putString(KEY_DONE_JSON, doneJSON)
}?.apply()
}
private fun readSharedPrefsToViewModel(){
val gson = Gson()
val sharedPrefs = activity?.getPreferences(MODE_PRIVATE)
val todoJSON = sharedPrefs?.getString(KEY_TODO_JSON, "[]")
val doingJSON = sharedPrefs?.getString(KEY_DOING_JSON, "[]")
val doneJSON = sharedPrefs?.getString(KEY_DONE_JSON, "[]")
val type = object: TypeToken<LinkedList<Task>>() {}.type //Gson requires type ref for generic types
taskViewModel.todoTaskList = gson.fromJson(todoJSON, type)
taskViewModel.doingTaskList = gson.fromJson(doingJSON, type)
taskViewModel.doneTaskList = gson.fromJson(doneJSON, type)
}
Main activity
public class MainActivity extends AppCompatActivity {
private TabLayout tabLayout;
private ViewPager2 viewPager2;
private MyFragment adapter;
private TextView register;
GridView contractorsGV;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabLayout = findViewById(R.id.tabLayout);
viewPager2 = findViewById(R.id.viewPager2);
tabLayout.addTab(tabLayout.newTab().setText("Home"));
tabLayout.addTab(tabLayout.newTab().setText("Idea Book"));
tabLayout.addTab(tabLayout.newTab().setText("My Profile"));
FragmentManager fragmentManager = getSupportFragmentManager();
adapter = new MyFragment(fragmentManager , getLifecycle());
viewPager2.setAdapter(adapter);
4. Fragment manager
public class MyFragment extends FragmentStateAdapter {
public MyFragment(#NonNull FragmentManager fm,Lifecycle lifecycle) {
super(fm,lifecycle);
}
#NonNull
#Override
public Fragment createFragment(int position) {
if(position==1)
{
return new Kanban();
}
if(position==2) {
return new signOut();
}
return new Navigation_Bar();
}

How to add ViewModel to a project which uses ViewPager and Tablayout?

Hello i am new in Android Development so maybe this question can be weird for you.
I have a class named IdentityCardInfo which has variables. And I am getting this variables in InfoFragment.
From InfoFragment I want to show these variables in a ResultsFragment wihch has 3 tabs with tablayout.
I want to use ViewModel to pass data to tablayouts but I don't know how to use I've searched but get stuck.
Here is code for IdentityCardInfo class:
class IdentityCardInfo {
companion object AppConstant{
const val serieNo ="67G74444"
const val validDate = "01/01/2022"
const val dateOfBirth = "10/08/1998"
const val fullName = "Muhittin KAYA"
const val identityNo: Long = 11111111111
const val gender = "MALE"
const val nationality = "TUR"
}
}
Here is code for InfoFragment:
class InfoFragment : BaseFragment() {
lateinit var navController: NavController
companion object {
private const val TAG = "Info Fragment"
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_info, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
navController = Navigation.findNavController(view)
button_info_idcard.setOnClickListener {
//start OcrActivity
val intent = Intent(activity, OcrActivity::class.java)
startActivityForResult(intent, 101)
}
imagebutton_info_settings.setOnClickListener {
navController.navigate(R.id.action_infoFragment_to_settingsFragment)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Log.i("Muhittin", "onActivityResult()")
if (requestCode == 101) {
val message = data?.getStringExtra("TEST_TEXT")
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
val serieNo = IdentityCardInfo.serieNo
val validDate = IdentityCardInfo.validDate
val dateOfBirth = IdentityCardInfo.dateOfBirth
val fullname = IdentityCardInfo.fullName
val gender = IdentityCardInfo.gender
val identityNo = IdentityCardInfo.identityNo
val nationality = IdentityCardInfo.nationality
val bundle = bundleOf(
"TEST_TEXT" to message,
"SERIE_NO" to serieNo,
"VALID_DATE" to validDate,
"DOB" to dateOfBirth,
"FULL_NAME" to fullname,
"GENDER" to gender,
"IDENTITY_NO" to identityNo,
"NATIONALITY" to nationality
)
navController.navigate(
R.id.action_infoFragment_to_detailFragment,
bundle
)
}
}
}
This is for ResultsFragment: (I don't add tablayout code and viewpager code)
class ResultsFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_results, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val tabLayout: TabLayout = requireView().findViewById(R.id.tabLayout_results)
tabLayout.tabGravity = TabLayout.GRAVITY_FILL
val tabTitles = arrayOf(
resources.getString(R.string.result_tab1_name),
resources.getString(R.string.result_tab2_name),
resources.getString(R.string.result_tab3_name)
)
val viewPager: ViewPager = requireView().findViewById(R.id.viewpager_results)
viewPager.offscreenPageLimit = 3
val adapter = PagerAdapter(fragmentManager, tabTitles)
viewPager.adapter = adapter
tabLayout.setupWithViewPager(viewPager)
}
}
If you want to use ViewModels to pass data between fragments in the same activity, here's the Android documentation about it. It lets the fragments access a shared object without needing to know about each other, or communicate through the activity (with a bunch of code just to enable that communication)
You'd basically do something like this:
// create a ViewModel that holds the data you want to share
class IdentityCardViewModel : ViewModel() {
val identityInfo = MutableLiveData<IdentityCardInfo>()
fun setInfo(info: IdentityCardInfo) {
identityInfo.value = info
}
}
Then each fragment would grab a copy of the same ViewModel instance by doing:
// Get a reference to the IdentityCardViewModel created and held by the activity
private val model: IdentityCardViewModel by activityViewModels()
and then InfoFragment can set the data with model.setInfo(yourIdentityCardInfo). ResultsFragmentcan observe this data and do something whenever it sees a new value:
model.identityInfo.observe(viewLifecycleOwner, Observer<IdentityCardInfo> { info ->
// Do whatever you need with the updated info, like displaying it
})
#muhittin kaya Refer below code to resolve your issue
InfoFragment
class InfoFragment : BaseFragment() {
lateinit var navController: NavController
// Initialize your variable
lateinit var infoFragmentInterface: InfoFragmentDataInterface
// If you get initialization exception then uncomment below line and comment above line
//private var infoFragmentInterface: InfoFragmentDataInterface? = null
companion object {
private const val TAG = "Info Fragment"
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_info, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
navController = Navigation.findNavController(view)
button_info_idcard.setOnClickListener {
//start OcrActivity
val intent = Intent(activity, OcrActivity::class.java)
startActivityForResult(intent, 101)
}
imagebutton_info_settings.setOnClickListener {
navController.navigate(R.id.action_infoFragment_to_settingsFragment)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Log.i("Muhittin", "onActivityResult()")
if (requestCode == 101) {
val message = data?.getStringExtra("TEST_TEXT")
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
val serieNo = IdentityCardInfo.serieNo
val validDate = IdentityCardInfo.validDate
val dateOfBirth = IdentityCardInfo.dateOfBirth
val fullname = IdentityCardInfo.fullName
val gender = IdentityCardInfo.gender
val identityNo = IdentityCardInfo.identityNo
val nationality = IdentityCardInfo.nationality
val bundle = bundleOf(
"TEST_TEXT" to message,
"SERIE_NO" to serieNo,
"VALID_DATE" to validDate,
"DOB" to dateOfBirth,
"FULL_NAME" to fullname,
"GENDER" to gender,
"IDENTITY_NO" to identityNo,
"NATIONALITY" to nationality
)
//Add This line for passing your data
//You can also pass string data here
infoFragmentInterface.getInfoFragmentData(bundle)
navController.navigate(
R.id.action_infoFragment_to_detailFragment,
bundle
)
}
}
}
// Create this interface to pass your data
interface InfoFragmentDataInterface {
fun getInfoFragmentData(bundle: Any)
}
ResultsFragment
class ResultsFragment : Fragment(), InfoFragmentDataInterface {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_results, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val tabLayout: TabLayout = requireView().findViewById(R.id.tabLayout_results)
tabLayout.tabGravity = TabLayout.GRAVITY_FILL
val tabTitles = arrayOf(
resources.getString(R.string.result_tab1_name),
resources.getString(R.string.result_tab2_name),
resources.getString(R.string.result_tab3_name)
)
val viewPager: ViewPager = requireView().findViewById(R.id.viewpager_results)
viewPager.offscreenPageLimit = 3
val adapter = PagerAdapter(fragmentManager, tabTitles)
viewPager.adapter = adapter
tabLayout.setupWithViewPager(viewPager)
}
override fun getInfoFragmentData(bundle: Any) {
// You'll get your Bundle data here.
}
}