Имплементация метода интерфейса во фрагменте android
Я решил использовать Navigation Drawer(стандартно созданный средствами Android Studio) и переключаюсь в нем между несколькими фрагментами. Так вот в одном из фрагментов(GalleryFragment) у меня есть RecyclerView и для него я написал класс OrderListAdapter и в этом классе я вызываю метод интерфейса openFragment(position) имплементация которого находится в GalleryFragment.
MainNavigationActivity
class MainNavigationActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_navigation)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow
), drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main_navigation, menu)
return true
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}
GalleryFragment
class GalleryFragment : Fragment(), AdapterView.OnItemSelectedListener, OpenFragment,
FragmentData {
private lateinit var viewModel: GalleryViewModel
private lateinit var recyclerOrders: RecyclerView
private lateinit var adapter: OrderListAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_gallery, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProvider(this).get(GalleryViewModel::class.java)
setHasOptionsMenu(true)
initializeRecycler()
}
override fun onResume() {
super.onResume()
if (this::adapter.isInitialized)
displayData()
}
private fun initializeRecycler() {
recyclerOrders = requireView().findViewById(R.id.recycler_orders)
recycler_orders.setHasFixedSize(true)
recycler_orders.layoutManager = (LinearLayoutManager(requireContext()))
viewModel.loadingState.observe(viewLifecycleOwner, Observer {
when (it.status) {
LoadingState.Status.FAILED -> Toast.makeText(
requireContext(),
it.msg,
Toast.LENGTH_SHORT
).show()
LoadingState.Status.RUNNING -> Toast.makeText(
requireContext(),
"Loading",
Toast.LENGTH_SHORT
).show()
LoadingState.Status.SUCCESS -> displayData()
}
})
}
private fun displayData() {
val tmpArrayOrders = ArrayList<Order>()
for (tmp in viewModel.orders) {
if (status[viewModel.actualStatus].value == tmp.status || status[viewModel.actualStatus].value < 0) {
tmpArrayOrders.add(tmp)
}
}
adapter = OrderListAdapter(requireContext(), tmpArrayOrders)
recyclerOrders.adapter = adapter
}
override fun openFragment(position: Int) {
val fragment = OrderFragment()
val bundle = Bundle()
bundle.putInt("position", position)
fragment.arguments = bundle
requireActivity().supportFragmentManager.beginTransaction()
.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
.replace(R.id.order_fragment, fragment)
.commit()
}
}
OpenFragment (интерфейс)
interface OpenFragment {
fun openFragment(position: Int)
}
OrderListAdapter
class OrderListAdapter(
var context: Context,
var orderList: List<Order>) :
RecyclerView.Adapter<OrderListViewHolder>() {
private lateinit var mDataPasser: OpenFragment
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OrderListViewHolder {
mDataPasser = context as OpenFragment
val view: View = LayoutInflater.from(parent.context)
.inflate(R.layout.order_layout, parent, false)
return OrderListViewHolder(view)
}
override fun onBindViewHolder(holder: OrderListViewHolder, position: Int) {
val order = orderList[position]
var tmpStatus: String = ""
for (tmp in status) {
if (tmp.value == order.status) {
tmpStatus = tmp.name
}
}
holder.id.text = order.id.toString()
holder.adres.text = order.adres.toString()
holder.user_id.text = order.user_id.toString()
holder.cena.text = order.cena.toString()
holder.status.text = tmpStatus.toString()
holder.data.text = order.data.toString()
holder.card.setOnClickListener {
mDataPasser.openFragment(position)
}
}
override fun getItemCount(): Int {
return orderList.size
}
}
Так вот, во фрагменте я инициализирую adapter и передаю context adapter = OrderListAdapter(requireContext(), tmpArrayOrders) и тут сама проблема. Так как я передаю context активити, а не фрагмента, то компилятор ругается на то, что нет имплементации метода интерфейса в активити. Это логично, т.к. передаю контекс активити и если заимплементировать метод в активити, то все будет работать. Но я бы не хотел загрязнять активити, чтобы это все оставалось во фрагменте.
Сама ошибка:
java.lang.ClassCastException: com.example.staff.MainNavigationActivity cannot be cast to com.example.staff.model.OpenFragment
Отсюда следует вопрос: как передать context именно фрагмента? Либо как правильно имплементировать методы интерфейса во фрагменте?
Ответы (1 шт):
Небольшое изменение адаптера:
class OrderListAdapter(
var context: Context,
var orderList: List<Order>
) : RecyclerView.Adapter<OrderListViewHolder>() {
lateinit var mDataPasser: OpenFragment // private modifier REMOVED
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OrderListViewHolder {
//mDataPasser = context as OpenFragment REMOVED
val view: View = LayoutInflater.from(parent.context)
.inflate(R.layout.order_layout, parent, false)
return OrderListViewHolder(view)
}
...
}
И создание из фрагмента:
adapter = OrderListAdapter(requireContext(), tmpArrayOrders)
adapter.mDataPasser = this // ADDED
recyclerOrders.adapter = adapter
Можно и отдельно передавать OpenFragment через конструктор адаптера. Ничего не мешает передать и контекст и OpenFragment как отдельные поля.