Synthetics to Viewbinding issues (onBackPress & Navigation Drawer) - kotlin

I am updating my app to completely remove synthetics and move to viewbinding, however I am struggling with converting the onBackPressed method (now also deprecated) with my Activity, Fragment and Navigation Drawer.
I originally had it like this:
Activity (Before)
override fun onCreate(savedInstanceState: Bundle?) {
Log.d(TAG, "onCreate")
super.onCreate(savedInstanceState)
val activityBinding: BusinessActivityBinding = DataBindingUtil.setContentView(
this,
R.layout.business_activity
)
nav_view.setNavigationItemSelectedListener(this)
val headerView = activityBinding.navView.getHeaderView(0)
headerView.navHeaderEmailText.setOnClickListener { sendSupportEmail() }
navController = findNavController(this, R.id.NavHostFragment)
// other stuff
}
fun openCloseNavigationDrawer() {
if (business_drawer_layout.isDrawerOpen(GravityCompat.START)) {
business_drawer_layout.closeDrawer(GravityCompat.START)
} else {
business_drawer_layout.openDrawer(GravityCompat.START)
}
}
override fun onBackPressed() {
val navHostFragment: NavHostFragment = supportFragmentManager.findFragmentById(R.id.NavHostFragment) as NavHostFragment
val backStackEntryCount = navHostFragment?.childFragmentManager?.backStackEntryCount
when {
(business_drawer_layout.isDrawerOpen(GravityCompat.START)) -> business_drawer_layout.closeDrawer(
GravityCompat.START
)
(backStackEntryCount == 0) -> dialogLeaveApp()
else -> super.onBackPressed()
}
}
private fun dialogLeaveApp(){
MaterialDialog(this).show {
title(R.string.business_activity_dialog_leave_app_heading)
message(R.string.business_activity_dialog_leave_app_message)
positiveButton(R.string.business_activity_dialog_confirm_button){
super.onBackPressed()
}
negativeButton(R.string.business_activity_dialog_cancel_button) {
dismiss()
}
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.nav_sites_fragment -> navigateWithClearStack(R.id.sitesFragment)
R.id.nav_projects_fragment -> navigateWithClearStack(R.id.projectsFragment)
R.id.nav_contacts_fragment -> navigateWithClearStack(R.id.contactsFragment)
R.id.nav_tasks_fragment -> navigateWithClearStack(R.id.tasksFragment)
R.id.nav_profile_fragment -> makeToast("Todo: Profile Fragment")
R.id.nav_settings_fragment -> navigateWithClearStack(R.id.settingsFragment)
}
business_drawer_layout.closeDrawer(GravityCompat.START)
return true
}
private fun navigateWithClearStack(destination: Int) {
businessViewModel.clearCurrentVMData()
val navHostFragment: NavHostFragment = supportFragmentManager.findFragmentById(R.id.NavHostFragment) as NavHostFragment
val inflater = navHostFragment.navController.navInflater
val graph = inflater.inflate(R.navigation.business_navigation)
graph.startDestination = destination
navController.graph = graph
}
}
Fragment (already using viewbinding)
class SitesFragment : Fragment() {
private lateinit var navController: NavController
private lateinit var businessViewModel: BusinessViewModel
private lateinit var sitesAdapter: SitesRecyclerViewAdapter
private var _binding: SitesFragmentBinding? = null // this property is only valid between onCreateView & onDestroyView
private val binding get() = _binding!! //https://stackoverflow.com/questions/57647751/android-databinding-is-leaking-memory
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
Log.d(TAG, "onCreateView()")
activity?.let {
businessViewModel = ViewModelProvider(it).get(BusinessViewModel::class.java)
Log.d(TAG, "businessViewModel = $businessViewModel")
}
Log.d(TAG, businessViewModel.currentStatus("${TAG}, onCreateView()"))
// Inflate the layout for this fragment
_binding = SitesFragmentBinding.inflate(inflater, container, false)
val view = binding.root
binding.apply {
sitesDrawerMenuButton.setOnClickListener {
(activity as BusinessActivity).openCloseNavigationDrawer()
Log.d(TAG, "sitesDrawerMenuButton clicked, openCloseNavigationDrawer()")
}
// Other listeners
}
return view
}
Activity (After)
private var _binding: BusinessActivityBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
Log.d(TAG, "onCreate")
super.onCreate(savedInstanceState)
// Inflate the layout for this activity
_binding = BusinessActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.NavHostFragment) as NavHostFragment
this.navController = navHostFragment.navController
binding.navView.setupWithNavController(this.navController)
// Setup OnBackPressedDispatcher
val backPressedCallback = object:OnBackPressedCallback(false){
override fun handleOnBackPressed() {
onBackButtonPressed()
}
}
// Other stuff
}
fun openCloseNavigationDrawer() { // accessed by Fragment
if (binding.businessDrawerLayout.isDrawerOpen(GravityCompat.START)) {
binding.businessDrawerLayout.closeDrawer(GravityCompat.START)
} else {
binding.businessDrawerLayout.openDrawer(GravityCompat.START)
}
}
fun onBackButtonPressed() {
val navHostFragment: NavHostFragment = supportFragmentManager.findFragmentById(R.id.NavHostFragment) as NavHostFragment
val backStackEntryCount = navHostFragment.childFragmentManager.backStackEntryCount
when {
(binding.businessDrawerLayout.isDrawerOpen(GravityCompat.START)) -> binding.businessDrawerLayout.closeDrawer(
GravityCompat.START
)
(backStackEntryCount == 0) -> dialogLeaveApp()
}
}
private fun dialogLeaveApp(){
// as before
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
// as before
}
private fun navigateWithClearStack(destination: Int) {
// as before
}
So the issue is that when you back press, it simply exits the app, rather than triggering my function onBackButtonPressed() (which replaces the depricated onBackPressed())and variable 'backPressedCallback' is never used..

