classifier does not have a companion object - android-studio

i want to use BottomNavigationView in my app and i'm facing this problem with kotlin (never had it before with java) i see this message :
classifier 'listFragment' does not have a companion object and thus must be initialized here
this is my code :
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.listNav -> {
//the problem is here in listFragment word below
setFragment(listFragment)
return#OnNavigationItemSelectedListener true
}
R.id.accountNav -> {
//the problem is here also in accountFragment word below
setFragment(accountFragment)
return#OnNavigationItemSelectedListener true
}
false
}
private fun setFragment(fragment: Fragment) {
supportFragmentManager.beginTransaction().replace(R.id.mainFrame , fragment).commit()
}
any help is appreciated :)

i edited it this way and it worked :
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.listNav -> {
val mFragment = cartFragment.newInstance()
openFragment(mFragment)
return#OnNavigationItemSelectedListener true
}
R.id.cartNav -> {
val mFragment = cartFragment.newInstance()
openFragment(mFragment)
return#OnNavigationItemSelectedListener true
}
R.id.supportNav -> {
val mFragment = supportFragment.newInstance()
openFragment(mFragment)
return#OnNavigationItemSelectedListener true
}
R.id.accountNav -> {
val mFragment = accountFragment.newInstance()
openFragment(mFragment)
return#OnNavigationItemSelectedListener true
}
}
false
}
private fun openFragment(fragment: Fragment) {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.mainFrame, fragment)
transaction.addToBackStack(null)
transaction.commit()
}
fragments goes like this :
class listFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
inflater.inflate(R.layout.fragment_list, container, false)
companion object {
fun newInstance(): listFragment = listFragment()
}
}

If someone is struggling (like I was) with the error in the title produced in a when block,
when compared a sealed object, then don't forget the is keyword, like this:
when (someSealedClass) {
is SomeSealedClass.Foo -> ...
// ^^ don't forget this
}

Related

I can't call bindingAdapterPosition in the ViewHolder

