Change API param based on Dialog Fragment input with MVVM in Kotlin - kotlin

i'm a beginner in android & kotlin and i'm having an issue i been trying to figure out all day...
I have an app that fetches data from NewsApi and displays it in a recycler view , i am using Retrofit library and Room (to save favorite articles) with MVVM architecture. I want to add an option so that the user can select the country of the news from a dialog that pops up by clicking on a icon on the toolbar menu.
I have created a custom DialogFragment and have it show up, the dialog contains a spinner with a list of countries and i'm using FragmentResult and FragmentResultListener to pass the country value between dialog fragment and news fragment.
DialogFragment
class CountrySelectDialog : DialogFragment(R.layout.country_selection_dialog) {
private lateinit var binding: CountrySelectionDialogBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = CountrySelectionDialogBinding.bind(view)
binding.spCountrySelection.onItemSelectedListener =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
adapterView: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
Toast.makeText(
context,
"you selected ${adapterView?.getItemAtPosition(position).toString()}",
Toast.LENGTH_SHORT
).show()
}
override fun onNothingSelected(adapterView: AdapterView<*>?) {
}
}
binding.btnCancel.setOnClickListener {
this.dismiss()
}
binding.btnConfirm.setOnClickListener {
val result = binding.spCountrySelection.selectedItem.toString()
setFragmentResult("countryCode", bundleOf("bundleKey" to result))
this.dismiss()
}
}
}
The news Fragment is observing data from the View Model
class BreakingNewsFragment : Fragment(R.layout.fragment_breaking_news) {
lateinit var viewModel: NewsViewModel
lateinit var newsAdapter: NewsAdapter
private lateinit var binding: FragmentBreakingNewsBinding
val TAG = "BreakingNewsFragment"
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentBreakingNewsBinding.bind(view)
viewModel = (activity as NewsActivity).viewModel
setUpRecyclerView()
setFragmentResultListener("countryCode") { countryCode, bundle ->
val result = bundle.getString("countryCode")
viewModel.countryCode = result!!}
viewModel.breakingNews.observe(viewLifecycleOwner, Observer {
when (it) {
is Resource.Success -> {
hideProgressBar()
it.data?.let {
newsAdapter.differ.submitList(it.articles.toList())
val totalPages = it.totalResults / QUERY_PAGE_SIZE + 2
isLastPage = viewModel.breakingNewsPage == totalPages
}
}
is Resource.Error -> {
hideProgressBar()
it.message?.let {
Log.e(TAG, "An error occurred: $it")
}
}
is Resource.Loading -> {
showProgressBar()
}
}
})
newsAdapter.setOnItemClickListener {
val bundle = Bundle().apply {
putSerializable("article", it)
}
findNavController().navigate(
R.id.action_breakingNewsFragment_to_articleFragment, bundle
)
}
}
ViewModel:
class NewsViewModel(val newsRepository: NewsRepository, val app: Application) : AndroidViewModel(app) {
val breakingNews: MutableLiveData<Resource<NewsResponse>> = MutableLiveData()
var breakingNewsPage = 1
var breakingNewsResponse: NewsResponse? = null
val searchNews: MutableLiveData<Resource<NewsResponse>> = MutableLiveData()
var searchNewsPage = 1
var searchNewsResponse: NewsResponse? = null
var countryCode :String = "it"
init {
getBreakingNews(countryCode)
}
fun getBreakingNews(countryCode: String) {
viewModelScope.launch {
breakingNews.postValue(Resource.Loading())
val response = newsRepository.getBreakingNews(countryCode, breakingNewsPage)
breakingNews.postValue(handleBreakingNewsResponse(response))
}
}
fun handleBreakingNewsResponse(response: Response<NewsResponse>): Resource<NewsResponse> {
if (response.isSuccessful) {
response.body()?.let { resultResponse ->
breakingNewsPage++
if (breakingNewsResponse == null) {
breakingNewsResponse = resultResponse
} else {
val oldArticles = breakingNewsResponse?.articles
val newArticles = resultResponse.articles
oldArticles?.addAll(newArticles)
}
return Resource.Success(breakingNewsResponse ?: resultResponse)
}
}
return Resource.Error(response.message())
}
fun searchNews(searchQuery: String) {
viewModelScope.launch {
searchNews.postValue(Resource.Loading())
val response = newsRepository.searchNews(searchQuery, searchNewsPage)
searchNews.postValue((handleSearchNewsResponse(response)))
}
}
fun handleSearchNewsResponse(response: Response<NewsResponse>): Resource<NewsResponse> {
if (response.isSuccessful) {
response.body()?.let { resultResponse ->
searchNewsPage++
if (searchNewsResponse == null) {
searchNewsResponse = resultResponse
} else {
val oldArticles = searchNewsResponse?.articles
val newArticles = resultResponse.articles
oldArticles?.addAll(newArticles)
}
return Resource.Success(searchNewsResponse ?: resultResponse)
}
}
return Resource.Error(response.message())
}
}
When i click on the icon on the toolbar menu the dialog appears and works fine but i can't seem to find a way to have the recycler view update with new data using given value for country
I searched everywhere and couldn't find a solution (or probably didn't understand it :S) can someone guide me into the right direction? I'm so lost...
When I click on the icon on the toolbar menu the dialog appears and works fine but I can't seem to find a way to have the recycler view update with new data using given value for country.

