Jetpack Compose: cached ComposeView can not show in Fragment - android

I use viewPager2 in my project the parent is HomeFragment and one of child Fragment is Fragmentone . I cached the root View of HomeFragment so next time I goto HomeFragment I can reuse it . ComposeView is add to Fragmentone. it can not show when I goto HomeFragment again.
class HomeFragment : BaseTrackFragment() {
lateinit var mTabs: TabLayout
private lateinit var mFragmentPager: ViewPager2
private var pageAdapter:HomePageAdapter? = null
val mFragmentList = SparseArray<Fragment>()
private var mView: View? = null
override fun initShareTrackParams(shareTrackParamsCtx: ShareTrackParamsCtx) {
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
if (mView!=null){
(mView?.parent as? ViewGroup)?.removeView(mView)
return mView as View
}
val root = inflater.inflate(R.layout.fragment_home, container, false)
mView = root
mTabs = root.findViewById(R.id.tab_header)
mFragmentPager = root.findViewById(R.id.fragment_pager)
try {
setupViewPager()
} catch (e: Exception) {
}
return root
}
private fun setupViewPager() {
pageAdapter = HomePageAdapter(mFragmentList,this)
mFragmentPager?.adapter = pageAdapter
mFragmentPager.isSaveEnabled = false
mTabs.layoutParams = mTabs.layoutParams.apply {
width = 2 * 120
}
TabLayoutMediator(mTabs, mFragmentPager) { t, position ->
t.text = if (position==0) "音乐" else "K歌"
}.attach()
mTabs.disableTooltips()
}
private fun TabLayout.disableTooltips() {
for (i in 0 until childCount) {
val c = getChildAt(i)
if (c is ViewGroup) {
for (j in 0 until c.childCount) {
val cc = c.getChildAt(j)
if (cc is TabLayout.TabView) {
// Avoid calling tooltip for L and M devices because long pressing twuice may freeze devices.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
TooltipCompat.setTooltipText(cc, null)
}
}
}
}
}
}
}
class Fragmentone : BaseTrackFragment(){
// TODO: Rename and change types of parameters
override fun initShareTrackParams(shareTrackParamsCtx: ShareTrackParamsCtx) {
}
var listView:ListView?=null
var composeView:ComposeView?=null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_fragmentone, container, false).apply {
listView = findViewById<ListView>(R.id.list_view)
composeView = findViewById<ComposeView>(R.id.compose_view).apply {
setContent {
Text(text = "我是测试的。。。。。")
}
}
listView?.adapter = MyAdapter(this.context)
}
}
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 Fragmentone.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
Fragmentone().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent"
tools:context=".ui.home.Fragmentone">
<androidx.compose.ui.platform.ComposeView
android:id="#+id/compose_view"
android:layout_width="match_parent"
android:layout_height="50dp"/>
<ListView
android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

Related

how pass data between fragments using LiveData