I've a list of elements, I want to make a click event,I'm trying to use the adapterPosition from bind fun inside the ViewHolder, but it's unresolved reference
I know I should be able to use : bindingAdapterPosition or absoluteAdapterPosition but both of them are unrecognized
please guys, can someone see where is the error in my code?
class MyArtistAdapter(
private var dataSet: List<ArtistItem>,
private val openDetails: ((Int) -> Unit)? = null
) :
RecyclerView.Adapter<MyArtistAdapter.ArtistViewHolder>() {
inner class ArtistViewHolder(private var binding: ArtistItemLayoutBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(currentArtist: ArtistItem, openDetails: (Int) -> Unit) {
binding.root.setOnClickListener {
var x = bindingAdapterPosition => error
openDetails(bindingAdapterPosition)=> error
}
binding.tvCollectionArtist.text = currentArtist.collectionName
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArtistViewHolder {
return ArtistViewHolder(
ArtistItemLayoutBinding.inflate(
LayoutInflater.from(parent.context),
parent, false
)
)
}
override fun onBindViewHolder(holder: ArtistViewHolder, position: Int) {
openDetails?.let {
holder.bind(dataSet[position], openDetails)
}
}
override fun getItemCount(): Int {
return dataSet.size
}
}

Firebase Realtime Database images are not showing up in fragment kotlin class

I'm trying to show images from my Firebase Realtime Database storage. I've done this before with a previous version of my app, but the difference is how I implemented it. My adapter and arraylist class are exactly the same, but instead of using an activity I switched to using fragments.
What I essentially did was copy my old work and make the appropriate changes so I wouldn't run into errors, but unfortunately I ran into some. My images from Firebase are not showing up at all and I'm not sure what is the problem.
Adapter Class
class AbstractAdapter(private val mContext: Context, private val abstractList: ArrayList<Abstract>) : RecyclerView.Adapter<AbstractAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.abstract_image_view, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
Glide.with(mContext)
.load(abstractList[position].abstract)
.into(holder.imageView)
}
override fun getItemCount(): Int {
return abstractList.size
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var imageView: ImageView = itemView.findViewById(R.id.abstractImageView)
}
companion object {
private const val Tag = "RecyclerView"
}
}
Data class
class Abstract {
var abstract: String? = null
constructor() {}
constructor(abstract: String?) {
this.abstract = abstract
}
}
Fragment in which images will be shown
class AbstractWallpapers: Fragment(), PurchasesUpdatedListener {
private lateinit var subscribeAbstract: Button
private var billingClient: BillingClient? = null
lateinit var recyclerView: RecyclerView
lateinit var abstractlist: ArrayList<Abstract>
private var recyclerAdapterAbstract: AbstractAdapter? = null
private var myRef3: DatabaseReference? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_abstract_wallpaper, container, false)
recyclerView = requireView().findViewById(R.id.abstract_recyclerView)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView = view.findViewById(R.id.abstract_recyclerView)
val layoutManager = LinearLayoutManager(requireActivity())
recyclerView.layoutManager = layoutManager
recyclerView.setHasFixedSize(true)
myRef3 = FirebaseDatabase.getInstance().reference
abstractlist = ArrayList()
ClearAll()
GetDataFromFirebase()
subscribeAbstract = view.findViewById(R.id.abstract_subscribe_btn)
subscribeAbstract.setOnClickListener {
subscribeAbstract()
}
// Establish connection to billing client
//check subscription status from google play store cache
//to check if item is already Subscribed or subscription is not renewed and cancelled
billingClient = BillingClient.newBuilder(requireActivity()).enablePendingPurchases().setListener(this).build()
billingClient!!.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
val queryPurchase = billingClient!!.queryPurchases(BillingClient.SkuType.SUBS)
val queryPurchases = queryPurchase.purchasesList
if (queryPurchases != null && queryPurchases.size > 0) {
handlePurchases(queryPurchases)
} else {
saveSubscribeValueToPref(false)
}
}
}
override fun onBillingServiceDisconnected() {
Toast.makeText(requireActivity(), "Service Disconnected", Toast.LENGTH_SHORT).show()
}
})
//item subscribed
if (subscribeValueFromPref) {
subscribeAbstract.visibility = View.GONE
} else {
subscribeAbstract.visibility = View.VISIBLE
}
}
// Code related to Firebase
#SuppressLint("NotifyDataSetChanged")
private fun GetDataFromFirebase() {
val query: Query = myRef3!!.child("Abstract")
query.addListenerForSingleValueEvent(object : ValueEventListener {
#SuppressLint("NotifyDataSetChanged")
override fun onDataChange(snapshot: DataSnapshot) {
for (dataSnapshot: DataSnapshot in snapshot.children) {
val abstract = Abstract()
abstract.abstract = dataSnapshot.child("abstract").value.toString()
abstractlist.add(abstract)
}
recyclerAdapterAbstract = abstractlist.let { AbstractAdapter(requireActivity(), it) }
recyclerView.adapter = recyclerAdapterAbstract
recyclerAdapterAbstract!!.notifyDataSetChanged()
}
override fun onCancelled(error: DatabaseError) {}
})
if (recyclerAdapterAbstract != null) recyclerAdapterAbstract!!.notifyDataSetChanged()
}
private fun ClearAll() {
abstractlist.clear()
abstractlist = ArrayList()
}
I fixed my problem. It turns out my rules in Firebase Realtime Database rules for read were set to false instead. My code works perfect. It was only a stupid error on my part.

Clearing a RecyclerView when User makes a second request (using diffUtils and livedata)

