onMapReady function seems to not be called on android app - kotlin

The map seems to be created but the marker does not get placed. Most questions relating to this problem seems to be missing getmapasync but th,s one seems to have it
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Retrieve the content view that renders the map.
setContentView(R.layout.fragment_dashboard)
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as? SupportMapFragment
mapFragment?.getMapAsync(this)
}
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
val sydney = LatLng(-33.852, 151.211)
mMap.addMarker(
MarkerOptions()
.position(sydney)
.title("Marker in Sydney")
)
// [START_EXCLUDE silent]
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))
// [END_EXCLUDE]
}
// [END maps_marker_on_map_ready_add_marker]

Is your map fragment nested in a fragment?
If you are calling getMapAsync from a fragment that contains the actual map, you need to use childFragmentManager instead of supportFragmentManager to find the map
(childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment).getMapAsync(this)

Related

Getting the coordinates of the camera on idle

I am trying to get the center coordinates of the camera once the camera is on idle state after movement but its not working or logging the coordinates. Here is the code
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_shifting_map)
val mapFragment = supportFragmentManager.findFragmentById(R.id.map_fragment) as SupportMapFragment
mapFragment.getMapAsync(this)
}
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
mMap.setOnCameraIdleListener { OnCameraIdleListener {
val centerLatLang = mMap.projection.visibleRegion.latLngBounds.center
Log.d("##", "lat{$centerLatLang.longitude} long{$centerLatLang.longitude}")
} }
}
setOnCameraIdleListener is a function and should use parentheses rather than brackets.
https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap#public-final-void-setoncameraidlelistener-googlemap.oncameraidlelistener-listener
OnCameraIdleListener should require the same fix.

how to navigate to fragment inside recycler view?

I have an activity that is controlled with a navigation component, it has few fragments, inside one of these fragments there is a recyclerView that has some items, when I click on an Item I want it to navigate me to another fragment that has additional information about the item, I don't know how to use navigation component inside a recycelerView, when I type findNavController it has some parameters that am not sure what to put in or if its even the right function, I also tried to do it by code like this:
val fm = (context as AppCompatActivity).supportFragmentManager
fm.beginTransaction()
.replace(R.id.fragmentContainer, fragment)
.addToBackStack(null)
.commit()
by the way this is the code that asks for other parameters:
// it asks for a (fragment) or (activity, Int)
findNavController().navigate(R.id.action_settingsFragment_to_groupUnits)
the problem is when I navigate out of this fragment or use the drawer navigation (nav component for the other fragments), this fragment that I navigated to stays displayed in the screen, I see both fragments at the same time, I assume its a fragment backStack issue but I don't know how to solve it, thanks for the help and your time in advance
You do not need to navigate from RecyclerView item click to AdditionalDetails fragment directly.
You can do this same thing by help of interface.
Steps:
Create an interface with a method declaration.
Extend Interface from the fragment where you are using your RecyclerView and Implement interface method.
Pass this interface with the adapter.
Using the interface from adapter you just pass object when click on item.
Finally from your fragment you just navigate to AdditionalDetails fragment with argument.
Lets see sample code from my current project:
Interface
interface ChatListClickListener {
fun onChatListItemClick(view:View, user: User)
}
Adapter Class
class UserAdapter(val Users: List<User>, val chatListClickListener: ChatListClickListener) : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
inner class UserViewHolder(
val recyclerviewUsersBinding: RecyclerviewChatlistBinding
) : RecyclerView.ViewHolder(recyclerviewUsersBinding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val vh = UserViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.recyclerview_chatlist,
parent,
false
)
)
return vh
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.recyclerviewUsersBinding.user = Users[position]
holder.recyclerviewUsersBinding.root.setOnClickListener{
chatListClickListener.onChatListItemClick(it,Users[position])
}
}
override fun getItemCount(): Int {
return Users.size
}
}
My fragment
class FragmentChatList : Fragment(), ChatListClickListener {
lateinit var binding: FragmentChatListBinding
lateinit var viewModel: ChatListViewModel
lateinit var listener: ChatListClickListener
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val args: FragmentChatListArgs by navArgs()
binding = FragmentChatListBinding.inflate(layoutInflater, container, false)
val factory = ChatListFactory(args.user)
viewModel = ViewModelProvider(this, factory).get(ChatListViewModel::class.java)
binding.viewModel = viewModel
listener = this
lifecycleScope.launch {
viewModel.addUserWhenUserConnect()
}
viewModel.userList.observe(viewLifecycleOwner, Observer { data ->
binding.rvChatList.apply {
layoutManager = LinearLayoutManager(requireContext())
setHasFixedSize(true)
adapter = UserAdapter(data, listener)
}
})
return binding.root
}
override fun onChatListItemClick(view: View, user: User) {
Toast.makeText(requireContext(), user.name + "", Toast.LENGTH_SHORT).show()
// here you navigate to your fragment....
}
}
I guess this will be helpful.