Related

Observing live data from an API is not updating ui when data changes

I am trying to develop a football app demo. Data comes from an API from the api
It loads data as expected when app started, but when score of match changes, ui is not updating for scores by itself. I am using DiffUtil getChangePayload() to detect changes in score and status fields of Match objects which comes from the response. But it is not triggering when live match data changes. What am i missing?
P.S. I put layout in SwipeRefreshLayout and when i refresh, it gets scores and update the ui. But i want to see the match status and scores updating by itself.
Here is my code:
class MatchesViewModel(
app: Application,
private val repository: MatchesRepository
): AndroidViewModel(app) {
val matchesToday: MutableLiveData<List<Matche>> = MutableLiveData()
init {
getMatchesToday()
}
fun getMatchesToday() = viewModelScope.launch {
safeMatchesToday()
}
private suspend fun safeMatchesToday() {
if (Constants.checkConnection(this)) {
val response = repository.getMatchesToday()
if (response.isSuccessful) {
response.body()?.let {
matchesToday.postValue(it.matches)
}
}
}
}
}
class MatchesTodayFragment : Fragment() {
private var _binding: FragmentMatchesTodayBinding? =null
private val binding get() = _binding!!
private lateinit var mMatchesAdapter: MatchesAdapter
private val viewModel: MatchesViewModel by viewModels {
MatchesViewModelFactory(requireActivity().application, (requireActivity().application as MatchesApplication).repository)
}
#RequiresApi(Build.VERSION_CODES.N)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupRecyclerView()
viewModel.matchesToday.observe(viewLifecycleOwner) { matches ->
mMatchesAdapter.differ.submitList(matches)
}
binding.srlMatchesToday.setOnRefreshListener {
viewModel.getMatchesToday()
binding.srlMatchesToday.isRefreshing = false
}
}
}
class MatchesAdapter(val fragment: Fragment): RecyclerView.Adapter<MatchesAdapter.ViewHolder>() {
private val differCallback = object: DiffUtil.ItemCallback<Matche>() {
override fun areItemsTheSame(oldItem: Matche, newItem: Matche): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Matche, newItem: Matche): Boolean {
return oldItem.status == newItem.status &&
oldItem.score.fullTime.home == newItem.score.fullTime.home &&
oldItem.score.fullTime.away == newItem.score.fullTime.away &&
oldItem == newItem
}
override fun getChangePayload(oldItem: Matche, newItem: Matche): Any? {
val bundle: Bundle = bundleOf()
if (oldItem.status != newItem.status) {
bundle.apply {
putString(Constants.MATCH_STATUS, newItem.status)
}
}
if (oldItem.score.fullTime.home != newItem.score.fullTime.home) {
bundle.apply {
putInt(Constants.HOME_SCORE, newItem.score.fullTime.home)
}
}
if (oldItem.score.fullTime.away != newItem.score.fullTime.away) {
bundle.apply {
putInt(Constants.AWAY_SCORE, newItem.score.fullTime.away)
}
}
if (bundle.size() == 0) {
return null
}
return bundle
}
}
val differ = AsyncListDiffer(this, differCallback)
#SuppressLint("UseCompatLoadingForDrawables")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val match = differ.currentList[position]
holder.apply {
Glide.with(fragment)
.load(match.homeTeam.crest)
.placeholder(fragment.resources.getDrawable(R.drawable.ic_ball))
.into(ivHomeTeamImage)
Glide.with(fragment)
.load(match.awayTeam.crest)
.placeholder(fragment.resources.getDrawable(R.drawable.ic_ball))
.into(ivAwayTeamImage)
tvHomeTeamName.text = match.homeTeam.name
tvAwayTeamName.text = match.awayTeam.name
when (match.status) {
Constants.TIMED -> {
tvMatchTime.text = Constants.toTimeForTR(match.utcDate)
tvHomeTeamScore.text = "-"
tvAwayTeamScore.text = "-"
}
Constants.PAUSED -> {
tvMatchTime.text = Constants.FIRST_HALF
tvHomeTeamScore.text = match.score.fullTime.home.toString()
tvAwayTeamScore.text = match.score.fullTime.away.toString()
}
Constants.FINISHED -> {
tvMatchTime.text = Constants.FINISHED
tvHomeTeamScore.text = match.score.fullTime.home.toString()
tvAwayTeamScore.text = match.score.fullTime.away.toString()
}
else -> {
tvMatchTime.text = Constants.IN_PLAY
tvHomeTeamScore.text = match.score.fullTime.home.toString()
tvAwayTeamScore.text = match.score.fullTime.away.toString()
}
}
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
if (payloads.isNotEmpty()) {
val item = payloads[0] as Bundle
val status = item.getString(Constants.MATCH_STATUS)
val homeScore = item.getInt(Constants.HOME_SCORE)
val awayScore = item.getInt(Constants.AWAY_SCORE)
holder.apply {
tvMatchTime.text = status
tvHomeTeamScore.text = homeScore.toString()
tvAwayTeamScore.text = awayScore.toString()
Log.e("fuck", status.toString())
}
}
super.onBindViewHolder(holder, position, payloads)
}
override fun getItemCount(): Int {
return differ.currentList.size
}
}
LiveData only pushes new values if you command it to. Since you want to do it repeatedly, you need to create a loop. This is very easy to do using the liveData coroutine builder.
class MatchesViewModel(
app: Application,
private val repository: MatchesRepository
): AndroidViewModel(app) {
val matchesToday = liveData {
while (true) {
if (Constants.checkConnection(this)) {
val response = repository.getMatchesToday()
if (response.isSuccessful) {
response.body()?.let {
emit(it.matches)
}
}
}
delay(5000) // however many ms you want between fetches
}
}
}
If this is a Retrofit response, I think checking isSuccessful is redundant because body() will be non-null if and only if isSuccessful is true. So it could be simplified a bit from what you have:
class MatchesViewModel(
app: Application,
private val repository: MatchesRepository
): AndroidViewModel(app) {
val matchesToday = liveData {
while (true) {
if (Constants.checkConnection(this)) {
repository.getMatchesToday()?.body()?.matches?.let(::emit)
}
delay(5000) // however many ms you want between fetches
}
}
}