i want to know how pass data from one fragment to other using LiveData
i have this code and do somethings that i know but it doesnt work pls help ...
this is my first fragmetn
enter code here
class ItemDetailsfragment : Fragment() {
lateinit var viewmodel: ViewModelPassItem
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.details_items_page, container, false)
val title = arguments?.getString("title")
view.title_details_item.text = title
val price = arguments?.getString("price")
view.price_item_details.text = price
val image = arguments?.getString("image")
Picasso.get().load(image).into(view.image_items_detail)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewmodel = ViewModelProviders.of(activity!!).get(ViewModelPassItem::class.java)
val title: TextView = view.findViewById(R.id.title_details_item)
view.plus_icon_item_details.setOnClickListener {
viewmodel.passdata(title.text.toString())
val myfragment = Cart_Fragment()
}
}
}
and this is second fragment
enter code here
class Cart_Fragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val viewitem = inflater.inflate(R.layout.cart_fragment, container, false)
val choosebtn: Button = viewitem.findViewById(R.id.choose_titme_and_submit_order_btn)
choosebtn.visibility = View.GONE
val rl_cart = viewitem.findViewById<RecyclerView>(R.id.recycler_view_cart)
rl_cart.visibility = View.GONE
val navbar: BottomNavigationView = activity!!.findViewById(R.id.nav_view_bottom_main)
navbar.visibility = View.GONE
val homeicon: ImageButton = viewitem.home_icon_cart
homeicon.setOnClickListener {
activity?.let {
val intent = Intent(requireContext(), HomeActivity::class.java)
it.startActivity(intent)
}
}
viewitem.start_shopping_in_cart.setOnClickListener {
activity?.let {
val intent = Intent(requireContext(), HomeActivity::class.java)
it.startActivity(intent)
}
}
return viewitem
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val viewmodel = ViewModelProviders.of(activity!!).get(ViewModelPassItem::class.java)
viewmodel.pass.observe(activity!!, Observer {
d("main", "${it.toString()}")
})
}
}
and this is my ViewModel Class
enter code here
class ViewModelPassItem:ViewModel() {
val pass = MutableLiveData<String>()
fun passdata (title : String) {
pass.postValue(title)
}
}
ok
when i click on btn to get string that i pass nothing happend ...
In the Cart Fragment instead of passign activity lifecycleowner pass your fragments lifecycle owner. So instead of :
viewmodel.pass.observe(activity!!, Observer {
Log.d("main", "${it.toString()}")
})
Do this :
viewmodel.pass.observe(this.viewLifecycleOwner, Observer {
Log.d("main", "${it.toString()}")
})

Updating RecyclerView Fragment adapter from Activity

I have a MainActivity that holds Fragment with RecyclerView inside. The fragment initiates with "supportFragmentManager.beginTransaction()
.add" as you can see below in MainActiviry code. MainActivity is registered to some CallBack that alters moviesArrayList, and when it happens I need to update the Frgamnet with new moviesArrayList and reload the adapter. What is a suitable approach for this? Removing and adding Fragment again? Updating the Instance? Sending data to fragment via callback?
Main Activity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
var moviesArrayList: ArrayList<Movie>? = ArrayList()
//moviesArrayList //Some initializtion here
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.add(R.id.container, ListFragment.newInstance(moviesArrayList))
.commitNow()
}
}
ListFragment:
class ListFragment : Fragment() {
private lateinit var moviesArrayList: ArrayList<Movie>
interface OnFragmentInteractionListener {
fun onFragmentInteraction(movie: Movie)
fun onFragmentInteraction()
}
override fun onAttach(context: Context) {
super.onAttach(context)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_list2, container, false)
val listView = view.findViewById<RecyclerView>(R.id.list2)
listView.adapter = MyMovieRecyclerViewAdapter(moviesArrayList,object : OnItemClickListener {
override fun onItemClicked(movie: Movie) {
//Some on click happening
}
})
return view
}
companion object {
#JvmStatic
fun newInstance(movies: ArrayList<Movie>?) = ListFragment().apply {
if (movies != null) {
moviesArrayList = movies //init moviesArrayList
}
}
}
}
When you sense there is a change in the list you simple call:
adapter.notifyDataSetChanged()
and that should update the recyclerview

use androidx.fragment.app.Fragment,I found that I can't initialize initAdapter() in initView(),Why?