Context in fragment for recyclerview - Kotlin

I should be able to resolve this as their are so many similar posts on Stack but my brain is just not getting it...
I'm fairly new to android (from flutter) and I want a recyclerview in a fragment... moreover the recycler view doesn't use XML but a custom view class created by some JSON/GSON. None of the online tutorials really cover this and the Stack articles deal with one or another part but not all combined.
I think I have setup my custom views and adapter ok, but no matter what I try I am getting errors from my fragment, mostly related to the context and null parameters.
Here is my fragment class:
class MySquibsFragment : Fragment() {
//var squibGrid: RecyclerView = RecyclerView(requireContext())
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val v: View = inflater.inflate(R.layout.fragment_my_squibs, container, false)
//squibGrid = v.findViewById<RecyclerView>(R.id.squibgrid)
return v
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val squibList: ArrayList<SquibModel> = ArrayList()
try {
val jsonString = getJSONFromAssets()!!
val squibs = Gson().fromJson(jsonString, Squibs::class.java)
//squibGrid.layoutManager = LinearLayoutManager(activity)
//val itemAdapter = MySquibsAdapter(requireActivity(), squibs.squibs)
//squibGrid.adapter = itemAdapter
} catch (e: JSONException) {
e.printStackTrace()
}
}
The parts that are commented out are the lines that are throwing errors. I've tried moving all of onCreate into onActivityCreated and I've tried using lateinit to get the context, I just can't get my head around it.
Writing val squibGrid = view.findViewById<RecyclerView>(R.id.squibgrid) at the top means that you're trying to find the view when your fragment object is initialized. At that time, the fragment's view is not inflated, so you'll get an exception.
The fragment's view is inflated in onCreateView()
val v: View = inflater.inflate(R.layout.fragment_my_squibs, container, false)
return v
Try moving everything to onViewCreated(). According to the docs for fragment's lifecycle onViewCreated() is called after onCreateView(), i.e after the view is inflated.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val squibGrid = view.findViewById<RecyclerView>(R.id.squibgrid)
try {
val jsonString = getJSONFromAssets()!!
val squibs = Gson().fromJson(jsonString, Squibs::class.java)
squibGrid.layoutManager = LinearLayoutManager(activity)
val itemAdapter = MySquibsAdapter(requireActivity(), squibs.squibs)
squibGrid.adapter = itemAdapter
} catch (e: JSONException) {
e.printStackTrace()
}
}
Context in fragments will be available after onAttachContext method is called, also your views won't be created before onCreateView, it will crash if you try to access squibGrid in onCreate, You can safely bet on onViewCreated method where context and views are already available to consume
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val squibList: ArrayList<SquibModel> = ArrayList()
try {
val jsonString = getJSONFromAssets()!!
val squibs = Gson().fromJson(jsonString, Squibs::class.java)
//squibGrid.layoutManager = LinearLayoutManager(activity)
//val itemAdapter = MySquibsAdapter(requireActivity(), squibs.squibs)
//squibGrid.adapter = itemAdapter
} catch (e: JSONException) {
e.printStackTrace()
}
}

How I get data from fun onResult to fun onMapReady in kotlin