Related

i want to add next page (every page is 10) to my recyclerview but it delet my last page

my recyclerview fragment:
this is the fragment that I set my recycler view , I want when touch the continue button (btn_continue) add the rest of the list, which is actually the next page, to my list when I click the button
But it deletes the previous list and displays the new list
and i use the kotlin coruotine, viewmodel and recyclerview
class AllUnpublishedAdsFragment : Fragment() {
lateinit var unpublishedAdsAdapter: UnpublishedAdsAdapter
var items = ArrayList<M_Ads>()
lateinit var loadMoreItems: ArrayList<M_Ads>
lateinit var scrollListener: RecyclerViewLoadMoreScroll
lateinit var mLayoutManager: RecyclerView.LayoutManager
val page = "1"
var newpage = page.toInt()
var navController: NavController? = null
lateinit var btn_continue: Button
private lateinit var viewModel: MainViewmodels
lateinit var token: String
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_all_unpublished_ads, container,
false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btn_continue = view.findViewById<Button>(R.id.btn_continueAds)
token = arguments?.getString(TOKEN_KEY).toString()
Log.i("TOKEN", token)
setupViewModel(token, page)
continueAds()
unpublishedAdsAdapter.itemClickListener = { item, position ->
val id = item.id
val bundle_id = Bundle()
bundle_id.putString(ID_KEY, id.toString())
navController = Navigation.findNavController(view)
//view.findNavController().navigate(R.id.action_UnpublishedAds_to_Detail,
bundle_id)
navController!!.navigate(
R.id.action_allUnpublishedAdsFragment_to_adsDetailFragment,
bundle_id
)
}
}
private fun setupViewModel(token: String, page: String) {
LoadingDialog.show(requireContext(), { ld ->
recy_unpublished_ads.layoutManager = LinearLayoutManager(activity)
val decoration = DividerItemDecoration(activity, DividerItemDecoration.VERTICAL)
recy_unpublished_ads.addItemDecoration(decoration)
viewModel = ViewModelProvider(this).get(MainViewmodels::class.java)
unpublishedAdsAdapter = UnpublishedAdsAdapter()
recy_unpublished_ads.adapter = unpublishedAdsAdapter
viewModel.adsListObserve().observe({ lifecycle }, { model ->
items.clear()
items.addAll(model.adsList!!)
unpublishedAdsAdapter.setUpdateData(items)
ld.dismiss()
btn_continue.visibility = View.VISIBLE
})
viewModel.getAdsList(token, page)
})
}
fun continueAds() {
var isTouched=false
btn_continue.setOnClickListener {
isTouched=true
newpage = newpage + 1
Log.i("CONTINUE", newpage.toString())
setupViewModel(token, newpage.toString())
unpublishedAdsAdapter.notifyDataSetChanged()
isTouched=false
}
}
RetrofitInstance class
class RetrofitInstance {
companion object{
fun getRetrofitInstance (): Retrofit{
// val interceptor = HttpLoggingInterceptor()
// interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
// val client: OkHttpClient = OkHttpClient.Builder().addInterceptor(interceptor).build()
val okHttpClient: OkHttpClient = OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.build()
return Retrofit.Builder()
.baseUrl(BASEURL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build()
}
}
}
my adapter:
class UnpublishedAdsAdapter : RecyclerView.Adapter<UnpublishedAdsAdapter.MyViewHolder>() {
var items = ArrayList<M_Ads>()
var itemClickListener: ((item: M_Ads, position: Int) -> Unit)? = null
lateinit var mcontext: Context
class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
class LoadingViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
fun setUpdateData(items: ArrayList<M_Ads>) {
this.items = items
notifyDataSetChanged()
}
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val img_ads = view.findViewById<ImageView>(R.id.img_recy_ads)
val txt_title = view.findViewById<TextView>(R.id.txt_recy_ads_title)
val txt_accountType = view.findViewById<TextView>(R.id.txt_recy_ads_acctype)
fun bind(data: M_Ads) {
txt_title.setText(data.title)
txt_accountType.setText(data.accountType)
if (!data.image1.equals("")) {
Picasso.with(img_ads.context).load(data.image1).into(img_ads)
} else {
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
mcontext = parent.context
return if (viewType == Constant.VIEW_TYPE_ITEM) {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.row_recy_unpublished_ads, parent, false)
MyViewHolder(view)
} else {
val view =
LayoutInflater.from(mcontext).inflate(R.layout.progress_loading, parent, false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
view.progressbar.indeterminateDrawable.colorFilter =
BlendModeColorFilter(Color.WHITE, BlendMode.SRC_ATOP)
} else {
view.progressbar.indeterminateDrawable.setColorFilter(
Color.WHITE,
PorterDuff.Mode.MULTIPLY
)
}
MyViewHolder(view)
}
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(items.get(position))
handleClick(holder)
}
fun handleClick(holder: UnpublishedAdsAdapter.MyViewHolder) {
holder.itemView.setOnClickListener {
val position = holder.adapterPosition
itemClickListener?.invoke(items.get(position), position)
}
}
override fun getItemCount(): Int {
return items.size
}
my Viewmodel:
class MainViewmodels:ViewModel() {
lateinit var getAds:MutableLiveData<Main_ModelAds>
init {
getAds= MutableLiveData<Main_ModelAds>()
}
fun adsListObserve():MutableLiveData<Main_ModelAds>{
return getAds
}
fun getAdsList(token:String,page:String){
viewModelScope.launch(Dispatchers.IO) {
try {
Log.i("ERRORRES",token + "")
val retrofitInstance=RetrofitInstance.getRetrofitInstance().create(RetrofitService::class.java)
val response=retrofitInstance.unPublishedAdsList(token,page)
getAds.postValue(response)
}catch (ex:Exception){
Log.i("ERRORRES", ex.message.toString() + "")
}
}
}
What you want here is to update the list that you are showing when the user clicks the button.
In this case you should use ListAdapter.
You can refer to this article for implementation:
https://developer.android.com/reference/androidx/recyclerview/widget/ListAdapter

How can i to show the Ad when i push the button for next activity?

class MainActivity : AppCompatActivity() {
lateinit var mAdView : AdView
private var mInterstitialAd: InterstitialAd? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
loadBannerAd()
loadInterAd()
val wLista = findViewById<Button>(R.id.Lista)
wLista.setOnClickListener{
showInterAd()
startActivity(Intent(this, com.tango.changapp.wLista::class.java))
}
private fun showInterAd() {
if(mInterstitialAd != null){
mInterstitialAd?.fullScreenContentCallback = object : FullScreenContentCallback(){
override fun onAdFailedToShowFullScreenContent(p0: AdError) {
super.onAdFailedToShowFullScreenContent(p0)
}
override fun onAdShowedFullScreenContent() {
super.onAdShowedFullScreenContent()
}
override fun onAdDismissedFullScreenContent() {
super.onAdDismissedFullScreenContent()
val intent = Intent(this#MainActivity, MainActivity::class.java)
startActivity(intent)
}
override fun onAdImpression() {
super.onAdImpression()
}
}
mInterstitialAd?.show(this)
}else{
val intent = Intent(this, MainActivity2::class.java)
//startActivity(intent)
}
}
private fun loadInterAd() {
var adRequest = AdRequest.Builder().build()
InterstitialAd.load(this,"ca-app-pub-3940256099942544/1033173712", adRequest, object : InterstitialAdLoadCallback() {
override fun onAdFailedToLoad(adError: LoadAdError) {
mInterstitialAd = null
}
override fun onAdLoaded(interstitialAd: InterstitialAd) {
mInterstitialAd = interstitialAd
}
})
}
I have the following code, and I want for an Ad to be launched when I advance to the next activity, but it doesn't happen, the Ad is only launched when I am in the other activity and I press the return button

RecyclerView in Fragment not populating

So I've been wrestling with this for days and I need some help. I've made this code work in an activity, but then I move it to a fragment it doesn't work. Everything else is the same between the two.
Using the debugger with the working Activity, the line
apiService = retrofit.create<HomeJsonApiService>(HomeJsonApiService::class.java)
goes to getItemCount(). However in the fragment it goes directly to onCreateView in the Fragment. I've attached my code below. Thanks in advance for the help! And be gentle. I'm still new to this :)
First is my fragment:
class TabHomeActivity : Fragment() {
val itemList = ArrayList<HomeCards>()
lateinit var adapter: HomeCardsAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
var binding = FragmentTabHomeActivityBinding.inflate(layoutInflater)
adapter = HomeCardsAdapter()
var rv = binding.rvHomeCards
rv.adapter = adapter
loadData()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.cards_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
private fun loadData() {
ApiManager.getInstance().service.listHeroes()
.enqueue(object : Callback<ResponseData<List<HomeCards>>> {
override fun onResponse(
call: Call<ResponseData<List<HomeCards>>>,
response: Response<ResponseData<List<HomeCards>>>
) {
val listData: List<HomeCards> = response.body()!!.data
// updating data from network to adapter
itemList.clear()
itemList.addAll(listData)
adapter.updateData(itemList)
adapter.notifyDataSetChanged()
}
override fun onFailure(call: Call<ResponseData<List<HomeCards>>>, t: Throwable) {
}
})
}
}
The HTTP request:
data class ResponseData<T> (
val code: Int,
val data: T
)
interface HomeJsonApiService {
#GET("marvel-heroes.asp?h=2")
fun listHeroes(): retrofit2.Call<ResponseData<List<HomeCards>>>
}
class ApiManager {
private var apiService: HomeJsonApiService? = null
init {
createService()
}
val service: HomeJsonApiService get() = apiService!!
private fun createService() {
val loggingInterceptor =
HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
override fun log(message: String) {
Log.i("Retrofit", message)
}
})
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS)
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.addInterceptor(loggingInterceptor)
.build()
val retrofit: Retrofit = Retrofit.Builder()
.client(client)
.baseUrl("https://www.mywebsite.com/jsonfolder/JSON/")
.addConverterFactory(GsonConverterFactory.create())
.build()
apiService = retrofit.create(HomeJsonApiService::class.java)
}
companion object {
private var instance: ApiManager? = null
fun getInstance(): ApiManager {
return instance ?: synchronized(this) {
ApiManager().also { instance = it }
}
}
}
}
And my adapter:
class HomeCardsAdapter() : RecyclerView.Adapter<HomeCardsAdapter.ViewHolder>() {
private lateinit var itemList: List<HomeCards>
lateinit var context: Context
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
context = parent.context
val view = LayoutInflater.from(context).inflate(R.layout.cards_home, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return if (::itemList.isInitialized) itemList.size else 0
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind()
}
fun updateData(list: List<HomeCards>) {
itemList = list;
notifyDataSetChanged()
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
//var binding = ActivityMainBinding(layoutInflater(inf))
fun bind() {
val item = itemList.get(adapterPosition)
ViewHolder(itemView).itemView.findViewById<TextView>(R.id.cardHomeTitle).text = item.name
ViewHolder(itemView).itemView.findViewById<TextView>(R.id.cardHomeTitle).text = item.superheroName
Glide.with(context)
.load(item.photo)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.circleCrop()
.into(ViewHolder(itemView).itemView.findViewById<ImageView>(R.id.cardHomeIcon))
}
}
}
class HomeCards {
#SerializedName("superhero_name")
var superheroName: String = ""
var name: String = ""
var photo: String = ""
}
The main problem is:
var binding = FragmentTabHomeActivityBinding.inflate(layoutInflater)
That is inside on onCreate but onCreateView is returning another view inflater.inflate(R.layout.cards_home, container, false)
So you are applying the adapter to a recycler that is on the binding, but the view on the screen is inflated from the layout. Change it to this:
private lateinit var binding: FragmentTabHomeActivityBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {
binding = FragmentTabHomeActivityBinding.inflate(layoutInflater, container, false)
return binding.root
}
And move the code from from onCreate to onViewCreated but make sure to use the lateinit binding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = HomeCardsAdapter()
var rv = binding.rvHomeCards
rv.adapter = adapter
loadData()
}
After that there is a problem in your adapter: private lateinit var itemList: List<HomeCards> very specifically List<HomeCards>. The method notifyDataSetChanged doesn't work by changing or updating the reference of the data structure but when the collection is modified. Change it to this:
private val list = mutableListOf<HomeCards>()
override fun getItemCount(): Int {
return list.size()
}
fun updateData(list: List<HomeCards>) {
this.itemList.clear()
this.itemList.addAll(list)
notifyDataSetChanged()
}
If onResponse() gets called and provides response, verify that code updating UI is running on main/ui thread. Common source of issue when working with network (other threads).
activity?.runOnUiThread {
itemList.clear()
itemList.addAll(listData)
adapter.updateData(itemList)
adapter.notifyDataSetChanged()
}

