Android Kotlin: Interface override function not being called - android

I have FragmentA and FragmentB.
I am trying to update the values of FragmentA from FragmentB
I have an interface:
interface FragmentCallback {
fun onDataSent(sendUpdatedData: String, position: Int?)
}
In FragmentA, I override the interface function. I also instantiate FragmentB and call setFragmentCallback function
class FragmentA: Fragment(), FragmentCallback {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
FragmentB().setFragmentCallback(this)
}
//This function is not being called from FragmentB...
override fun onDataSent(sendUpdatedData: String, position: Int?) {
updateRecyclerView(sendUpdatedData, position!!)
}
In FragmentB (which is on top of FragmentA) I instantiate the FragmentCallback interface. When I am done editing and pop the fragment(backstack), I call the overridden function from FragmentA(onDataSent).
class FragmentB: Fragment(){
private var fragmentCallback: FragmentCallback? = null
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
btn_save.setOnClickListener{
fragmentCallback?.onDataSent(et_new_text.text.toString(), position )
fragmentManager?.popBackStack()
}
}
fun setFragmentCallback(callback: FragmentCallback?) {
fragmentCallback = callback
}
}
For some reason, when I pop FragmentB and call onDataSent, through the line:
fragmentCallback?.onDataSent(et_new_text.text.toString(), position)
onDataSent will actually NOT be called.

Use a FragmentResultListener in FragmentA:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setFragmentResultListener("requestKey") { key, bundle ->
val sendUpdatedData = bundle.getString("sendUpdatedData")
// Do something with the result...
}
}
Then in FragmentB set the result:
btn_save.setOnClickListener{
val result = et_new_text.text.toString()
setFragmentResult("requestKey", bundleOf("sendUpdatedData" to result))
...
}
Have a look at the official documentation.
The old-fashioned way uses the Activity to communicate between two fragments. You could also use a shared ViewModel to share data.