I have made an app that uses an API to make a request and then shows the results in a RecyclerView.
I was following a tutorial and in it they used a differCallback and a liveData so the lists updates and such. However whenever the user makes a second search, the recyclerView should only show the new results but the previous results don't dissapear and the new results just appear below the previous search.
I have debugged it for quite some time now but I don't seem to understand where the list is made and where sure it be updated (or in this case cleared).
I tried using .clear() for the diff (Asynclistdiffer), creating a new list in the onBindViewHolder and then clearing that list every time the "search" is called but without any luck. As im still a beginner I don't have a clue on where or what is happening, all your helo will be greatly appreciated
this is my adapter:
class RecipePreviewAdapter : RecyclerView.Adapter<RecipePreviewAdapter.RecipePreviewViewHolder>() {
inner class RecipePreviewViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
private val differCallback = object : DiffUtil.ItemCallback<Recipe>() {
override fun areItemsTheSame(oldItem: Recipe, newItem: Recipe): Boolean {
return oldItem.sourceUrl == newItem.sourceUrl
}
override fun areContentsTheSame(oldItem: Recipe, newItem: Recipe): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this, differCallback)
lateinit var recipeList: MutableList<Recipe>
var isRecipeListInitialized = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecipePreviewViewHolder {
return RecipePreviewViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.item_recipe_preview,
parent,
false
)
)
}
override fun onBindViewHolder(holder: RecipePreviewViewHolder, position: Int) {
recipeList = differ.currentList.toMutableList()
isRecipeListInitialized = true
// Log.d(TAG, recipeList.toString())
val recipe = recipeList[position]
holder.itemView.apply {
Glide.with(this).load(recipe.image).into(ivRecipeImagePreview)
tvRecipeTitlePreview.text = recipe.title
tvTimeToMakeTVPreview.text = "${recipe.readyInMinutes} minutes"
tvSummaryPreview.text = Jsoup.parse(recipe.summary).text()
setOnClickListener {
onItemClickListener?.let { it(recipe) }
}
}
}
override fun getItemCount(): Int {
return differ.currentList.size
}
And this is where I call it:
class SearchRecipeFragment : Fragment(R.layout.fragment_search_recipe) {
lateinit var viewModel: RecipeViewModel
lateinit var recipeAdapter: RecipePreviewAdapter
val TAG = "SearchRecipeFragment"
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = (activity as RecipesActivity).viewModel
setupRecyclerView()
recipeAdapter.setOnItemClickListener {
val bundle = Bundle().apply {
putSerializable("recipe", it)
}
findNavController().navigate(
R.id.action_searchRecipeFragment_to_recipeFragment,
bundle
)
}
etSearch.setOnKeyListener(View.OnKeyListener { _, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN) {
if (etSearch.text.toString().isNotEmpty()) {
viewModel.searchRecipe(etSearch.text.toString())
}
return#OnKeyListener true
}
false
})
viewModel.searchRecipeLiveData.observe(viewLifecycleOwner, Observer { response ->
when (response) {
is Resource.Success -> {
hideProgressBar()
response.data?.let { recipeResponse ->
recipeAdapter.differ.submitList(recipeResponse.results.toList())
}
}
is Resource.Error -> {
hideProgressBar()
response.message?.let { message ->
Log.e(TAG, "An error occurred: $message")
Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG)
.show()
}
}
is Resource.Loading -> {
showProgressBar()
}
}
})
}
Ans this is the part of the ViewModel that I'm not really sure what it does
private fun handleSearchRecipeResponse(response: Response<SearchRecipeResponse>): Resource<SearchRecipeResponse> {
if (response.isSuccessful) {
response.body()?.let { resultResponse ->
searchRecipesPage++
if (searchRecipesResponse == null) {
searchRecipesResponse = resultResponse
} else {
val oldRecipes = searchRecipesResponse?.results
val newRecipes = resultResponse.results
oldRecipes?.addAll(newRecipes)
}
return Resource.Success(searchRecipesResponse ?: resultResponse)
}
}
return Resource.Error(response.message())
}
too late but it is because of "searchRecipesResponse". You have to set it to "null" and reset searchRecipesPage to 1 for each new search in etSearch.setOnKeyListener().

OnItem click not working properly after clicking on the item in Recyclerview