I use retrofit for get data From API. i will displays data ini the maps. data was successfull get from retrofit, but i found problem get data response to fun onMapReady. i don't know to be it
class HomeMapsActivity : AppCompatActivity(), OnMapReadyCallback,
MapHomeContract.View {
private lateinit var mMap: GoogleMap
lateinit var presenter: MapHomePresenter
lateinit var prefsManager: PrefsManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home_maps)
supportActionBar!!.title = "Posisi driver"
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
prefsManager = PrefsManager(this)
presenter = MapHomePresenter(this)
presenter.getAnak(prefsManager.prefsIdUser)
}
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
for (dataAnak in anak) {
// Add a marker in Sydney and move the camera
val sydney = LatLng(-34.0, 151.0)
mMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))
}
}
override fun onResult(dataAnakResponse: AnakResponse) {
dataAnakResponse.anak
}
}
please help
onMapReady() is called when you initially start the Map Activity. You can set the map data in onResult.
override fun onResult(dataAnakResponse: AnakResponse) {
val anak = dataAnakResponse.anak
for (dataAnak in anak) {
// Add a marker in Sydney and move the camera
val sydney = LatLng(-34.0, 151.0)
mMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))
}
}

how to remove the pager fragment from activity to prevent the old fragment instance to be restored by os

It is an activity hosting a pager fragment which has android.support.v4.view.ViewPager and the adapter class derived from FragmentStatePagerAdapter.
The problem is from the pager fragment it has two or three fragments cached, but the data is not parseable (including a view dynamically getting from a 3rd part sdk), when sometime os recreate this fragment in case like minimize/reopen it, or after rotation the restored fragment are blank (using the one from cache and lacking data).
Not find a way to re-populate the fragments restored by os through the pager fragment's recreation flow.
Even tried in the pager fragment to clear the adapter's data in onActivityCreated()
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val childFragmentManager = childFragmentManager
mAdapter = ContentPagerAdapter( activity as Context,
childFragmentManager, emptyList())
mContentViewPager!!.setAdapter(mAdapter)
mAdapter?.setData(emptyList())
}
the adapter:
fun setData(itemsList: List<Data>) {
this.data = itemsList
notifyDataSetChanged()
}
the viewPager seems still showing the previous cachhed fragment without expected data after the re-creation flow is complete. (tried to make sure it is from the cached one, by in the fragment's onsaveInstance() to save the position of the data in the adapter data list, and the re-created fragment in the viewPager got that position, so it is a os re-created one from cache. But how could it be after at beging already set the adapter with empty list at onActivityCreated()).
Cannt resolve with clean the fragments by setting data to empty.
So tried to remove the page fragment from the activity at onDestroy() with hope that there will be no fragment to be put in cache:
class ContentPagerFragment :Fragment {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.content_pager, container, false)
mContentViewPager = view.findViewById(R.id.contentViewPager)
return view
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val childFragmentManager = childFragmentManager
mAdapter = ContentPagerAdapter( activity as Context,
childFragmentManager, emptyList())
mContentViewPager!!.setAdapter(mAdapter)
mAdapter?.setData(emptyList())
}
interface RemoveFragmentAtClose {
fun onContentPagerFragmentDoestroy()
}
override fun onDestroy() {
(activity as? RemoveAtCloseFragment)?
.onContentPagerFragmentDoestroy()
super.onDestroy()
}
}
and in the hosting activity
class HostActivity : AppCompatActivity(),
ContentPagerFragment.RemoveFragmentAtClose {
override fun onContentPagerFragmentDoestroy() {
supportFragmentManager.beginTransaction().
remove(supportFragmentManager.findFragmentById(R.id.pagerFragmentContainer))
.commitAllowingStateLoss()
var contentPagerFragment = ContentPagerFragment::class.java.cast(supportFragmentManager
.findFragmentById(R.id.pagerFragmentContainer))
Log.i(TAG, " onContentPagerFragmentDoestroy(), this $this" +
"\ngetContentPagerFragment: $contentPagerFragment"
)
}
override fun onAttachFragment(fragment: Fragment) {
Log.d(TAG, " onAttachFragment(), " +
"fragment: $fragment \nthis $this")
}
}
But the log shows that the supportFragmentManager.findFragmentById(R.id.pagerFragmentContainer) still find the fragment after the .commitAllowingStateLoss() call.
And when os restores the activity the ContentPagerFragment is showing up in the activity's onAttachFragment(fragment: Fragment) before activity's onCreate(savedInstanceState: Bundle?) is called.
Why is the viewPager using the old fragment after remove the pager fragment from the activity's supportFragmentManager?
How to prevent the view pager from use the cached fragment?