You can try this too.
Let your activity implements your interface.
class YourActivity : FragmentCallback{
override fun onDataSent(sendUpdatedData: String, position: Int?) {
// Get Fragment A
val fraga: FragmentA? =
supportFragmentManager.findFragmentById(R.id.fragment_a) as FragmentA?
fraga.updateRecyclerView(sendUpdatedData,position)
}
}
In your fragmentB, send the data like this.
class FragmentB : Fragment() {
var mCallback: FragmentCallback? = null
override fun onAttach(activity: Activity) {
super.onAttach(activity)
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
mCallback = try {
activity as FragmentCallback
} catch (e: ClassCastException) {
throw ClassCastException(
activity.toString()
+ " must implement TextClicked"
)
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
mCallback.onDataSent(et_new_text.text.toString(), position)
fragmentManager?.popBackStack()
}
override fun onDetach() {
mCallback = null // => avoid leaking, thanks #Deepscorn
super.onDetach()
}
}
In your FragmentA.
class FragmentA : Fragment() {
fun updateRecyclerView(sendUpdatedData: String, position: Int?) {
// Here you'll have it
}
}

Related

Add Listener into ViewHolder for fragement to communication with Activity

I am trying to trigger the start of a fragment B when a click is detected on an item from the Recycler view present in the Fragment A.
The way I did it is:
MainActivity start the Fragement A and display a list of CardView
Once the user click on one of the CardView, an interface call a click method implemented in the main Activity to start the Fragment B
MainActivity.kt
class MainActivity : AppCompatActivity(), OnLocationSelectedListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if(savedInstanceState == null) { // initial transaction should be wrapped like this
--Start Fragment A
}
}
override fun onLocationSelected(id: String) {
replaceFragment(FragmentB(), R.id.listcontainer, id)
}
companion object {
val LOCATION_ID: String = "location_id"
}
}
The interface is defined in : OnLocationSelectedListener.kt
interface OnLocationSelectedListener {
fun onLocationSelected(id: String)
}
the listener must be called from the Adapter linked to Fragment B
class FragmentBAdapter(
var listOfLocations: List<RestaurantLocation>) : RecyclerView.Adapter<LocationsListAdapter.ViewHolder>() {
private lateinit var onLocationSelectedListener: OnLocationSelectedListener
override fun getItemCount(): Int {
return listOfLocations.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LocationsListAdapter.ViewHolder {
return ViewHolder(
parent.context,
DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.location_item,
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindViewHolder(listOfLocations[position])
}
inner class ViewHolder(private val context: Context, private val viewDataBinding: LocationItemBinding) :
RecyclerView.ViewHolder(viewDataBinding.root) {
fun bindViewHolder(location: RestaurantLocation) {
viewDataBinding.locationName.text = location.name
viewDataBinding.cardItem.setOnClickListener {
onLocationSelectedListener.onLocationSelected(location.id)
}
}
}
}
I have an exception popping up because lateinit property onLocationSelectedListener has not been initialized
I do not understand how to initialize it?
Any idea?
Thanks
You need to pass the listener to the constructor of your FragmentBAdapter, like so:
class FragmentBAdapter(val onLocationSelectedListener: OnLocationSelectedListener)
Your Activity is a OnLocationSelectedListener, so in your Fragment where you create your adapter, probably in onCreateView(), you can just do this
adapter = FragmentBAdapter(activity as? OnLocationSelectedListener)
As you have onLocationSelectedListener's implementation in your MainActivity, you can pass MainActivity's object to FragmentBAdapter and initialize onLocationSelectedListener in FragmentBAdapter's constructor by MainActivity Object

When to call livedata observer?

On a button click i have to get some value from API call and then launch one screen. I have two options:
Call the observer each time when user will click on button.
Call the observer on fragment onActivityCreated() and store the value in variable and act accordingly on button click.
So which approach I should follow?
Actually it's up to you. But i always prefer to call it in Activity's onCreate() function, so activity only has 1 observer. If you call it in button click, it will give you multiple observers as much as button clicking
Here is some example :
class HomeProfileActivity: BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initObserver()
initView()
}
private fun initObserver() {
viewModel.profileWorkProccess.observe(this, {
swipeRefreshLayout.isRefreshing = it
})
viewModel.isLoadingJobs.observe(this, {
layoutProgressBarJobs.visibility = View.VISIBLE
recyclerViewJobs.visibility = View.GONE
dotsJobs.visibility = View.GONE
})
//other viewmodel observing ......
}
private fun initView() {
imageProfile.loadUrl(user.image, R.drawable.ic_user)
textName.text = identity.user?.fullName
textAddress.text = identity.user?.city
buttonGetData.setOnClickListener { viewModel.getData(this) }
}
}
If the button is placed on the Activity, and data is displayed in the Fragment, you need to store variable in Activity ViewModel and observe it in Fragment
You only need to call observe one time when fragment is created.
For example:
class MyActivity : AppCompatActivity() {
val viewModel: MyActViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
myButton.setOnClickListener { view ->
viewModel.getData()
}
}
}
class MyActViewModel: ViewModel {
val data: LiveData<String> = MutableLiveData()
fun getData() {}
}
class MyFragment: Fragment {
val actViewModel: MyActViewModel by activityViewModels()
override fun onActivityCreated(...) {
....
actViewModel.data.observe(viewLifecycleOwner, Observer { data ->
...
}
}
}

How to Open a "Details" Fragment onclick of Recyclerview

I have this fragment, its viewmodel, and its adapter. It can already listen to a click, but all I know to do on this is to show a toast. I want it to go to another fragment which will show its "details", which passes the data of the clicked recyclerview item to that "details" fragment. Hint: on the fragment, there's a //TODO there, and I need the code for that.
Here's the fragment:
class HomeFragment : Fragment(), RecyclerViewClickListener {
private lateinit var factory: HomeViewModelFactory
private lateinit var viewModel: HomeViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?)
{
super.onActivityCreated(savedInstanceState)
val api = DormsAPI()
val repository = DormRepository(api)
factory = HomeViewModelFactory(repository)
viewModel = ViewModelProviders.of(this, factory).get(HomeViewModel::class.java)
viewModel.getDorms()
viewModel.dorms.observe(viewLifecycleOwner, Observer { dorms ->
recyclerViewDorms.also{
it.layoutManager = LinearLayoutManager(requireContext())
it.setHasFixedSize(true)
it.adapter = dormAdapter(dorms, this)
}
})
}
override fun onRecyclerViewItemClick(view: View, dorms: Dorms) {
when(view.id){
R.id.button_reserve -> {
// TODO: Go to new account if not signed up, etc...
Toast.makeText(requireContext(), "Reserve button clicked", Toast.LENGTH_LONG).show()
}
R.id.layoutBox -> {
// TODO: Go to Dorm Details
Toast.makeText(requireContext(), "Go to dorm details", Toast.LENGTH_LONG).show()
}
}
}
}
As for the Adapter class:
class dormAdapter(
private val dorms: List<Dorms>,
private val listener: RecyclerViewClickListener
) : RecyclerView.Adapter<dormAdapter.DormViewHolder>() {
override fun getItemCount() = dorms.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
DormViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.layout_home,
parent, false
)
)
override fun onBindViewHolder(holder: DormViewHolder, position: Int) {
holder.recyclerviewDormBinding.dorm = dorms[position]
holder.recyclerviewDormBinding.buttonReserve.setOnClickListener {
listener.onRecyclerViewItemClick(holder.recyclerviewDormBinding.buttonReserve, dorms[position])
}
holder.recyclerviewDormBinding.layoutBox.setOnClickListener {
listener.onRecyclerViewItemClick(holder.recyclerviewDormBinding.layoutBox, dorms[position])
}
}
inner class DormViewHolder(
val recyclerviewDormBinding: LayoutHomeBinding
) : RecyclerView.ViewHolder(recyclerviewDormBinding.root)
}
Finally, here's the ViewModel:
class HomeViewModel(private val repository: DormRepository) : ViewModel() {
private lateinit var job: Job
private val _dorms = MutableLiveData<List<Dorms>>()
val dorms: LiveData<List<Dorms>>
get() = _dorms
fun getDorms() {
job = Coroutines.ioThenMain(
{ repository.getDorms() },
{ _dorms.value = it }
)
}
override fun onCleared() {
super.onCleared()
if(::job.isInitialized) job.cancel()
}
}
EDIT: I also have this interface, if needed:
interface RecyclerViewClickListener {
fun onRecyclerViewItemClick(view: View, dorms: Dorms)
}
Since we are adding the HomeFragment from an activity, what we will try to do is create a interface to communicate between activity and fragment.
1. Create an interface
class HomeFragment : Fragment(), RecyclerViewClickListener {
...
...
private var callback : Callback? = null
...
...
override fun onAttach(context: Context) {
...
// Callback instance is initialized
if(context is Callback) callback = context
else throw RuntimeException("$context must implement Callback")
}
...
...
override fun onDetach() {
callback = null
}
...
...
override fun onRecyclerViewItemClick(view: View, dorms: Dorms) {
when(view.id){
R.id.button_reserve -> {
// TODO: Go to new account if not signed up, etc...
Toast.makeText(requireContext(), "Reserve button clicked", Toast.LENGTH_LONG).show()
}
R.id.layoutBox -> {
// Go to Dorm Details
callback?.onShowDormDetail(dorm)
}
}
}
...
...
// This interface will act as mode to communication between
// activity and fragment
interface Callback {
fun onShowDormDetail(dorm: Dorm)
}
}
2. Implement the Callback on the calling activity
class HomeActivity : AppCompatActivity(), HomeFragment.Callback {
...
...
override onShowDormDetail(dorm: Dorm) {
// Add or replace the detail fragment here
}
}