How to show rewardedInterstitial ad which was loaded in mainActivity in a compose?

I try to load rewarded interestitial ad in Mainactivity and then show it in one composable screen in jetpack compose. I loaded it successfully but in my RewardedShow compose screen rewardedInterstitialAd is null? I used my code from https://developers.google.com/admob/android/rewarded-interstitial
This is my code in MainActivity
class MainActivity : ComponentActivity(){
var rewardedInterstitialAd: RewardedInterstitialAd? = null
private var TAG = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyBeautyAppInJetpackComposeTheme {
MyNavGraph()
MobileAds.initialize(this) {
loadAd()
}
}
}
}
private fun loadAd() {
RewardedInterstitialAd.load(this, "ca-app-pub-
3940256099942544/5354046379",
AdRequest.Builder().build(), object :
RewardedInterstitialAdLoadCallback() {
override fun onAdLoaded(ad: RewardedInterstitialAd) {
Log.d(TAG, "Ad was loaded.")
rewardedInterstitialAd = ad
}
override fun onAdFailedToLoad(adError: LoadAdError) {
Log.d(TAG, adError?.toString())
rewardedInterstitialAd = null
}
})
}
}
and this the RewardedShowCompose screen
#SuppressLint("UnrememberedMutableState")
#Composable
fun RewardedShowCompose( actions: MainActions, maskArg: String) {
val context = LocalContext.current
val loading = mutableStateOf(true)
Surface(modifier = Modifier.fillMaxSize())
{
if (MainActivity.rewardedInterstitialAd != null){
MainActivity.rewardedInterstitialAd?.show(context as Activity, OnUserEarnedRewardListener { actions.gotoFinalShow.invoke(maskArg) })
}
}
}
I made rewardedInterstitialAd Companion and now it works well. like this
companion object {
var rewardedInterstitialAd: RewardedInterstitialAd? = null
}

