I'm trying to implement viewpager when press of a button on secondary activity for that I created a PageAdaper class which extends Recycler view.Adapter .I got viewpager must not be null error on runtime .
PageAdaper.kt
open class PageAdapter(context: Context, arrayList: ArrayList<Uri>) : RecyclerView.Adapter<PageAdapter.MyViewHolder>() {
private var mContext: Context? =null
private var galleryUri= arrayListOf<Uri>()
private var layoutInflater: LayoutInflater? =null
init {
this.mContext=context
this.galleryUri=arrayList
this.layoutInflater=context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
}
private fun onBindViewHolderr(holder: MyViewHolder, position: Int) {
holder.iView.setImageURI(galleryUri[position])
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view=LayoutInflater.from(mContext).inflate(R.layout.image_container,parent,false)
return MyViewHolder(view)
}
override fun getItemCount(): Int {
return galleryUri.size
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val iView: ImageView
init {
super.itemView
iView=itemView.findViewById(R.id.imageContainer)
}
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
onBindViewHolderr(holder, position)
}
}
Image_container.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/imageContainer"
android:contentDescription="#string/gallery" />
</LinearLayout>
Activity_gallery.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageButton
android:id="#+id/galleryBack"
android:layout_width="59dp"
android:layout_height="56dp"
android:background="#android:color/transparent"
android:contentDescription="#string/back_button"
android:src="#drawable/ic_baseline_arrow_back_24"
style="#style/Widget.AppCompat.Button.Colored"
app:layout_constraintHorizontal_bias="0.05"
app:layout_constraintVertical_bias="0.05"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/viewPager"
android:layout_width="409dp"
android:layout_height="729dp"
android:background="#android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</androidx.viewpager2.widget.ViewPager2>
</androidx.constraintlayout.widget.ConstraintLayout>
Creation on viewpager on button click from activity_main
gallery.setOnClickListener { // gallery button reference
if (lastImageUri!=null){
val intent= Intent(this,GalleryActivity::class.java)
startActivity(intent) // inflates activity_gallery.xml
val iAdapter=PageAdapter(this,galleryUri) // creating object with params
viewPager.adapter=iAdapter // here comes the error
}
}
Update
GalleryActivity.kt
It contains only setContentview to activity_gallery.xml
Do I need to add anything.
class GalleryActivity : AppCompatActivity() {
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_gallery)
overridePendingTransition(android.R.anim.slide_in_left,android.R.anim.slide_out_right)
galleryBack.setOnClickListener {
finish()
overridePendingTransition(android.R.anim.slide_in_left,android.R.anim.slide_out_right)
}
}
}
Explain me about this as I'm new to android. Thank you!
So, startActivity will go to the GalleryActivity class. You need to put the lines after that into the GalleryActivity.
Okay, now that you've added your GalleryActivity.kt. You need to make 2 changes. First, in your activity_main:
gallery.setOnClickListener { // gallery button reference
if (lastImageUri!=null){
val intent= Intent(this,GalleryActivity::class.java)
intent.putExtra("IMAGE_URI", galleryUri)
startActivity(intent) // inflates activity_gallery.xml
}
}
Then, in your GalleryActivity.kt
class GalleryActivity : AppCompatActivity() {
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_gallery)
val galleryUri = getIntent().getStringExtra("GALLERY_URI")
val iAdapter=PageAdapter(this,galleryUri) // creating object with params
viewPager.adapter=iAdapter
overridePendingTransition(android.R.anim.slide_in_left,android.R.anim.slide_out_right)
galleryBack.setOnClickListener {
finish()
overridePendingTransition(android.R.anim.slide_in_left,android.R.anim.slide_out_right)
}
}
}
Try that.
Related
I'm using Kotlin to create an event that generates a toast message on click of a recyclerview. I run into trouble making a Tost message in a recyclerview event.
I tried the following page, but couldn't solve it.
Toast message is not working in Recycler View
error code is
in kotlin & None of the following functions can be called with the arguments supplied: public open fun makeText(p0: Context!, p1: CharSequence!, p2: Int): Toast! defined in android.widget.Toast public open fun makeText(p0: Context!, p1: Int, p2: Int): Toast! defined in android.widget.Toast
PrintActivity.kt
package com.questionbank
class PrintActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val vBinding = ActivityPrintBinding.inflate(layoutInflater)
setContentView(vBinding.root)
val helper = SqliteHelper(this, "myDB.sql", 1)
var recyclerViewAdapter = CustomAdapter()
recyclerViewAdapter.listData = helper.select()
vBinding.myRecyclerView.adapter = recyclerViewAdapter
vBinding.myRecyclerView.layoutManager = LinearLayoutManager(this)
vBinding.myRecyclerView.addItemDecoration(
DividerItemDecoration(this, DividerItemDecoration.VERTICAL)
)
}
class CustomAdapter : RecyclerView.Adapter<CustomAdapter.Holder>() {
var listData = ArrayList<questionType>()
inner class Holder(val vBinding: QuestionLayoutRecyclerBinding) :
RecyclerView.ViewHolder(vBinding.root) {
fun setData(id:Int?, question: String, answer: String, exp: String) {
vBinding.printId.text=id.toString()
vBinding.myLinear.setOnClickListener {
// error occur
Toast.makeText(this#PrintActivity, "test", Toast.LENGTH_SHORT).show()
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val vBinding = QuestionLayoutRecyclerBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return Holder(vBinding)
}
override fun onBindViewHolder(holder: Holder, position: Int) {
val question = listData[position]
holder.setData(question.id, question.question, question.answer, question.exp)
}
override fun getItemCount(): Int {
return listData.size
}
}
}
activity_print
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PrintActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/myRecyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="32dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="32dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
question_layout_recycler.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/myLinear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="#+id/printId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
Two ways to fix,
Make CustomAdapter class as inner class.
innner class CustomAdapter : RecyclerView.Adapter<CustomAdapter.Holder>() {
So toast function it will take constant from activity class.
In viewholder, get context from view. it.context will get context from linearlayout.
vBinding.myLinear.setOnClickListener {
Toast.makeText(it.context, "test", Toast.LENGTH_SHORT).show()
}
Its recommended to place adapter logic in separate file and use second solution.
So you dont need to make adapter as inner class.
[enter image description here][1]
[enter image description here][2]VHFV.png
strong text
[2]: https://i.stack.imgur.com/YJOpm.png
activity_main
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#170628"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_images"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
image_layout.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.cardview.widget.CardView
android:layout_width="100dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_margin="5dp"
app:cardCornerRadius="10dp"
android:layout_height="100dp">
<ImageView
android:id="#+id/big_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="#drawable/zone_images" />
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var zoneBinding: ActivityMainBinding
var image = ArrayList<String>()
lateinit var zoneAdapter:ZoneImagesAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
zoneBinding= DataBindingUtil.setContentView(this,R.layout.activity_main)
buildData()
setRecyclerView()
}
private fun buildData() {
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQzx__blVU5FWJAUCU4d9-E095_n3Fgy1tuxA&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQh90iDDn5BoUnZqANXUszd17_Q-RhfRo8V6Q&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQzx__blVU5FWJAUCU4d9-E095_n3Fgy1tuxA&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQh90iDDn5BoUnZqANXUszd17_Q-RhfRo8V6Q&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQzx__blVU5FWJAUCU4d9-E095_n3Fgy1tuxA&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQh90iDDn5BoUnZqANXUszd17_Q-RhfRo8V6Q&usqp=CAU")
}
private fun setRecyclerView() {
zoneAdapter = ZoneImagesAdapter(image)
val flexboxLayoutManager = FlexboxLayoutManager(this)
flexboxLayoutManager.flexDirection =FlexDirection.ROW
flexboxLayoutManager.flexWrap = FlexWrap.WRAP
flexboxLayoutManager.justifyContent = JustifyContent.CENTER
flexboxLayoutManager.alignItems = AlignItems.STRETCH
zoneBinding.rvImages.apply {
adapter=zoneAdapter
layoutManager=flexboxLayoutManager
}
}
Adapter
class ZoneImagesAdapter (var listOfImageUrl:ArrayList<String>):
RecyclerView.Adapter<ZoneImagesAdapter.ImageViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder {
val view: View = LayoutInflater.from(parent.context)
.inflate(R.layout.big_image_layout, parent, false)
return ImageViewHolder(view)
}
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
val image = listOfImageUrl[position]
holder.setImages(image)
}
override fun getItemCount(): Int {
return listOfImageUrl.size
}
class ImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var zoneImage:ImageView=itemView.findViewById(R.id.big_image)
fun setImages(images: String) {
Glide.with(zoneImage).load(images).into(zoneImage)
val layoutParams:ViewGroup.LayoutParams = zoneImage.layoutParams
if (layoutParams is FlexboxLayoutManager.LayoutParams){
val flexboxLp:FlexboxLayoutManager.LayoutParams= layoutParams as FlexboxLayoutManager.LayoutParams
flexboxLp.flexGrow= 1.0f
}
}
}
}
How can I achieve this layout that is showing inside image using recyclerView, ?? I use flexboxLayoutManager for this but I do not know how can I used, Can anyone help me to make this layout that is showing inside image
My app shows multiple ImageButton with recycleview, everything works fine, what i want is when a person clicks a Imagebutton, they will be directed to the activity "monactivitefinal" and keep the content of "article.ifram" so that I use it on this new activity.
all the Imagebutton redirect to the same activity "monactivitefinal" only the variable "article.ifram" that changes
This is my code :
class Article(var id: Int, var nom: String, var lienimg: String, var ifram: String){
}
class ArticleAdapter(var articles: ArrayList<Article>) : RecyclerView.Adapter<ArticleAdapter.MyViewHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
var vue=LayoutInflater.from(parent.context).inflate(
R.layout.listevisitess,
parent,
false
)
return MyViewHolder(vue)
}
override fun getItemCount(): Int {
return articles.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
var article = articles.get(position)
holder.nomvisite.setText(article.nom)
holder.lieimgvisite.setText(article.lienimg)
holder.ifram.setText(article.ifram)
var urldelimg:String = article.lienimg
Glide.with(holder.imagedubloc.context).load(urldelimg).into(holder.imagedubloc)
}
class MyViewHolder(var vue: View):RecyclerView.ViewHolder(vue){
var nomvisite=vue.findViewById<TextView>(R.id.nom_visite)
var lieimgvisite=vue.findViewById<TextView>(R.id.lienimg)
var ifram=vue.findViewById<TextView>(R.id.ifram)
var imagedubloc=vue.findViewById<ImageView>(R.id.imagedubloc)
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="#+id/nom_visite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="25dp"
/>
<TextView
android:id="#+id/lienimg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="25dp"
/>
<ImageButton
android:id="#+id/imagedubloc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:scaleType="fitCenter"
/>
<TextView
android:id="#+id/ifram"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="25dp"
/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclevirtuel"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
Thank you
You can pass an extra field within your Intent that you are using to navigate to the new activity, you code would be like this:
class ArticleAdapter(var articles: ArrayList<Article>) : RecyclerView.Adapter<ArticleAdapter.MyViewHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
var vue=LayoutInflater.from(parent.context).inflate(
R.layout.listevisitess,
parent,
false
)
return MyViewHolder(vue)
}
override fun getItemCount(): Int {
return articles.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
var article = articles.get(position)
holder.nomvisite.setText(article.nom)
holder.lieimgvisite.setText(article.lienimg)
holder.ifram.setText(article.ifram)
var urldelimg:String = article.lienimg
Glide.with(holder.imagedubloc.context).load(urldelimg).into(holder.imagedubloc)
// here you pass your "ifram" value to the activity you're navigating to
holder.imagedubloc.setOnClickListener {
startActivity(Intent(holder.vue.context,monactivitefinal::class.java).apply {
putExtra("ifram", article.ifram)
})
}
}
class MyViewHolder(var vue: View):RecyclerView.ViewHolder(vue){
var nomvisite=vue.findViewById<TextView>(R.id.nom_visite)
var lieimgvisite=vue.findViewById<TextView>(R.id.lienimg)
var ifram=vue.findViewById<TextView>(R.id.ifram)
var imagedubloc=vue.findViewById<ImageView>(R.id.imagedubloc)
}
}
in your activity you can get "ifram" value as follows:
val ifram = getIntent().getStringExtra("ifram")
You need add listener to handle onClick Event, then the ButtonListActivity needs to implement this interface and init your adapter with it like this.
Listener
interface ImageButtonClickListener {
fun onImageButtonClick(articleIfram: String)
}
Activity with list of buttons
class ButtonListActivity : AppCompactActivity(), ImageButtonClickListener {
private val adapter: ArticleAdapter = ArticleAdapter(ArrayList(), this)
override fun onImageButtonClick(articleIfram: String) {
val intent = Intent(context, Monactivitefinal::class.java)
intent.putExtra("articleIfram", articleIfram)
startActivity(intent)
}
}
Your adapter
class ArticleAdapter(
val onImageButtonClickListener: ImageButtonClickListener,
var articles: ArrayList<Article>
) : RecyclerView.Adapter<ArticleAdapter.MyViewHolder>(){
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
var article = articles.get(position)
imagedubloc.setOnClickListener {
onImageButtonClickListener.onImageButtonClick(article. ifram)
}
}
}
You could use lambda if you don't want to add listener
Activity with list of buttons
class ButtonListActivity : AppCompactActivity(), ImageButtonClickListener {
private val onImageButtonClick: (String) -> Unit = {
val intent = Intent(context, Monactivitefinal::class.java)
intent.putExtra("articleIfram", articleIfram)
startActivity(intent)
}
private val adapter: ArticleAdapter = ArticleAdapter(ArrayList(), onImageButtonClick)
}
Your adapter
class ArticleAdapter(
val onImageButtonClickListener: (String) -> Unit,
var articles: ArrayList<Article>
) : RecyclerView.Adapter<ArticleAdapter.MyViewHolder>(){
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
var article = articles.get(position)
imagedubloc.setOnClickListener {
onImageButtonClickListener(article. ifram)
}
}
}
I have created a recycle view and inside that using card view for items. I have a delete button inside a card view whenever I click on that button my item is deleted from SQLite database. But to reflect it on UI, app need to restart. How can I notify adpater that item is deleted?
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="57dp"
android:layout_height="64dp"
android:layout_marginEnd="40dp"
android:layout_marginBottom="40dp"
android:clickable="true"
android:onClick="addNewCredentials"
app:backgroundTint="#270867"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="#android:drawable/ic_menu_add" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="1dp"
android:layout_marginTop="1dp"
android:layout_marginEnd="1dp"
android:layout_marginBottom="1dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" >
</androidx.recyclerview.widget.RecyclerView>
</androidx.constraintlayout.widget.ConstraintLayout>
list_item_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/urlView"
android:layout_width="300dp"
android:layout_height="30dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:text="url"
android:textAppearance="#style/TextAppearance.AppCompat.Large"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="#+id/userNameView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0" />
<TextView
android:id="#+id/userNameView"
android:layout_width="300dp"
android:layout_height="25dp"
android:layout_marginBottom="16dp"
android:text="userName"
app:layout_constraintBottom_toTopOf="#+id/passwordView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.1"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="#+id/passwordView"
android:layout_width="300dp"
android:layout_height="25dp"
android:layout_marginBottom="16dp"
android:text="password"
app:layout_constraintBottom_toTopOf="#+id/noteView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.1"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="#+id/noteView"
android:layout_width="300dp"
android:layout_height="30dp"
android:layout_marginBottom="16dp"
android:text="note"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.1"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="#+id/delButton"
android:layout_width="78dp"
android:layout_height="40dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="36dp"
android:background="#E6360F"
android:text="#string/delete_credential_button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
MainActivity.kt
package com.example.passwordmanager
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL,false)
val db = DataBaseHandler(this)
val detailsData = db.readCredentials()
val adapter = CredentialAdapter(detailsData,this,{credentialsModel: CredentialsModel->deleteClick(credentialsModel)})
recyclerView.adapter = adapter
}
fun deleteClick(credential: CredentialsModel){
val db = DataBaseHandler(this)
if(db.deleteData(credential.id)){
//adapter.notifyItemRemoved(position)
Toast.makeText(applicationContext,"Deleted", Toast.LENGTH_SHORT).show()
}
}
fun addNewCredentials(view : View){
print("hello world")
val intent = Intent(this, AddDetailActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
}
}
CredentialAdapter.kt
package com.example.passwordmanager
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.list_item_layout.view.*
class CredentialAdapter(
private val items: List<CredentialsModel>,
ctx: Context, val clickListener: (CredentialsModel) -> Unit
): RecyclerView.Adapter<CredentialAdapter.ViewHolder>() {
var context = ctx
class ViewHolder(itemView: View):RecyclerView.ViewHolder(itemView){
fun bind(credential: CredentialsModel,clickListener: (CredentialsModel) -> Unit){
itemView.urlView.text = credential.url
itemView.userNameView.text = credential.userName
itemView.passwordView.text = credential.password
itemView.noteView.text = credential.note
itemView.delButton.setOnClickListener{clickListener(credential)}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item_layout,parent,false))
}
override fun getItemCount(): Int {
return items.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val credential:CredentialsModel = items[position]
holder.bind(credential,clickListener)
}
}
add remove setOnClickListener in your onBindViewHolder.
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.remove.setOnClickListener {
val db = DataBaseHandler(this)
if(db.deleteData(credential.id)){
notifyItemRemoved(holder.getAdapterPosition())
}
}
}
The best way to handle these kinds of situations is to use LiveData.
LiveData is basically an observable class which reads data only when there is a change.
What you can do is create a set function in your adapter like:
internal fun setData(data: List<Data>) {
this.data= dataList //this datalist is a list defined in your adapter
notifyDataSetChanged()
}
now in your main activity/fragment, create a LiveData List outside the onCreate function like this:
private lateinit var allData:LiveData<List<Data>>
Now inside your onCreate function, use can observe the livedata and set the data for recyclerview like this:
allData.observe(this, Observer { data->
data?.let { adapter.setData(it) }
})
You are deleting the item from database but not from the list inside recyclerview adapter.
class CredentialAdapter(
private val items: ArrayList<CredentialsModel>, // Change list to arraylist
ctx: Context, val clickListener: (CredentialsModel, Int) -> Unit
): RecyclerView.Adapter<CredentialAdapter.ViewHolder>() {
...
...
fun remove(position: Int) {
// Remove and notify the adapter to reload
items.removeAt(position)
notifyItemRemoved(position)
}
class ViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) {
fun bind(credential: CredentialsModel,clickListener: (CredentialsModel, Int) -> Unit){
...
...
// Pass adapter item position so that we can update the list after delete
itemView.delButton.setOnClickListener{clickListener(credential, adapterPosition)
}
}
...
...
}
Inside MainActivity.kt
fun deleteClick(credential: CredentialsModel, position: Int) {
val db = DataBaseHandler(this)
if(db.deleteData(credential.id)){
adapter.remove(position)
Toast.makeText(applicationContext,"Deleted", Toast.LENGTH_SHORT).show()
}
}
use ListAdpater
class AdapterMain(var onClickListener: (Int) -> Unit) :
ListAdapter<Note, AdapterMain.NoteViewHolder>(DIFFCALBACK) {
companion object DIFFCALBACK : DiffUtil.ItemCallback<Note>() {
override fun areItemsTheSame(oldItem: Note, newItem: Note): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Note, newItem: Note): Boolean {
return oldItem.title == newItem.title &&
oldItem.description == newItem.description &&
oldItem.priority == newItem.priority
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.note_item, parent, false)
return NoteViewHolder(view)
}
override fun onBindViewHolder(holder: NoteViewHolder, position: Int) {
holder.txtTitle.text = getItem(position).title
holder.txtDesc.text = getItem(position).description
holder.txtPriority.text = getItem(position).priority.toString()
}
inner class NoteViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var txtTitle: TextView = itemView.txt_title
var txtDesc: TextView = itemView.txt_desc
var txtPriority: TextView = itemView.txt_priority
init {
itemView.setOnClickListener { onClickListener(adapterPosition) }
}
}
fun getNoteAt(position: Int): Note {
return getItem(position)
}
}
you can see complete code of simple NoteApp with kotlin , recyclerView , MVVM and..
class coba : AppCompatActivity() {
private lateinit var recycleView :RecyclerView
private lateinit var datalis :ArrayList
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_coba)
recycleView = findViewById(R.id.rcycoba)
datalis = ArrayList()
val dtnama = arrayOf(
"Danial Sanganus",
"Bijonia Skolin",
"Alianes Pertoli",
"Sivanian Pertici",
"Olehsan alausi"
)
for (i in dtnama.indices){
datalis.add(
dataCoba(
dtnama[i]
)
)
populateData()
}
}
private fun populateData(){
val linearManager = LinearLayoutManager(this)
linearManager.reverseLayout=true
linearManager.stackFromEnd=true
recycleView.layoutManager=linearManager
val adp =adpCoba(this,datalis)
recycleView.adapter=adp
}
}
I see the problem with a RecyclerView in viewpager fragment and I use bottom naviagation bar. When I tab on the navigation bar to change a screen and then pressed on back button it will go to the first screen which have the viewpager but the recyclerview doesn't appear and when I tab the naviagtion bar to reselect this screen it appear.
The recyclerview is show the list from firestore database and using ViewModel.
I try to set retainInstance to true but it doesn't work. And try to setup the recyclerview in onCreate and onCreateView it doesn't work too.
Edit: this is my code.
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navView: BottomNavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
navView.setupWithNavController(navController)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId){
android.R.id.home -> {
onBackPressed()
return true
}
}
return super.onOptionsItemSelected(item)
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="#drawable/bg_nav"
app:itemIconTint="#color/navbar_color"
app:itemTextColor="#color/navbar_color"
app:itemTextAppearanceActive="#style/navbar_font"
app:itemTextAppearanceInactive="#style/navbar_font"
app:itemBackground="#drawable/nav_ripple"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/bottom_nav_menu"/>
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="#id/nav_view"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/mobile_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>
HomeFragement.kt (it contain tablayout and viewpager)
class HomeFragment : Fragment() {
private lateinit var homeViewModel: HomeViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
homeViewModel =
ViewModelProviders.of(this).get(HomeViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_home, container, false)
return root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setupTab()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
private fun setupTab(){
Log.d("SET UP TAB", "SETTING UP")
val pageTabAdapter = PageTabAdapter(activity!!.supportFragmentManager, activity_tab.tabCount)
view_activity.adapter = pageTabAdapter
view_activity.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(activity_tab))
activity_tab.setOnTabSelectedListener(object : TabLayout.OnTabSelectedListener{
override fun onTabReselected(p0: TabLayout.Tab?) {
}
override fun onTabUnselected(p0: TabLayout.Tab?) {
}
override fun onTabSelected(p0: TabLayout.Tab?) {
view_activity.currentItem = p0!!.position
}
})
}
}
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
android:orientation="vertical">
<TextView
android:id="#+id/home_header"
style="#style/page_header"
android:text="#string/title_home"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:id="#+id/calendar_btn"
android:layout_width="60dp"
android:layout_height="40dp"
android:background="#drawable/btn_calendar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#id/home_header"
app:layout_constraintBottom_toBottomOf="#id/home_header"
android:layout_marginEnd="10dp"/>
<com.google.android.material.tabs.TabLayout
android:id="#+id/activity_tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabRippleColor="#color/colorPrimary"
app:tabTextAppearance="#style/tab_font"
app:tabIndicatorHeight="2.5dp"
app:tabGravity="fill"
app:layout_constraintTop_toBottomOf="#id/home_header"
app:layout_constraintStart_toStartOf="parent"
android:background="#android:color/white">
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="กิจกรรมในเดือนนี้" />
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="กิจกรรมที่ผ่านไปแล้ว" />
</com.google.android.material.tabs.TabLayout>
<androidx.viewpager.widget.ViewPager
android:id="#+id/view_activity"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="#id/activity_tab"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
PageAdapter.kt
class PageTabAdapter(private val fragmentManager: FragmentManager, private val anInt: Int) :
FragmentStatePagerAdapter(fragmentManager) {
override fun getItem(position: Int): Fragment {
return when (position) {
0 -> {
NewActivity.newInstance()
}
1 -> {
PastActivity.newInstance()
}
else -> {
null!!
}
}
}
override fun getCount(): Int {
return anInt
}
}
ActivityAdapter.kt (this is a recyclerview adapter)
class ActivityAdapter(
private val mContext: Context, private val mItems: List<ActivityModel>
): RecyclerView.Adapter<ActivityAdapter.Holder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val inflater = LayoutInflater.from(this.mContext)
val view = inflater.inflate(R.layout.activity_list, parent, false)
return Holder(view)
}
override fun getItemCount(): Int {
return this.mItems.size
}
override fun onBindViewHolder(holder: Holder, position: Int) {
val item = this.mItems[position]
holder.setName(item.name)
val date = item.date?.toDate()
val dateFormat: DateFormat = SimpleDateFormat("dd-MMM-yyyy")
val newDate = dateFormat.format(date).toString()
holder.setDate(newDate)
val period = item.start + " - " +item.end
holder.setPeriod(period)
holder.setButton(item)
}
inner class Holder(view: View): RecyclerView.ViewHolder(view){
private var activityName: TextView = view.activity_list_name
private var activityDate: TextView = view.activity_list_date
private var activityPeriod: TextView = view.activity_list_period
private var activityPicture: ImageView = view.activity_list_pic
private var activityButton: Button = view.activity_list_btn
fun setName(name: String?){
this.activityName.text = name
}
fun setDate(date: String?){
this.activityDate.text = date
}
fun setPeriod(period: String?){
this.activityPeriod.text = period
}
fun setPicture(picpath: String?){
}
fun setButton(data: ActivityModel){
}
}
}
}
PS.: I'm using Kotlin in my project
Thank you