I am developing new app when I run project I am getting following java.lang.ClassCastException: com.example.runtrackerapp.ui.MainActivity cannot be cast to com.example.runtrackerapp.databinding.ActivityMainBinding
at com.example.runtrackerapp.ui.fragments.SetupFragment.writePersonalDataToSharedPref(SetupFragment.kt:84)
at com.example.runtrackerapp.ui.fragments.SetupFragment.onViewCreated$lambda-0(SetupFragment.kt:60)
at com.example.runtrackerapp.ui.fragments.SetupFragment.$r8$lambda$4d3caNvVygzMMPPCQbih5sKklFY(Unknown Source:0)
at com.example.runtrackerapp.ui.fragments.SetupFragment$$ExternalSyntheticLambda0.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:6614)
at android.view.View.performClickInternal(View.java:6587)
at android.view.View.access$3100(View.java:787)
at android.view.View$PerformClick.run(View.java:26122)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:201)
below my SetupFragment.kt where exception occuring
#AndroidEntryPoint
class SetupFragment : Fragment() {
private var _binding: FragmentSetupBinding? = null
private val binding get() = _binding!!
#Inject
lateinit var sharedPref: SharedPreferences
#set:Inject
var isFirstAppOpen = true
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// inflate the layout and bind to the _binding
_binding = FragmentSetupBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if(!isFirstAppOpen){
val navOptions = NavOptions.Builder()
.setPopUpTo(R.id.setupFragment, true)
.build()
findNavController().navigate(
R.id.action_setupFragment_to_runFragment,
savedInstanceState,
navOptions)
}
binding.tvContinue.setOnClickListener {
val success = writePersonalDataToSharedPref()
if (success){
findNavController().navigate(R.id.action_setupFragment_to_runFragment)
}else{
Snackbar.make(requireView(), "Please enter all the fields", Snackbar.LENGTH_SHORT).show()
}
}
}
private fun writePersonalDataToSharedPref(): Boolean {
val name = binding.etName.text.toString()
val weight = binding.etWeight.text.toString()
if(name.isEmpty() || weight.isEmpty()) {
return false
}
sharedPref.edit()
.putString(KEY_NAME, name)
.putFloat(KEY_WEIGHT, weight.toFloat())
.putBoolean(KEY_FIRST_TIME_TOGGLE, false)
.apply()
val toolbarText = "Let's go, $name!"
(requireActivity() as ActivityMainBinding).tvToolbarTitle.text = toolbarText
return true
}
}
I want to know exactly where I am making mistake
(requireActivity() as MainActivity).tvToolbarTitle.text = toolbarText
or
(requireActivity() as MainActivity).binding.tvToolbarTitle.text = toolbarText
error is with ActivityMainBinding this line add your activity name here like (MainActivity)
(requireActivity() as ActivityMainBinding)
This is the problem statement .. You can not cast Activity to a Binding Object because they are not related in any way ..
Although this is a wrong approach IMO . for now to make it work you can make your binding object public . and access it as below .
(requireActivity() as MainActivity).binding.tvToolbarTitle.text = toolbarText
For a better implementation you can use a SharedViewModel . Or have the toolbar in fragment itself if possible.
Related
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
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.
I want to use currentItem on Fragments in viewpager2
ViewPager is also fragment. and my all fragments have viewbinding.
My fragment call viewpager by findViewById. But It isn't worked. It's data is always 'null'. Can I use findviewbyid and viewbinding both of them? I already tried to use findViewbyID in onviewcreated or oncreateview Please help me
pagertest.kt(first page fragment)
class pagertest : Fragment() {
private var _binding: FragmentPagertestBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
_binding = FragmentPagertestBinding.inflate(inflater, container, false)
binding.button5.setOnClickListener {
val pager = activity?.findViewById<ViewPager2>(R.id.dayspager22)
pager?.currentItem = 2
}
return binding.root
}
}
dayspager22.kt(ViewPagerFragment)
class dayspager22 : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
private var _binding: FragmentDayspager22Binding? = null
private val binding get() = _binding!!
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? {
_binding = FragmentDayspager22Binding.inflate(inflater, container, false)
val fragmentList = arrayListOf<Fragment>(
pagertest(),
days_1(),
days_2(),
days_3()
)
val adapter = ViewPagerAdapter(
fragmentList,
requireActivity().supportFragmentManager,
lifecycle
)
binding.views.adapter = adapter
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment dayspager22.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
dayspager22().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
ViewPage Adapter
class ViewPagerAdapter(
list: ArrayList<Fragment>,
fm: FragmentManager,
lifecycle: Lifecycle
) : FragmentStateAdapter(fm, lifecycle) {
private val fragmentList = list
override fun getItemCount(): Int {
return fragmentList.size
}
override fun createFragment(position: Int): Fragment {
return fragmentList[position]
}
}
I think it might be because you're creating and adding pagertest to the adapter inside dayspager22's onCreateView method. You haven't returned its layout view yet, so it's not added to the Activity's layout - and if it's not added, you won't be able to find it with findViewById. (I'm not sure exactly when pagertest's onCreateView runs here, but I'd look into that possibility.)
Also make sure fragment_dayspager_22.xml or whatever actually has a ViewPager2 with an id of dayspager22 - you're setting your adapter on something called views:
val adapter = ViewPagerAdapter(
fragmentList,
requireActivity().supportFragmentManager,
lifecycle
)
// you're setting a ViewPagerAdapter on something that's probably a ViewPager,
// and its id is R.id.views
binding.views.adapter = adapter
Are you sure that's not the ID you want to look up with findViewById?
***I am trying to create af spinningWheel animation with my imageView spinning once the button is pressed. I found a youtube video with some java code i converted into kotlin. With the code below nothing happens when the button is pushed. I have used the rotateAnimation class and some calculations in the GameViewModel thus far, and call the spin() in the GameFragment class' onCreateView().
The code below are the two classes i use for the rotateAnimation but it doesn't seem to work. I am not sure which part is the problem. Does anyone know?***
class GameViewModel : ViewModel() {
private val fields = arrayOf("1","2","3","4","5","6","7")
private val fieldDegrees = IntArray(fields.size)
private var degree = 0
var isSpinning = false
fun getDegreesForSectors(){
val oneFieldsDegrees = 360/fields.size
for (i in fields.indices){
fieldDegrees[i] = (i+1) * oneFieldsDegrees
}
}
fun spin(imageView: ImageView){
isSpinning = true
degree = (0..fields.size).random()
val rotateAnimation = RotateAnimation(0.toFloat(),
(360 * fields.size + fieldDegrees[degree]).toFloat(),
RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f)
rotateAnimation.setDuration(3600)
rotateAnimation.setFillAfter(true)
rotateAnimation.setInterpolator(DecelerateInterpolator())
rotateAnimation.setAnimationListener(object : Animation.AnimationListener{
override fun onAnimationStart(animation: Animation) {}
override fun onAnimationEnd(animation: Animation) {
isSpinning = false
}
override fun onAnimationRepeat(animation: Animation) {}
})
imageView.startAnimation(rotateAnimation)
}
}
class GameFragment : Fragment() {
private lateinit var gameViewModel: GameViewModel
private var _binding: GameFragmentBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
gameViewModel =
ViewModelProvider(this).get(GameViewModel::class.java)
val spinBtn: Button? = view?.findViewById(R.id.spinBtn)
val wheelImage: ImageView? = view?.findViewById(R.id.Spinning_Wheel)
gameViewModel.getDegreesForSectors()
spinBtn?.setOnClickListener() {
if (!gameViewModel.isSpinning) {
gameViewModel.spin(wheelImage!!)
}
}
_binding = GameFragmentBinding.inflate(inflater, container, false)
val root: View = binding.root
return root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
You are accessing fragment view inside onCreateView(). This will return null since nothing has been inflated yet.
Use the binding variable to access the views.
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
gameViewModel = ViewModelProvider(this).get(GameViewModel::class.java)
_binding = GameFragmentBinding.inflate(inflater, container, false)
gameViewModel.getDegreesForSectors()
binding.spinBtn.setOnClickListener() {
if (!gameViewModel.isSpinning) {
gameViewModel.spin(binding.spinningWheel)
}
}
return binding.root
}
I have a recyclerView where I send data with my adapter but got the error
RecyclerView must not be null
code with my adpater:
class InWaitingFragment : Fragment() {
private lateinit var adapter: FastItemAdapter<BarterWaitingItem>
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
println("CONTAINER: " + container)
val inflate: FrameLayout = inflater.inflate(R.layout.fragment_in_waiting, container, false) as FrameLayout
adapter = FastItemAdapter<BarterWaitingItem>()
waitingRecyclerView.layoutManager = LinearLayoutManager(this)
waitingRecyclerView.adapter = adapter
val retrofit = Retrofit.Builder()
.baseUrl("http://10.93.182.95:8888")
.addConverterFactory(GsonConverterFactory.create())
.build()
val service = retrofit.create(RequestManager::class.java)
val action = service.getPending()
action.enqueue(object: Callback<ArrayList<GetBarterResponse>> {
override fun onResponse(
call: Call<ArrayList<GetBarterResponse>>,
response: Response<ArrayList<GetBarterResponse>>
) {
val allBarter = response.body()
if(allBarter != null){
for (c in allBarter){
println("OBJET: ${c.buyer_object.title}")
}
println("ONRESPONSE En attente: " + response.body().toString())
}
}
override fun onFailure(call: Call<ArrayList<GetBarterResponse>>, t: Throwable) {
println("ONFAILURE En attente: " + t.toString())
}
})
return inflate
}
}
got an error to on the this of LinearLayoutManager(this), says:
`require:Context!
Founds: InWaitingFragment
You should change LinearLayoutManager(this) to LinearLayoutManager(this.context)
For your LinearLayoutManager, Fragments aren't extending Context so you cant use this as parameters. Instead, use this:
waitingRecyclerView.layoutManager = LinearLayoutManager(context!!)
For the runtime error, "RecyclerView must not be null", it's because you're accessing the properties of the waitingRecyclerView inside the onCreateView callback. The layout hasn't been initialized yet. You can move your initialization of waitingRecyclerView to the 'onViewCreated' callback.
If you must initialize the waitingRecyclerView inside onCreateView you can access the waitingRecyclerView via the object you created when inflating the layout, i.e. inflate:
inflate.waitingRecyclerView.layoutManager = LinearLayoutManager(context!!)
inflate.waitingRecyclerView.adapter = adapter