App crash after activity has been killed in background

i have an issue with an app that use ViewPager for display fragment. All works fine until the app goes in background and be killed from OS. It seems that after restore i have 2 IncidentScreenFragment that handle events, one with a null presenter (MVP) that crash my app.
My HomeActivity looks like:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
presenter.onViewCreated()
initViews(savedInstanceState)
}
private fun initViews(savedInstanceState: Bundle?){
mapView.onCreate(savedInstanceState)
mapView.getMapAsync(this)
initFragment()
initMenu()
}
private fun initFragment(){
homeFragment = HomeScreenFragment.newInstance()
incidentFragment = IncidentScreenFragment.newInstance()
chatFragment = ChatFragment.newInstance()
weatherFragment = WeatherFragment.newInstance()
viewPager.adapter = ViewPagerAdapter(supportFragmentManager, this)
viewPager.offscreenPageLimit = 4
viewPager?.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) {bottom_navigation.currentItem = position}
})
}
override fun getFragmentByPos(pos: Int): Fragment {
return when(pos){
0 -> homeFragment
1 -> incidentFragment
2 -> chatFragment
3 -> weatherFragment
else -> {
homeFragment
}
}
}
And my Adapter:
class ViewPagerAdapter internal constructor(fm: FragmentManager, activity:infinite_software.intelligence_center.intelligencecenter.ui.home.FragmentManager) : FragmentPagerAdapter(fm) {
private val COUNT = 4
private val activity = activity
override fun getItem(position: Int): Fragment{
var fragment: Fragment? = null
when (position) {
0 -> fragment = activity.getFragmentByPos(0)
1 -> fragment = activity.getFragmentByPos(1)
2 -> fragment = activity.getFragmentByPos(2)
3 -> fragment = activity.getFragmentByPos(3)
}
return fragment!!
}
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
super.destroyItem(container, position, `object`)
}
override fun getCount(): Int {
return COUNT
}
override fun getPageTitle(position: Int): CharSequence? {
return "Section " + (position + 1)
}
}
Each Fragment have a static method that return new Fragment:
companion object {
fun newInstance(): HomeScreenFragment {
return HomeScreenFragment()
}
}
When the app has been killed in background i figure out that there is 2 objects (Fragment) that listen to event, one with Presenter correctly instantiate and one without.
Below my abstract BaseFragment class:
abstract class BaseFragment<P : BasePresenter<BaseView>> : BaseView,Fragment() {
protected lateinit var presenter: P
override fun getContext(): Context {
return activity as Context
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
presenter = instantiatePresenter()
}
override fun showError(error: String) {
(activity as BaseActivity<BasePresenter<BaseView>>).showError(error)
}
override fun showError(errorResId: Int) {
(activity as BaseActivity<BasePresenter<BaseView>>).showError(errorResId)
}
abstract fun onBackPressed(): Boolean
/**
* Instantiates the presenter the Fragment is based on.
*/
protected abstract fun instantiatePresenter(): P
abstract val TAG: String
Incident Fragment code:
class IncidentScreenFragment: BaseFragment<IncidentScreenPresenter>(), BaseView, IncidentView, AlertFilterListener, AlertItemClickListener, IncidentDetailListener {
var rvAdapter : IncidentAdapter? = null
var state : Int = LIST_STATE
override fun instantiatePresenter(): IncidentScreenPresenter {
return IncidentScreenPresenter(this)
}
override val TAG: String
get() = "INCIDENT"
override fun getContext(): Context {
return activity as Context
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
return inflater.inflate(R.layout.fragment_incident, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
presenter.onViewCreated()
initObserve()
}
private fun initViews(){
//Reclycler view
alertRV.layoutManager = LinearLayoutManager(context)
rvAdapter = IncidentAdapter(ArrayList(), context, this)
alertRV.adapter = rvAdapter
//Apply Listeners
headerBox.setFilterListener(this)
incidentDetailView.setListener(this)
}
override fun initObserve() {
//Init observe presenter model
val alertObserver = Observer<ArrayList<AlertModel>> { alerts ->
Timber.d("Data received from Presenter [$alerts]")
showAlertList(alerts)
}
presenter.filteredAlertList.observe(context as BaseActivity<BasePresenter<BaseView>>,alertObserver)
}
override fun updateThisFilters(boxState: Boolean, level: Int) {
presenter.updateFilterList(boxState,level)
}
fun showOnlyThisLevel(level:Int){
presenter.showOnlyThisLevel(level)
headerBox.disableBoxExcept(level)
}
fun showAlertList(list: ArrayList<AlertModel>){
rvAdapter?.updateData(list)
}
override fun onItemClick(model: AlertModel) {
presenter.loadAlertDetail(model)
}
override fun showAlertDetail(model: AlertModel) {
incidentDetailView.setUpFromModel(model)
WhiteWizard.slideLeftEffect(incidentDetailView,incidentListRootElement)
state = DETAIL_STATE
}
override fun onbackFromDetailPressed() {
WhiteWizard.slideRightEffect(incidentListRootElement,incidentDetailView)
state = LIST_STATE
}
override fun showLoader() {
loaderIncident.visibility = View.VISIBLE
}
override fun hideLoader() {
loaderIncident.visibility = View.INVISIBLE
}
override fun onBackPressed(): Boolean {
when(state){
LIST_STATE -> return false
DETAIL_STATE -> {
onbackFromDetailPressed()
return true
}
else -> return false
}
}
fun newInstance(): IncidentScreenFragment {
return IncidentScreenFragment()
}
}
When i click on the button in homePage to display fragment content i got:
Process: XXXXXX, PID: 3192
kotlin.UninitializedPropertyAccessException: lateinit property presenter has not been initialized
at infinite_software.intelligence_center.intelligencecenter.base.BaseFragment.getPresenter(BaseFragment.kt:11)
at XXXXXX.ui.home.incidentScreen.IncidentScreenFragment.showOnlyThisLevel(IncidentScreenFragment.kt:78)
at XXXXXX.ui.home.HomeActivity.filterDataWithSeverity(HomeActivity.kt:110)
at XXXXXX.ui.home.homeScreen.HomeScreenFragment.filterBy(HomeScreenFragment.kt:76)
at XXXXXX.ui.home.homeScreen.HomeScreenFragment$initViews$5.onClick(HomeScreenFragment.kt:56)
If i try to print the id of Fragment, i obtain 2 different ids from method call showOnlyThisLevel() and onBackPressed(). What i miss ?
After doing some research, it seems that the problem stems from the misnaming of FragmentPagerAdapter's method - being named getItem(), but not clearly specifying that the abstract method getItem(int position) is supposed to return a new instance of a fragment rather than just "get an instance of one".
Of course, there is not much we can do about an incorrect name after it's been out in the wild for 7 years, but at least we can fix the bug that stems from this issue in your code ;)
Without further ado, the cause of your NPE is that onCreateView (where your Presenter is instantiated) is never called.
This happens because you are creating the fragment here:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
...
homeFragment = HomeScreenFragment.newInstance()
incidentFragment = IncidentScreenFragment.newInstance()
}
You return this fragment from inside getItem(int position) in your FragmentPagerAdapter:
override fun getItem(position: Int): Fragment = when(position) {
...
1 -> activity.incidentFragment
...
}
So what we know about activity.incidentFragment is that in it, onCreateView() is never called.
This is caused by the fact that it's never actually added to a FragmentManager and never displayed on the screen.
That's because super.onCreate(savedInstanceState) in Activity recreates all Fragments, using their no-args constructor, via reflection, while keeping their tag (see findFragmentByTag).
So as you can see in this answer, or as I can quote here:
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
The getItem(position) method is only called if the Fragment is not found by the fragment tag that the FragmentPagerAdapter sets for the fragment, which IS automatically recreated after low memory condition kills your app.
Therefore, YOUR new fragment (that you create by hand in the Activity) is NEVER used, and therefore it has no view, never initialized, never added to FragmentManager, it's not the same instance as what's actually inside your ViewPager, and it crashes when you call it. Boom!
Solution is to instantiate the Fragment inside FragmentPagerAdapter's getItem(position) method. To get an instance of the fragment, use this answer.

Does Kotlin have a way to delegate the implementation of an interface to another class?

I am using one activity and three fragments for my application
Each fragment has an interface that is used to communicate with the logic
the activity implements this interface and calls the logic object (a persistent fragment) with the same arguments, so it looks something like this:
class Child : Fragment() {
private fun userInteraction() {
(activity as? ChildInteraction)?.askStuff()
}
interface ChildInteraction {
fun askStuff():Unit
}
}
class ParentActivity : AppCompatActivity(), ChildInteraction {
override fun askStuff() {
(supportFragmentManager.findFragmentByTag("LOGIC") as? ChildInteraction).askStuff()
}
}
class LogicFragment : Fragment(), ChildInteraction {
override fun askStuff() {
//do some work here
}
}
the thing is, that each interaction has 5-10 methods in it, and all ParentActivity does is pass on the message, is there a way to simplify the passing along?
I know you can't do this in Java but I was hoping there is a way for Kotlin to do it
Take a look on setTargetFragment and getTargetFragment. Here is an example of Fragment-to-Fragment communication:
interface ChildInteraction {
companion object
fun askStuff()
}
fun ChildInteraction.Companion.wrap(f: Fragment) = (f.targetFragment as? ChildInteraction)
class Child1 : Fragment() {
private fun userInteraction() {
ChildInteraction.wrap(this)?.askStuff()
}
}
class Child2 : Fragment() {
private fun userInteraction() {
ChildInteraction.wrap(this)?.askStuff()
}
}
class LogicFragment : Fragment(), ChildInteraction {
override fun askStuff() {
//do some work here
}
}
class ParentActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val logic ...
val child1 ...
child1.setTargetFragment(logic, 0)
val child2 ...
child2.setTargetFragment(logic, 0)
}
}
Now I know that this is probably what works for me, so I'll be still accepting the other answer, and because it taught me something I didn't know.
But after some work the way that I handled it was this:
The fragment that attaches looks like this:
class Child : Fragment() {
private var parent: ChildInteraction? = null
override fun onAttach(context: Context?) {
super.onAttach(context)
//this should throw an exception if it is not implemented correctly
parent = (context as LogicProvider).logic!! as Child.ChildInteraction
}
private fun userInteraction() {
parent!!.askStuff()
}
interface ChildInteraction {
fun askStuff():Unit
}
}
Then I have the LogicProvider interface like this:
interface LogicProvider {
val logic: Any?
}
and then the parent will implement logic providers that will pass on the arguments
class ParentActivity : AppCompatActivity(), LogicProvider {
override var logic: Logic? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var frag: Fragment? = supportFragmentManager.findFragmentByTag("parent_logic")
if (frag == null) {
frag = Logic()
supportFragmentManager.beginTransaction().add(frag, "parent_logic").commitNow()
}
logic = frag as Logic
}
override fun onPause() {
super.onPause()
if (isFinishing)
supportFragmentManager.beginTransaction().remove(supportFragmentManager.findFragmentByTag("parent_logic")).commitNow()
}
}
that way the logic fragment is the only one that has to implement interfaces
class Logic : Fragment(), Child.ChildInteraction, Child2.ChildInteraction2 {
override fun askStuff() {
//do stuff here
}
override fun askStuff2() {
//do other stuff here
}
}

Categories

Resources