RecyclerView adapter inside a fragment is not updating when data changes

I have an activity that contains 2 tabs and each tab has a fragment inside ViewPager. Each fragment have a RecyclerView.
When I navigate to another activity the data inside the Fragments should be updated. Although the data is being sent correctly to the fragment, the original data is displayed.
I tried using notifyDataSetChanged() method inside the fragment but it didn't work.
I also tried calling it from the activity like:
if (!pickedItemsList.isNullOrEmpty() && notScannedItemsFragment != null && notScannedItemsFragment.isAdded)
{
notScannedItemsFragment.notScannedItemsAdapter.notifyDataSetChanged()
}
However, it didn't work too.
That's how I am initiating the fragment:
override fun initFragments(savedInstanceState: Bundle?, pickedItemsList: ArrayList<OrderDetail>, remainigItemsList: ArrayList<OrderDetail>) {
val listener: ItemsInteractionListener = object : ItemsInteractionListener {
override fun onSwipeToRefresh() {
presenter.onSwipeToRefresh()
}
}
if (!pickedItemsList.isNullOrEmpty() && notScannedItemsFragment != null && notScannedItemsFragment.isAdded) {
notScannedItemsFragment.notScannedItemsAdapter.notifyDataSetChanged()
scannedItemsFragment = ScannedItemsFragment().newInstance(remainingItemsList)
notScannedItemsFragment = NotScannedItemsFragment().newInstance(pickedItemsList)!!
} else {
scannedItemsFragment = ScannedItemsFragment().newInstance(arrayListOf())
notScannedItemsFragment = NotScannedItemsFragment().newInstance(allItemsList)!!
}
scannedItemsFragment.setListener(listener)
notScannedItemsFragment.setListener(listener)
}
allItemList is the original list and pickedItemsList and remainingItemsList are the lists after the changes (that I got from the other activity)
This is one of the fragments classes:
class NotScannedItemsFragment : BaseFragment() {
private var listener: ItemsInteractionListener? = null
lateinit var notScannedItemsAdapter: OrderItemListingAdapter
private var itemRemainingCount: Int = 0
lateinit var notScannedItems: ArrayList<OrderDetail>
lateinit var recyclerView: RecyclerView
lateinit var fragmentView: View
fun newInstance(notScannedItems: ArrayList<OrderDetail>): NotScannedItemsFragment? {
val notScannedItemsFragment = NotScannedItemsFragment()
val args = Bundle()
val order = Gson().toJson(notScannedItems)
args.putString(IntentConstants.EXTRA_NOT_SCANNED_ITEM_LIST, order)
notScannedItemsFragment.setArguments(args)
return notScannedItemsFragment
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val str = arguments?.getString(IntentConstants.EXTRA_NOT_SCANNED_ITEM_LIST)
notScannedItems = Gson().fromJson(
str,
object : TypeToken<List<OrderDetail?>?>() {}.type
) as ArrayList<OrderDetail>
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
fragmentView = inflater.inflate(R.layout.fragment_not_scanned_items, container, false)
recyclerView = fragmentView.notScannedItemListing
return fragmentView
}
fun setListener(listener: ItemsInteractionListener) {
this.listener = listener
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setUpRecycler(view)
super.onViewCreated(view, savedInstanceState)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
}
private fun setUpRecycler(view: View) {
imageLoader = ImageLoader(context)
notScannedItemsAdapter = OrderItemListingAdapter(
false,
imageLoader,
object : ImageClickListener {
override fun onImageClick(
itemName: String,
itemQuantity: Int,
url: String,
barcodes: List<String>?
) {
startImageFullViewActivity(itemName, itemQuantity, url, barcodes)
}
})
notScannedItemsAdapter.addItem(notScannedItems)
notScannedItemsAdapter.notifyDataSetChanged()
view.notScannedItemListing.apply {
view.notScannedItemListing.layoutManager = LinearLayoutManager(context)
view.notScannedItemListing.setHasFixedSize(true)
view.notScannedItemListing.isNestedScrollingEnabled = false
adapter = notScannedItemsAdapter
}
notScannedItemsAdapter.printList()
}
fun showOrderItemListing(notScannedItems: ArrayList<OrderDetail>) {
this.notScannedItems = notScannedItems
itemRemainingCount = notScannedItems.size
}
fun getItemsRemainingCount(): Int{
return notScannedItems.size
}
fun clearItems() {
notScannedItemsAdapter.clearItems()
}
fun updateAdapterContent(pickedItemsList: ArrayList<OrderDetail>) {
if(this::notScannedItemsAdapter.isInitialized ) {
notScannedItemsAdapter.clearItems()
notScannedItemsAdapter.addItem(notScannedItems)
notScannedItemsAdapter.notifyDataSetChanged()
}
}
}
It turns out since I'm getting the list from arguments it's not updating with the new list. As stated here: Anything initialized in onCreate() is preserved if the Fragment is paused and resumed.
So I added a boolean variable loadListFromArgs and I only loaded the list from args if it's true and when I call updateAdapterContent I set it to false.