I have tried to implement search functionality in the recycler view.for that I have written below code in My "Main.kt" class
search functionality is working fine for me,
the issue is when I am searching the item from the list and clicking on that item I am getting the wrong position.
please help me with this issue.
adapter = DynamicListAdapter(dynamicList)
dynamic_list_recyclerview.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL,false) as RecyclerView.LayoutManager
dynamic_list_recyclerview.adapter = adapter
adapter!!.setRecyclerViewItemClickLister(this)
i have taken edit text and added the addTextChangedListener
edt_search_dynamic.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun afterTextChanged(editable: Editable?) {
filter(editable.toString())
}
})
fun filter(text : String){
var filteredList = mutableListOf<DynamicModel>()
for(list in dynamicList){
if(list.vehicleno.toLowerCase().contains(text.toLowerCase())){
filteredList.add(list)
}
}
adapter?.filterList(filteredList)
}
and this is my adapter class
class DynamicListAdapter (var dynamiclist : List<DynamicModel>) : RecyclerView.Adapter<DynamicListAdapter.DynamicViewHolder>() {
var recyclerViewOnItemClickListener : RecyclerViewOnItemClickListener? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DynamicViewHolder {
val inflatedView = LayoutInflater.from(parent.context)
.inflate(R.layout.singlerowdynamiclist,parent,false)
return DynamicViewHolder(inflatedView,dynamiclist)
}
override fun getItemCount(): Int {
return dynamiclist.size
}
override fun onBindViewHolder(holder: DynamicViewHolder, position: Int) {
holder.bindItem(dynamiclist[position])
}
inner class DynamicViewHolder(itemView : View, var dynamiclists : List<DynamicModel>) : RecyclerView.ViewHolder(itemView), View.OnClickListener
{
private var txtStatus : TextView? = null
init {
txtStatus = itemView.findViewById(R.id.txtStatus)
itemView.setOnClickListener(this)
}
fun bindItem(dynamiclist : DynamicModel){
txtStatus?.text = dynamiclist.vehiclestatus
}
override fun onClick(view: View?) {
when(view){
itemView -> if(recyclerViewOnItemClickListener!= null){
recyclerViewOnItemClickListener!!.onItemClick(adapterPosition,view)
}
}
}
}
// method of outer class
fun setRecyclerViewItemClickLister(onRecyclerviewItemClickListener : RecyclerViewOnItemClickListener){
this.recyclerViewOnItemClickListener = onRecyclerviewItemClickListener
}
// for filter the list
fun filterList(dymaniclist : List<DynamicModel>){
this.dynamiclist = dymaniclist
notifyDataSetChanged()
}
}
and this is the interface which I have implemented in my Main.kt class
interface RecyclerViewOnItemClickListener {
fun onItemClick(position : Int, view: View)
}
You won't get the desired position (the position from the unfiltered list) after applying your filters, because you lose that information when creating a new filtered list and putting it inside the DynamicListAdapter.
Let's say inside the adapter we have a list of the following items:
val dynamicList = listOf(
"#0 A", // 0th position
"#1 B", // 1st position
"#2 AB" // 2nd position
)
Now let's use your filter method:
filter("A")
This ends with replacing the old dynamicList inside the DynamicListAdapter with a completely new filteredList, which looks like this:
val filteredList = listOf(
"#0 A", // 0th position
"#2 AB", // 1st position
)
Now when clicking the #2 AB you will get position of value 1 (not desired 2) as it is the item's index in the new filteredList.
There are multiple ways of how to achieve what you want, but if you only want data from the clicked item, just return the object instead of its position on the item click:
interface RecyclerViewOnItemClickListener {
fun onItemClick(dynamicModel: DynamicModel, view: View)
}
// inside DynamicListAdapter
inner class DynamicViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindItem(dynamiclist : DynamicModel) {
with (itemView) {
txtStatus.text = dynamiclist.vehiclestatus
setOnClickListener {
recyclerViewOnItemClickListener?.onItemClick(dynamiclist, this)
}
}
}
}
However if you need to return the position and the above is not an option, I would suggest leaving the original list in the adapter and letting it handle filtering by itself, for example:
// _dynamicList is always the original list
class DynamicListAdapter (private val _dynamicList: List<DynamicModel>) : RecyclerView.Adapter<DynamicListAdapter.DynamicViewHolder>() {
var recyclerViewOnItemClickListener : RecyclerViewOnItemClickListener? = null
var filterText: String = ""
set(value) {
field = value
notifyDataSetChanged()
}
// return original list (_dynamicList) if no filter should be applied or return the filtered list based on the filterText
private val dynamicList: List<DynamicModel>
get() = if (filterText.isBlank()) _dynamicList
else _dynamicList.filter { it.vehicleno.contains(filterText, ignoreCase = true) }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DynamicViewHolder {
val inflatedView = LayoutInflater.from(parent.context).inflate(R.layout.singlerowdynamiclist,parent,false)
return DynamicViewHolder(inflatedView)
}
override fun getItemCount(): Int {
return dynamicList.size
}
override fun onBindViewHolder(holder: DynamicViewHolder, position: Int) {
holder.bindItem(dynamicList[position])
}
inner class DynamicViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindItem(dynamicModel: DynamicModel) {
with (itemView) {
txtStatus.text = dynamicModel.vehiclestatus
// get the item's original position (before filtering)
val position = _dynamicList.indexOf(dynamicModel)
setOnClickListener {
recyclerViewOnItemClickListener?.onItemClick(position, this)
}
}
}
}
}
// filter method
fun filter(text: String){
adapter?.filterText = text
}
I put my solution it might help somebody.
Given: recyclerView is working fine.
Problem: on item click is not working after implementing searchview.
solution: add mAdapter.setOnItemClickListener again inside onQueryTextChange as below:
#Override
public boolean onQueryTextChange(String newText) {
mAdapter = new MyAdapter(getApplicationContext(), OtherInofYouWantToPass);
recyclerView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {
#Override
public void onItemClick(View view, MyObj obj, int position) {
{ add your work here}
}
});
return false;
}

