I'm trying to integrate a VerticalGridSupportFragment() inside a BrowseSupportFragment() based on some of the Leanback examples.
On running the code below (partial snippet provided below) I get the exception java.lang.IllegalArgumentException: Fragment must implement MainFragmentAdapterProvider
I'm struggling to understand how to implement the interface methods defined by MainFragmentAdapterProvider [i.e getMainFragmentAdapter()]. Could anyone provide insight surrounding this issue, or could you provide an example? I've tried to return the mRowsAdapter, however it was not of the correct type.
Any help would really be appreciated, thanks!
class MainFragmentByGroupFragment : BrowseSupportFragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
Log.i(TAG, "onCreate")
super.onActivityCreated(savedInstanceState)
prepareBackgroundManager()
mainFragmentRegistry.registerFragment(
PageRow::class.java,
PageRowFragmentFactory(mBackgroundManager)
)
setupUIElements()
createRows()
setupEventListeners()
}
private class PageRowFragmentFactory(backgroundManager: BackgroundManager) : BrowseSupportFragment.FragmentFactory<androidx.fragment.app.Fragment>() {
override fun createFragment(rowObj: Any?): androidx.fragment.app.Fragment {
val row = rowObj as Row
return ChannelFragment()
}
}
}
class ChannelFragment : VerticalGridSupportFragment(), OnItemViewClickedListener, BrowseSupportFragment.MainFragmentAdapterProvider {
private var mRowsAdapter: ArrayObjectAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mRowsAdapter = ArrayObjectAdapter(CardPresenter())
setAdapter(mRowsAdapter)
setOnItemViewClickedListener(this)
createRows()
}
private fun createRows() {
val gridPresenter = VerticalGridPresenter()
gridPresenter.numberOfColumns = NUM_COLUMNS
setGridPresenter(gridPresenter)
setOnItemViewClickedListener(this)
val list = MovieList.list
for (i in 0 until 100) {
mRowsAdapter!!.add(list[i % 5])
}
}
override fun onItemClicked(
itemViewHolder: Presenter.ViewHolder?, item: Any,
rowViewHolder: RowPresenter.ViewHolder?, row: Row?
) {
}
override fun getMainFragmentAdapter(): BrowseSupportFragment.MainFragmentAdapter<*> {
TODO("Not yet implemented")
}
companion object {
private const val NUM_COLUMNS = 5
}
}
I think you should implement getMainFragmentAdapter.
Add the following to ChannelFragment:
private val mMainFragmentAdapter: BrowseSupportFragment.MainFragmentAdapter<*> =
object : BrowseSupportFragment.MainFragmentAdapter<Fragment?>(this) {
override fun setEntranceTransitionState(state: Boolean) {
}
}
And return mMainFragmentAdapter in getMainFragmentAdapter:
override fun getMainFragmentAdapter(): BrowseSupportFragment.MainFragmentAdapter<*> {
return mMainFragmentAdapter
}
Related
I m getting data from two End points using flows and assigning those two list to temporary list in ViewModel. For this purpose, I'm using combine function and returning result as stateFlows with stateIn operator but that's not working. Can anyone point me out where I go wrong please.
ViewModel.kt
private val _movieItem: MutableStateFlow<State<List<HomeRecyclerViewItems>>> =
MutableStateFlow(State.Loading())
val movieItems: StateFlow<State<List<HomeRecyclerViewItems>>> = _movieItem
fun getHomeItemList() {
viewModelScope.launch {
val testList: Flow<State<List<HomeRecyclerViewItems.Movie>>> =
settingsRepo.getMovieList().map {
State.fromResource(it)
}
val directorList: Flow<State<List<HomeRecyclerViewItems.Directors>>> =
settingsRepo.getDirectorList().map {
State.fromResource(it)
}
_movieItem.value = combine(testList, directorList) { testList, directorList ->
testList + directorList // This is not working as "+" Unresolve Error
}.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5000),
State.loading<Nothing>()
) as State<List<HomeRecyclerViewItems>> // Unchecked cast: StateFlow<Any> to State<List<HomeRecyclerViewItems>>
}
Repository.kt
fun getMovieList(): Flow<ResponseAPI<List<HomeRecyclerViewItems.Movie>>> {
return object :
NetworkBoundRepository<List<HomeRecyclerViewItems.Movie>, List<HomeRecyclerViewItems.Movie>>() {
override suspend fun saveRemoteData(response: List<HomeRecyclerViewItems.Movie>) {
}
override fun fetchFromLocal() {
}
override suspend fun fetchFromRemote(): Response<List<HomeRecyclerViewItems.Movie>> =
apiInterface.getMoviesList()
}.asFlow()
}
fun getDirectorList(): Flow<ResponseAPI<List<HomeRecyclerViewItems.Directors>>> {
return object :
NetworkBoundRepository<List<HomeRecyclerViewItems.Directors>, List<HomeRecyclerViewItems.Directors>>() {
override suspend fun saveRemoteData(response: List<HomeRecyclerViewItems.Directors>) {
}
override fun fetchFromLocal() {
}
override suspend fun fetchFromRemote(): Response<List<HomeRecyclerViewItems.Directors>> =
apiInterface.getDirectorsList()
}.asFlow()
}
Network BoundRepository.kt
#ExperimentalCoroutinesApi
abstract class NetworkBoundRepository<RESULT, REQUEST> {
fun asFlow() = flow<ResponseAPI<REQUEST>> {
val apiResponse = fetchFromRemote()
val remotePosts = apiResponse.body()
if (apiResponse.isSuccessful && remotePosts != null) {
emit(ResponseAPI.Success(remotePosts))
} else {
emit(ResponseAPI.Failed(apiResponse.errorBody()!!.string()))
}
}.catch { e ->
e.printStackTrace()
emit(ResponseAPI.Failed("Server Problem! Please try again Later. "))
}
#WorkerThread
protected abstract suspend fun saveRemoteData(response: REQUEST)
#MainThread
protected abstract fun fetchFromLocal()
#MainThread
protected abstract suspend fun fetchFromRemote(): Response<REQUEST>
}
Endpoints with Sealed Class
#GET("directors")
fun getDirectorsList(): Response<List<HomeRecyclerViewItems.Directors>>
#GET("movies")
fun getMoviesList(): Response<List<HomeRecyclerViewItems.Movie>>
sealed class HomeRecyclerViewItems {
class Title(
val id: Int,
val title: String
) : HomeRecyclerViewItems()
class Movie(
val id: Int,
val title: String,
val thumbnail: String,
val releaseDate: String
) : HomeRecyclerViewItems()
class Directors(
val id: Int,
val name: String,
val avator: String,
val movie_count: Int
) : HomeRecyclerViewItems()
}
Fragment.kt
#AndroidEntryPoint
#ExperimentalCoroutinesApi
class SettingsFragment : BaseBottomTabFragment() {
private var _binding: FragmentSettingsBinding? = null
private val binding get() = _binding!!
private val viewModel by viewModels<SettingViewModel>()
#Inject
lateinit var recyclerViewAdapter: RecyclerViewAdapter
#Inject
lateinit var bundle: Bundle
var finalList = mutableListOf<HomeRecyclerViewItems>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
_binding = FragmentSettingsBinding.inflate(layoutInflater,container,false)
val view = binding.root
binding.rvMovie.apply {
setHasFixedSize(true)
layoutManager = LinearLayoutManager(activity)
}
bundle.putString("Hello","hihg")
Toast.makeText(activity, "${bundle.getString("Hello")}", Toast.LENGTH_SHORT).show()
finalList.add(HomeRecyclerViewItems.Title(1,"hello"))
return view
}
private fun observeList() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED){
launch {
viewModel.movieItems.collect { state ->
when(state){
is State.Loading ->{
}
is State.Success->{
if (state.data.isNotEmpty()){
recyclerViewAdapter = RecyclerViewAdapter()
binding.rvMovie.adapter = recyclerViewAdapter
recyclerViewAdapter.submitList(finalList)
}
}
is State.Error -> {
Toast.makeText(activity, "Error", Toast.LENGTH_SHORT).show()
}
else -> Unit
}
}
}
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
(activity as MainActivity).binding.ivSearch.isGone = true
viewModel.getHomeItemList()
observeList()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
Note: I m following this tutorial simpliedCoding for api data for multirecyclerview but want to implement it with Kotlin State Flow. Any help in this regard is highly appreciated. Thanks.
Your problem is in here
val testList: Flow<State<List<HomeRecyclerViewItems.Movie>>> =
settingsRepo.getMovieList().map {
State.fromResource(it)
}
val directorList: Flow<State<List<HomeRecyclerViewItems.Directors>>> =
settingsRepo.getDirectorList().map {
State.fromResource(it)
}
_movieItem.value = combine(testList, directorList) { testList, directorList ->
testList + directorList
}
They are not returning a List<HomeRecyclerViewItems>, but a State<List<HomeRecyclerViewItems>. Maybe a better name for the variables are testsState and directorsState. After that it will be more clear why you need to unpack the values before combining the lists
_movieItem.value = combine(testsState, directorsState) { testsState, directorsState ->
val homeRecyclerViewItems = mutableListOf<HomeRecyclerViewItems>()
if (testsState is Success) homeRecyclerViewItems.add(testsState.data)
if (directorsState is Success) homeRecyclerViewItems.add(directorsState.data)
homeRecyclerViewItems
}
I want to use the below object in another class:
private var mSingleAccountApp: ISingleAccountPublicClientApplication? = null
PublicClientApplication.createSingleAccountPublicClientApplication(
this,
R.raw.auth_config_single_account,
object : IPublicClientApplication.ISingleAccountApplicationCreatedListener {
override fun onCreated(application: ISingleAccountPublicClientApplication) {
mSingleAccountApp = application
// loadAccount()
}
override fun onError(exception: MsalException) {
//txt_log.text = exception.toString()
}
}
)
I need to call the below method from another class
fun performOperationOnSignOut() {
mSingleAccountApp!!.signOut(object : ISingleAccountPublicClientApplication.SignOutCallback {
override fun onSignOut() {
}
override fun onError(exception: MsalException) {
//displayError(exception)
}
})
}
I tried to call but mSingleAccountApp always throws NullPointerException
How can I pass or use the mSingleAccountApp variable in another class?
ISingleAccountPublicClientApplication this is an interface
This is the simplest example I could come up with:
//class with one property
class Foo(val name : String){
}
class Bar(){
constructor(foo: Foo) : this() {
//access the property of the foo object
println(foo.name)
}
}
fun main() {
val foo = Foo("John Doe")
//pass foo-object in the constructor
val bar = Bar(foo)
}
see also: https://kotlinlang.org/docs/reference/properties.html
class CustomClass(var listener: ListenerAppImp){
private var mSingleAccountApp: ISingleAccountPublicClientApplication? = null
PublicClientApplication.createSingleAccountPublicClientApplication(
this,
R.raw.auth_config_single_account,
object : IPublicClientApplication.ISingleAccountApplicationCreatedListener {
override fun onCreated(application: ISingleAccountPublicClientApplication) {
mSingleAccountApp = application
listener.getAppValue(mSingleAccountApp) // todo mSingleAccountApp Value through interface
// loadAccount()
}
override fun onError(exception: MsalException) {
//txt_log.text = exception.toString()
}
}
)
}
// todo for example
interface ListenerAppImp {
fun getAppValue(mSingleAccountApp : ISingleAccountPublicClientApplication)
}
class User {
var customClass = CustomClass(object : ListenerAppImp{
override fun getAppValue(mSingleAccountApp: ISingleAccountPublicClientApplication) {
}
})
}
hope that may help you
In your case just implement interface ISingleAccountPublicClientApplication in another class for your understanding let's keep class name is Another
class Another : ISingleAccountPublicClientApplication {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
.....InitialiseYourInterfaceHere.....
}
override fun signOut(..yourcode...){
.......yourcode.......
}
}
I want to get a variable from an activity and use it in another class.
This variable will be filled by an user in a editText that is called editTextSerie
override fun searchSeries(listener: OnDataListener) {
val retrofit = Retrofit.Builder().addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://api.themoviedb.org/3/")
.build()
val client = retrofit.create(MovieDBApiInterface::class.java)
val objetoClasse1 = SearchActivity()
var nomeS = objetoClasse1.editTextSerie.text.toString().trim()
val responseCall = client.searchSeries("API_KEY", "pt-BR", nomeS)
responseCall.enqueue(object : Callback<AllSeriesResponse> {
override fun onResponse(call: Call<AllSeriesResponse>?, response1: Response<AllSeriesResponse>?) {
listener.onSuccess(response1!!.body()!!.results)
}
override fun onFailure(call: Call<AllSeriesResponse>?, t: Throwable?) {
listener.onFailure(t!!.message.toString())
}
})
}
This function "searchSeries" is from the class "Series".
I want to get the "editTextSerie" from another class called "Search Activity",
so i created the variable "nomeS" to receive the value of it.
class SearchActivity : AppCompatActivity() {
var botaoSearch: AppCompatImageButton? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_search)
botaoSearch = findViewById(R.id.btn_search)
botaoSearch?.setOnClickListener {
var nomeSerie = editTextSerie.text.toString().trim()
}
}
}
I want to receive this value (value of editTextSerie comes from the XML of SearchActivity ) and use it at responseCall with the "nomeS" variable
What is OnDataListener? Not really sure it is interface or abstract class, so I' ll write some pseudo code.
First change your function searchSeries's params to
searchSeries(text: String, listener: OnDataListener)
So in the class Series, you can get the data in your function searchSeries:
override fun searchSeries(text: String, listener: OnDataListener) {
// ...
// you can get the "text" string
}
Then edit your SearActivity's listener:
class SearchActivity : AppCompatActivity() {
var botaoSearch: AppCompatImageButton? = null
// create class "Series"
val series = Series()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_search)
botaoSearch = findViewById(R.id.btn_search)
botaoSearch?.setOnClickListener {
var nomeSeries = editTextSerie.text.toString().trim()
searchSeries(nomeSeries)
}
}
private fun searchSeries(text: String) {
series.searchSeries(text, object : OnDataListener {
override onSuccess(a0: ...) {
}
override onFailure(message: String) {
}
})
}
}
If OnDataListener is a abstract class:
series.searchSeries(text, object : OnDataListener() {
override onSuccess(a0: ...) {
}
override onFailure(message: String) {
}
})
Hello iam learning build apps with kotlin but i got stack with this error says "Required Iterable, Found List", how i can solve this problem? please see my code below thanks
class MainActivity : AppCompatActivity(),ProductView {
private lateinit var productAdapter: ProductAdapter
private var productList: MutableList<ProductData> = mutableListOf()
private lateinit var dataPresenter : DataPresenter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initRecycler();
getProduct()
}
private fun getProduct() {
dataPresenter = DataPresenter(applicationContext,this)
dataPresenter.getProduct()
}
private fun initRecycler() {
productAdapter = ProductAdapter(this,productList)
rvMain.layoutManager = LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false)
rvMain.adapter = productAdapter
}
override fun showLoading() {
pgMain.visibility = View.VISIBLE
}
override fun hideLoading() {
pgMain.visibility = View.GONE
}
override fun showProduct(products: List<ProductData>?) {
if (products?.size != 0){
this.productList.clear()
this.productList.addAll(products) // <= Required Iterable<ProductData>, Found List<ProductData>
productAdapter.notifyDataSetChanged()
}
}
}
I suspect that the error message actually is:
Required Iterable<ProductData>, Found List<ProductData>?
The question mark at the end is not just punctuation. That is the nullable indicator in Kotlin. A List<ProductData> cannot be null, but a List<ProductData>? can. And I believe that addAll() requires a non-null value.
Ideally, you should change ProductView so that the signature for showProduct() is fun showProduct(products: List<ProductData>).
Alternatively, you could rewrite showProduct() to be:
override fun showProduct(products: List<ProductData>?) {
if (products?.size != 0){
this.productList.clear()
products?.let { this.productList.addAll(it) }
productAdapter.notifyDataSetChanged()
}
}
This question already has answers here:
Pass ArrayList<? implements Parcelable> to Activity
(6 answers)
Closed 5 years ago.
I have a custom class filled with information of a User. I use an ArrayList to hold all the User class data. I would like to pass the array to another activity where the it can be read and modified. Since the array could be large, I need this process to be done as efficiently and fast as possible, which is why I choose to use Parcelable instead of Serializable.
I am having trouble doing this using Kotlin. There are lots of Java tutorials but none are in Kotlin, which is what makes this question different then all the others. Can someone please provide and explain the code in Kotlin on how this can be achieved?
This is what I have so far:
constructor(`in`:Parcel) {
CollegeName = `in`.readString()
}
override fun describeContents(): Int {
return 0
}
override fun writeToParcel(dest: Parcel?, flags: Int) {
}
private fun readFromParcel(`in`:Parcel) {
CollegeName = `in`.readString()
}
companion object {
#JvmField final val CREATOR: Parcelable.Creator<College> = object: Parcelable.Creator<College> {
override fun createFromParcel(source: Parcel): College {
return College(source)
}
override fun newArray(size: Int): Array<College?> {
return arrayOfNulls<College>(size)
}
}
}
Use something like this...
class Series() : Parcelable {
private var name: String? = null
private var numOfSeason: Int = 0
private var numOfEpisode: Int = 0
constructor(parcel: Parcel) : this() {
val data = arrayOfNulls<String>(3)
parcel.readStringArray(data)
this.name = data[0]
this.numOfSeason = Integer.parseInt(data[1])
this.numOfEpisode = Integer.parseInt(data[2])
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name);
parcel.writeInt(numOfSeason);
parcel.writeInt(numOfEpisode);
}
private fun readFromParcel(parcel: Parcel){
name = parcel.readString()
numOfSeason = parcel.readInt()
numOfEpisode = parcel.readInt()
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Creator<Series> {
override fun createFromParcel(parcel: Parcel): Series {
return Series(parcel)
}
override fun newArray(size: Int): Array<Series?> {
return arrayOfNulls(size)
}
}
}
and then in your Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
val i = Intent(this, SecondActivity::class.java)
val testing = ArrayList<testparcel>()
i.putParcelableArrayListExtra("extraextra", testing)
startActivity(i)
}
class SecondActivity :Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.secondActivty_activity)
val testing = this.intent.getParcelableArrayListExtra<Parcelable>("extraextra")
}
}