cant navigate to other fragment from webview

im trying to navigate from webview to fragment using navController, but it seems not working.
here is my code
class LandingPageCreditCardFragment : Fragment(R.layout.fragment_landing_page_credit_card) {
private val binding by viewBinding(FragmentLandingPageCreditCardBinding::bind)
lateinit var navController: NavController
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
navController = view.findNavController()
Log.i("link url", arguments?.getString("url").toString())
showWebViewContent(requireArguments().getString("url")!!)
}
private fun showWebViewContent(url: String) {
binding.webViewCreditCard.settings.javaScriptEnabled = true
binding.webViewCreditCard.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
if (url != null) {
view?.loadUrl(url)
}
return true
}
}
binding.webViewCreditCard.addJavascriptInterface(object : Any() {
#JavascriptInterface
fun valid() {
Toast.makeText(requireContext(), "test", Toast.LENGTH_SHORT).show()
val builder = AlertDialog.Builder(requireContext())
builder.setTitle("Konfirmasi")
builder.setMessage("navigasi ke pesanan")
builder.setPositiveButton("Ya") { dialog, which ->
navController.navigate(R.id.action_landingPageCreditCardFragment_to_pesananFragment)
dialog.dismiss()
}
builder.setNegativeButton("Tidak") { dialog, which ->
dialog.dismiss()
}
builder.show() }
}, "btn")
binding.webViewCreditCard.loadUrl(url)
} }
im referrring to this answer to get my function working
i try to show toast, its working
then im try to show alertDialog contain button to navigate from webview to next fragment, when i click it, my app crash.
any help appreciated
after much debugging, i found the answer.
call the navController in runOnUiThread wrapped on Thread and Handler
binding.webViewCreditCard.addJavascriptInterface(object : Any() {
#JavascriptInterface
fun valid() {
val handler = Handler(Looper.getMainLooper())
handler.post(Thread {
(activity as MainActivity).runOnUiThread {
navController.navigate(R.id.action_landingPageCreditCardFragment_to_pesananFragment)
}
})
}
}, "btn")

how to save and retrieve application info to shared preference in kotlin?