Code using kotlin,
first,this is my error code.
this is my used extends BaseFragment
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val cacheView = mView == null
if (cacheView) {
mView = inflater.inflate(getFragLayoutResID(), container, false)
initView(mView!!)
}
return mView
}
//When used in an activity
fun addFragment(context: FragmentActivity, fragmentContainer: Int) {
val fragmentManager = context.supportFragmentManager
val ft = fragmentManager.beginTransaction()
ft.replace(fragmentContainer, this, javaClass.simpleName).addToBackStack(javaClass.simpleName)
.commitAllowingStateLoss()
ft.setMaxLifecycle(this, Lifecycle.State.RESUMED)
}
this is my HomeActivity
homeVideoFragment.addFragment(mContext as FragmentActivity, mainFrameLayout.id)
this is my HomeFragment
//HomeFragment
override fun initView(view: View) {//this is my homeFragment
initAdapter()
//init()
}
private var homeVideoAdapter: HomeVideoAdapter? = null
private fun initAdapter() {//this is my init adapter
val homeVideoManager = LinearLayoutManager(mContext, RecyclerView.VERTICAL, false)
homeVideoAdapter = HomeVideoAdapter(mContext!!)
home_video_rv.layoutManager = homeVideoManager
home_video_rv.adapter = homeVideoAdapter
}
private fun init() = runBlocking {
GlobalScope.launch(Dispatchers.Main) {
initAdapter()
//GlobalScope.async(Dispatchers.IO) {
//presenter!!.getVideoClassPost(AllPort.POST_GET_VIDEO_HOME)//network requests
//}.await()
}
}
When the code is run like this, it will report an error: home_video_rv must not be null.
But when I use init(), it works fine.
Although successful, but can not make network requests.
Why is this problem occurring?
Use onViewCreated method
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val cacheView = mView == null
if (cacheView) {
mView = inflater.inflate(getFragLayoutResID(), container, false)
}
return mView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initView(view)
}

Element expected after creating Fragment

I noticed that after creating a fragment an element is expected. In Java, all that was needed was getActivity() but it seems more difficult in Kotlin. < and > in mTwoPane = <FragmentActivity>(activity).findViewById(R.id.master_container) != null become red underlined and return this error:
Expecting an element
class MyFragment() : Fragment() {
private var mAdapter: MyListAdapter? = null
internal lateinit var mRecyclerView: RecyclerView
var mTwoPane: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.md, container, false)
mTwoPane = <FragmentActivity>(activity).findViewById(R.id.master_container) != null
mRecyclerView = view.findViewById(R.id.recyclerView_list)
mRecyclerView.setHasFixedSize(true)
mRecyclerView.layoutManager = LinearLayoutManager(this.activity)
mRecyclerView.addItemDecoration(DividerItemDecoration(Objects.requireNonNull<Context>(context), LinearLayout.VERTICAL))
val myList = ArrayList<Product>()
val items = resources.getStringArray(R.array.product_names)
val itemDescriptions = resources.getStringArray(R.array.product_descriptions)
for (n in items.indices) {
val product = Product(items[n], itemDescriptions[n])
myList.add(product)
}
mAdapter = MyListAdapter(activity, myList, mTwoPane)
mRecyclerView.adapter = mAdapter
return view
}
}
try this
mTwoPane = (activity as FragmentActivity).findViewById<View>(R.id.master_container) != null

RecyclerView not viewed in a Fragment

when I add a fragment to my view, it is not displayed. Only when I click an OptionsButton the fragment becomes visible. But I don't know if the RecyclerView just doesn't show any elements or if the fragment isn't started.
Code from MainActivity
override fun onCreate(savedInstanceState: Bundle?) {
val fragment= ArticleFragment()
var args=Bundle()
args.putInt("id",0)
fragment.arguments=args
supportFragmentManager.beginTransaction().replace(R.id.fragment_area,fragment).addToBackStack(null).commit()
}
Code from ArticleFragment
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
val view= inflater.inflate(R.layout.fragment_article, container, false)
articles=getArticleJson(url)
val recyclerView=view.findViewById<RecyclerView>(R.id.articlesRecyclerView)
recyclerView.setHasFixedSize(true)
val lm = LinearLayoutManager(activity)
recyclerView.layoutManager = lm
val adapter = ArticleAdapter(context = context, articles = articles) {
val intent = Intent(activity, ArticleWebActivity::class.java).apply
{
putExtra("article", Gson().toJson(it))
}
startActivity(intent)
}
recyclerView.adapter = adapter
return view
}

Categories

Resources