how to send a Cursor instance from one fragment to a fragment which contains a recyclerview with same activity in kotlin

I am still doing my first steps with app development, so i would appreciate any kind of feedback for my code.
To my problem. I got two Fragments, "ListFragment.kt" and "SetListFilters.kt". My intention is to create a cursor instance in SetListFilters and then when I press a "apply"-button i perform a popBackStack while sending the cursor instance to ListFrament. To my understanding ListFragment will call OnCreateView() and there i want to pass the new cursor to my adapter so that the Recyclerview get filtered. I tried so many things but nothing worked for me. I hope you can help me. Here is my Code:
class SetListFilters(var transactionDB: SQLiteDatabase, var adapter: TransactionAdapter):Fragment(R.layout.fragment_set_list_filters), DataPassListener {
private lateinit var gridView : GridView
private lateinit var btnYearFilter : Button
private lateinit var btnMonthFilter : Button
private lateinit var btnWeekFilter : Button
private lateinit var btnRevenueFilter : Button
private lateinit var btnExpeneseFilter : Button
private lateinit var btnNeutralFilter : Button
private lateinit var btnSbmtFilter : Button
private lateinit var tvShowAmountFilter : TextView
private lateinit var sbAmountFilters : SeekBar
private val viewModel: ListViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_set_list_filters, container, false)
setUpViews(view)
setUpButtonOnclick()
setUpSeekbar()
val arrayAdapter: ArrayAdapter<CategoryEnum> = ArrayAdapter<CategoryEnum>(activity!!, android.R.layout.simple_list_item_multiple_choice, CategoryEnum.values())
gridView.setAdapter(arrayAdapter)
// When the user clicks on the GridItem
/*gridView.setOnItemClickListener(OnItemClickListener { a, v, position, id ->
val o: Any = gridView.getItemAtPosition(position)
})*/
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.filters.observe(viewLifecycleOwner, Observer { set ->
// Update the selected filters UI
}
}
fun onFilterSelected(filter: Filter) = viewModel.addFilter(filter)
fun onFilterDeselected(filter: Filter) = viewModel.removeFilter(filter)
private fun upDateQueryForDB(){
}
private fun getAllItemsNeu(): Cursor {
val selArgs = arrayOf("r")
return transactionDB!!.query(
TransactionList.TransactionEntry.TABLE_NAME,
null,
"type = ?",
selArgs,
null,
null,
TransactionList.TransactionEntry.COLUMN_CREATEDAT + " DESC")
}
private fun setUpViews(view: View){
gridView = view.findViewById(R.id.gvCategoryFilter )
btnExpeneseFilter = view.findViewById(R.id.btnExpenseFilter)
btnMonthFilter = view.findViewById(R.id.btnMonthFilter)
btnWeekFilter = view.findViewById(R.id.btnWeekFilter)
btnNeutralFilter = view.findViewById(R.id.btnNeutralFilter)
btnRevenueFilter = view.findViewById(R.id.btnRevenueFilter)
btnSbmtFilter = view.findViewById(R.id.btnSbmtFilter)
btnYearFilter = view.findViewById(R.id.btnYearFilter)
sbAmountFilters = view.findViewById(R.id.seekBar)
tvShowAmountFilter = view.findViewById(R.id.tvFilterAmount)
}
private fun setUpButtonOnclick(){
btnExpeneseFilter.setOnClickListener { changeButtonAppearance(btnExpeneseFilter) }
btnMonthFilter.setOnClickListener { changeButtonAppearance(btnMonthFilter) }
btnWeekFilter.setOnClickListener { changeButtonAppearance(btnWeekFilter) }
btnNeutralFilter.setOnClickListener { changeButtonAppearance(btnNeutralFilter) }
btnRevenueFilter.setOnClickListener { changeButtonAppearance(btnRevenueFilter) }
btnYearFilter.setOnClickListener { changeButtonAppearance(btnYearFilter) }
btnSbmtFilter.setOnClickListener{
mainActivity.passDataCom(getAllItemsNeu())
activity!!.supportFragmentManager.popBackStack()
}
}
private fun changeButtonAppearance(button:Button) {
if(button.tag == "notPressed"){
button.setBackgroundResource(R.drawable.rounded_select_button_pressed)
button.setTextColor(Color.WHITE)
button.tag = "pressed"
}else{
button.setBackgroundResource(R.drawable.rounded_select_button)
button.setTextColor(ContextCompat.getColor(context!!,R.color.mainBlue))
button.tag ="notPressed"
}
}
private fun setUpSeekbar(){
sbAmountFilters.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
// Display the current progress of SeekBar
tvShowAmountFilter.text = "< $i"
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
// Do something
//Toast.makeText(context!!,"start tracking",Toast.LENGTH_SHORT).show()
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
// Do something
//Toast.makeText(context!!,"stop tracking",Toast.LENGTH_SHORT).show()
if(tvShowAmountFilter.text.toString()=="< 0"){
tvShowAmountFilter.text = "none"
}
}
})
}
override fun onAttach(context: Context) {
super.onAttach(context)
try{
mCallback = (OnImageClickListener) //folled the tutorial, dont know what to replace it with
}
}
}
class ListFragment:Fragment(R.layout.fragment_list) {
lateinit var transactionDB : SQLiteDatabase
lateinit var adapter : TransactionAdapter
private lateinit var filterBtn : ImageButton
private lateinit var flActBtn : FloatingActionButton
var mCursorFilter : Cursor? = null
private val viewModel: ListViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val dbHelper = TransactionDBHelper(activity)
transactionDB = dbHelper.writableDatabase
adapter = TransactionAdapter(activity!!, getAllItems())
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.filteredList.observe(viewLifecycleOwner, Observer { list ->
//TODO
}
}
private fun addRandomTransactionItem() {
var a = 1234.56
for (i in 0..10) {
if(i%2==0){
transactionDB.execSQL("INSERT INTO transactionList (type, amount, category, createdAt) VALUES('r', ${a}, 'K', CURRENT_TIMESTAMP)")
adapter.swapCursor(getAllItems())
}else if(i%5==0){
transactionDB.execSQL("INSERT INTO transactionList (type, amount, category, createdAt) VALUES('ne', ${a}, 'K', CURRENT_TIMESTAMP)")
adapter.swapCursor(getAllItems())
}else if(i%6==0){
transactionDB.execSQL("INSERT INTO transactionList (type, amount, category, createdAt) VALUES('ne', ${a}, 'K', CURRENT_TIMESTAMP)")
adapter.swapCursor(getAllItems())
}else{
transactionDB.execSQL("INSERT INTO transactionList (type, amount, category, createdAt) VALUES('e', ${a}, 'K', CURRENT_TIMESTAMP)")
adapter.swapCursor(getAllItems())
}
}
}
private fun getAllItems(): Cursor {
return transactionDB!!.query(
TransactionList.TransactionEntry.TABLE_NAME,
null,
null,
null,
null,
null,
TransactionList.TransactionEntry.COLUMN_CREATEDAT + " DESC")
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_list, container, false)
val rvRecyclerView = view.findViewById<RecyclerView>(R.id.rvRecyclerView)
rvRecyclerView.layoutManager = LinearLayoutManager(activity)
if(mCursorFilter!=null){
adapter.swapCursor(mCursorFilter!!)
}
rvRecyclerView.adapter = this.adapter
rvRecyclerView.addItemDecoration(MarginItemDecoration(10))
flActBtn = view.findViewById(R.id.floatingActionButton)
flActBtn.setOnClickListener {
var ft:FragmentTransaction = activity!!.supportFragmentManager.beginTransaction()
ft.replace(R.id.flFrameLayout, AddItemFragment(transactionDB, adapter))
ft.addToBackStack(null)
ft.commit()
}
filterBtn=view.findViewById(R.id.ibFilterBtn)
filterBtn.setOnClickListener {
var ft:FragmentTransaction = activity!!.supportFragmentManager.beginTransaction()
ft.replace(R.id.flFrameLayout, SetListFilters(transactionDB, adapter))
ft.addToBackStack(null)
ft.commit()
}
addRandomTransactionItem()
return view
}
}
class MainActivity() : AppCompatActivity() {
var mCursorFilters: Cursor? = null
private val viewModel: ItemViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.selectedItem.observe(this, Observer { item ->
// TODO
})
val homeFragment = HomeFragment()
val listFragment = ListFragment()
val profileFragment = ProfileFragment()
setCurrentFragment(homeFragment)
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomNavigationView)
bottomNavigationView.setOnNavigationItemSelectedListener {
var ft: FragmentTransaction = this.supportFragmentManager.beginTransaction()
when (it.itemId) {
R.id.pageHome -> ft.replace(R.id.flFrameLayout, homeFragment) // setCurrentFragment(homeFragment)
R.id.pageList -> ft.replace(R.id.flFrameLayout, listFragment) //setCurrentFragment(listFragment)
R.id.pageProfile -> ft.replace(R.id.flFrameLayout, profileFragment) //setCurrentFragment(profileFragment)
}
// ft.replace(R.id.flFrameLayout, AddItemFragment())
ft.addToBackStack(null)
ft.commit()
true
}
}
private fun setCurrentFragment(fragment: Fragment){
supportFragmentManager.beginTransaction().apply {
replace(R.id.flFrameLayout, fragment)
commit()
}
}
}