I want to hide app icon from grid view and save it.
I can save application info to shared preferences as mutable set string and get it but cant convert string to application info and show in my grid view
my app activity
private var applist: List<ApplicationInfo>? = null
private var listadaptor: ApplicationAdapter? = null
private var grid: GridView? = null
private var mSelected: ArrayList<Any> = ArrayList()
var context: Activity = this
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_apps)
val packageManager = getPackageManager()
LoadApplications().execute()
grid = findViewById<View>(R.id.grid) as GridView
grid!!.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE)
grid!!.adapter = listadaptor
grid!!.onItemClickListener = AdapterView.OnItemClickListener { parent: AdapterView<*>?, view: View?, position: Int, id: Long ->
val app = applist!![position]
try {
val intent = packageManager.getLaunchIntentForPackage(app.packageName)
intent?.let { startActivity(it) }
} catch (e: Exception) {
Toast.makeText(this#appsActivity, e.message, Toast.LENGTH_LONG).show()
}
}
grid!!.onItemLongClickListener = AdapterView.OnItemLongClickListener { parent, view, position, id ->
val position1: String = (position).toString()
if (mSelected.contains(position1)) {
mSelected.remove(position1)
view.setBackgroundColor(Color.TRANSPARENT) // remove item from list
// update view (v) state here
// eg: remove highlight
} else {
mSelected.add(position1)
view.setBackgroundColor(Color.LTGRAY) // add item to list
// update view (v) state here
// eg: add highlight
}
button3.setOnClickListener(
object : View.OnClickListener {
override fun onClick(view: View?) {
val builder1: AlertDialog.Builder = AlertDialog.Builder(this#appsActivity)
builder1.setMessage("Are you sure you want to delete it ?")
builder1.setCancelable(true)
builder1.setPositiveButton(
"Yes",
DialogInterface.OnClickListener { dialog, id ->
deleteSelectedItems()
mSelected.remove(position)
listadaptor!!.notifyDataSetChanged()
val app = applist!![position]
listadaptor!!.remove(app)
})
builder1.setNegativeButton(
"No",
DialogInterface.OnClickListener { dialog, id -> dialog.cancel() })
val alert11: AlertDialog = builder1.create()
alert11.show()
}
})
true
}
}
private fun deleteSelectedItems() {
val checked: SparseBooleanArray = grid!!.getCheckedItemPositions()
if (checked != null) {
val list: List<Any> = mSelected
for (i in 0 until checked.size()) {
if (checked.valueAt(i)) {
mSelected.remove(checked.keyAt(i))
}
}
}
}
private fun checkForLaunchIntent(list: List<ApplicationInfo>): List<ApplicationInfo> {
val applist = ArrayList<ApplicationInfo>()
for (info in list) {
try {
if (null != packageManager!!.getLaunchIntentForPackage(info.packageName)) {
applist.add(info)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
Collections.sort(applist, ApplicationInfo.DisplayNameComparator(packageManager))
return applist
}
#SuppressLint("StaticFieldLeak")
private inner class LoadApplications : AsyncTask<Void?, Void?, Void?>() {
override fun doInBackground(vararg params: Void?): Void? {
applist = checkForLaunchIntent(packageManager!!.getInstalledApplications(
PackageManager.GET_META_DATA))
listadaptor = ApplicationAdapter(this#appsActivity,
R.layout.grid_item, applist!!)
return null
}
override fun onPostExecute(result: Void?) {
grid!!.adapter = listadaptor
super.onPostExecute(result)
}
}
items are deleted, but after re-running the application, all installed apps will be restored in gridview
You can look into my open source project LibTron which has one module library for SharedPref written in Kotlin.
To use the library follow the instruction in Project ReadMe
Example to use the library:
val applicationInfo: ApplicationInfo = sharedprefrence.Object(name = "sharedprefKey", defaultValue = null)
Or in case you want to use it without the help of the you can use GSON, Moshi, Jackson type libraries to convert to/from string to your ApplicationInfo class while saving or reading from the Sharedprefrence

How to get the selected item from ListView in Kotlin?

Code Sample:
package tech.kapoor.listviewdemo
import android.content.Context
import android.graphics.Color
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ListView
import android.widget.TextView
import android.widget.AdapterView
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val listView = findViewById<ListView>(R.id.main_listview)
var redColor = Color.parseColor("#FF0000")
listView.setBackgroundColor(redColor)
listView.adapter = CustomAdapter(this)
}
private class CustomAdapter(context: Context): BaseAdapter() {
private val mContext: Context
init {
mContext = context
}
override fun getCount(): Int {
return 80
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItem(position: Int): Any {
return position
}
override fun getView(position: Int, view: View?, viewGroup: ViewGroup?): View {
val textView = TextView(mContext)
textView.text = "Here comes the !!"
return textView
}
}
}
I'm trying to understand list view instead of recycler view to understand basics first.
Anybody knows how we get the selected row id/index value on selection or onclick and also how to perform some action on selection of a specific row in kotlin?
To populate listview you must have dataset. Dataset may be any list of either datatypes like Strings or you can use list of model class. Something like this:
This is my simple list of dataset which I will use in ListView:
val data = ArrayList<TopicDTO>()
data.add(TopicDTO("1", "Info 1", true))
data.add(TopicDTO("2", "Info 2", false))
data.add(TopicDTO("3", "Info 3", true))
data.add(TopicDTO("4", "Info 4", false))
I have created one model class named TopicDTO which contains id,title and its status.
Now let's populate this into ListView:
list.adapter = ButtonListAdapter(baseContext, data)
Here is a simple adapter:
class ButtonListAdapter(//Class for rendering each ListItem
private val context: Context, private val rowItems: List<TopicDTO>) : BaseAdapter() {
override fun getCount(): Int {
return rowItems.size
}
override fun getItem(position: Int): Any {
return rowItems[position]
}
override fun getItemId(position: Int): Long {
return rowItems.indexOf(getItem(position)).toLong()
}
private inner class ViewHolder {
internal var main_text: TextView? = null //Display Name
internal var subtitle: TextView? = null //Display Description
internal var can_view_you_online: Button? = null //Button to set and display status of CanViewYouOnline flag of the class
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var convertView = convertView
var holder: ViewHolder? = null
val mInflater = context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE) as LayoutInflater
holder = ViewHolder()
if (convertView == null) {
convertView = mInflater.inflate(R.layout.main_lp_view_item, null)
holder.main_text = convertView!!.findViewById(R.id.main_lp_text) as TextView
holder.subtitle = convertView.findViewById(R.id.main_lp_subtitle) as TextView
holder.can_view_you_online = convertView.findViewById(R.id.can_view_you_online) as Button
convertView.tag = holder
} else {
holder = convertView.tag as ViewHolder
}
val rowItem = rowItems[position]
val main_text: String
val subtitle: String
holder.main_text!!.text = rowItem.info
holder.subtitle!!.text = rowItem.info
if (rowItem.canViewYouOnline) {
holder.can_view_you_online!!.setBackgroundColor(context.resources.getColor(R.color.colorPrimary))
} else {
holder.can_view_you_online!!.setBackgroundColor(context.resources.getColor(R.color.colorAccent))
}
holder.can_view_you_online!!.setOnClickListener(object : View.OnClickListener {
internal var buttonClickFlag: Boolean = false
override fun onClick(v: View) { //The Onclick function allows one to click the button on the list item and set/reset the canViewYouOnline flag. It is working fine.
}
})
return convertView
}
}
Now you can get your selected item like this:
list.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
// This is your listview's selected item
val item = parent.getItemAtPosition(position) as TopicDTO
}
Hope you understands this.
You can use inside the getView() method something like:
view.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
//use getItem(position) to get the item
}
})
or using the lambda:
view.setOnClickListener({ v -> //use theItem(position) })
Just a tip:
I'm trying to understand list view instead of recycler view to understand basics first.
In my opinion in your projects you will use RecyclerView in 99% of the cases.
add OnItemClickListener in you oncreate()
listView.setOnItemClickListener{ parent, view, position, id ->
Toast.makeText(this, "You Clicked:"+" "+position,Toast.LENGTH_SHORT).show()
}
Add the array of Items in your CustomAdapter class.
class CustomAdptor(private val context: Activity): BaseAdapter() {
//Array of fruits names
var names = arrayOf("Apple", "Strawberry", "Pomegranates", "Oranges", "Watermelon", "Bananas", "Kiwi", "Tomato", "Grapes")
//Array of fruits desc
var desc = arrayOf("Malus Domestica", "Fragaria Ananassa ", "Punica Granatum", "Citrus Sinensis", "Citrullus Vulgaris", "Musa Acuminata", "Actinidia Deliciosa", "Solanum Lycopersicum", "Vitis vinifera")
//Array of fruits images
var image = intArrayOf(R.drawable.apple, R.drawable.strawberry, R.drawable.pomegranates, R.drawable.oranges, R.drawable.watermelon, R.drawable.banana, R.drawable.kiwi, R.drawable.tomato, R.drawable.grapes)
override fun getView(p0: Int, p1: View?, p2: ViewGroup?): View {
val inflater = context.layoutInflater
val view1 = inflater.inflate(R.layout.row_data,null)
val fimage = view1.findViewById(R.id.fimageView)
var fName = view1.findViewById(R.id.fName)
var fDesc = view1.findViewById(R.id.fDesc)
fimage.setImageResource(image[p0])
fName.setText(names[p0])
fDesc.setText(desc[p0])
return view1
}
override fun getItem(p0: Int): Any {
return image[p0]
}
override fun getItemId(p0: Int): Long {
return p0.toLong()
}
override fun getCount(): Int {
return image.size
}
}
You can find the whole tutorial at: listview with onItemClickListener using kotlin