Getting Unresolved Reference from Singleton Class

I am working with android studio and in Kotlin. I am working with a Singleton class so my confusion is that my getInstance function is not being called when I am trying to add that into my setupRecyclerView function and it keeps saying it is an unresolved reference. I also have the issue that my NewsListActivity.SimpleItemRecyclerViewAdapter also keeps getting an unresolved reference when I try to reference it. Any help would be greatly appreciated.
package edu.uw.amjadz.material_news
import android.content.Context
import android.graphics.Bitmap
import android.util.LruCache
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.toolbox.ImageLoader
import com.android.volley.toolbox.Volley
class Singleton private constructor(context: Context){
private var INSTANCE: edu.uw.amjadz.material_news.Singleton? = null
fun getInstance(context: Context): edu.uw.amjadz.material_news.Singleton {
if(INSTANCE == null){
INSTANCE = Singleton(context)
}
return INSTANCE as edu.uw.amjadz.material_news.Singleton
}
val requestQueue: RequestQueue by lazy {
Volley.newRequestQueue(context.applicationContext)
}
val imageLoader: ImageLoader by lazy {
ImageLoader(requestQueue,
object : ImageLoader.ImageCache{
private val cache = LruCache<String, Bitmap>(20)
override fun getBitmap(url: String?): Bitmap {
return cache.get(url)
}
override fun putBitmap(url: String?, bitmap: Bitmap?) {
cache.put(url, bitmap)
}
}
)
}
fun <T> add(req: Request<T>){
requestQueue.add(req)
}
}
private fun setupRecyclerView(recyclerView: RecyclerView) {
recyclerView.setAdapter(null)
val key = getString(R.string.NEWS_API_KEY)
val url = "https://newsapi.org/v2/everything?q=bitcoin&from=2018-10-01&sortBy=publishedAt&apiKey=$key"
val jsonObjectRequest = JsonObjectRequest(
Request.Method.GET, url, null,
Response.Listener { response ->
recyclerView.adapter = NewsListActivity.SimpleItemRecyclerViewAdapter(this, DummyContent.parseData(response.toString()), twoPane)
},
Response.ErrorListener { error ->
}
)
Singleton.getInstance(this).add(jsonObjectRequest)
if (twoPane){
recyclerView.layoutManager = LinearLayoutManager(this)
} else {
recyclerView.layoutManager = GridLayoutManager(this, 2)
}
}
}
class SimpleItemRecyclerViewAdapter(
private val parentActivity: NewsListActivity,
private val values: List<DummyContent.DummyItem>,
private val twoPane: Boolean
) :
RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder>() {
private val onClickListener: View.OnClickListener
init {
onClickListener = View.OnClickListener { v ->
val item = v.tag as DummyContent.DummyItem
if (twoPane) {
val fragment = NewsDetailFragment().apply {
arguments = Bundle().apply {
putString(NewsDetailFragment.ARG_ITEM_ID, item.id)
}
}
parentActivity.supportFragmentManager
.beginTransaction()
.replace(R.id.news_detail_container, fragment)
.commit()
} else {
val intent = Intent(v.context, NewsDetailActivity::class.java).apply {
putExtra(NewsDetailFragment.ARG_ITEM_ID, item.id)
}
v.context.startActivity(intent)
}
}
}

Resources