I have error in this code (
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter result)
And didn't save image
i will give you all the code:
MainActivity code:
package com.masreta87.backhussian
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.masreta87.backhussian.models.BlogPost
import com.masreta87.backhussian.models.DataSource
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private lateinit var blogAdapter:BlogRecyclerAdapter
lateinit var data: List<BlogPost>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initRecyclerView()
addDataSet()
}
private fun addDataSet(){
data=DataSource.createDataSet()
blogAdapter.submitList(data)
}
private fun initRecyclerView(){
recycler_view.apply {
layoutManager=LinearLayoutManager(this#MainActivity)
blogAdapter=BlogRecyclerAdapter()
adapter=blogAdapter
}
}
}
and BlogRecyclerAdapter.kt
package com.masreta87.backhussian
import android.content.Context
import android.graphics.Bitmap
import android.os.AsyncTask
import android.os.Environment
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.masreta87.backhussian.models.BlogPost
import kotlinx.android.synthetic.main.layout_blog_list_item.view.*
import java.net.URL
import android.os.Environment.getExternalStorageDirectory
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy
import java.io.File
import java.io.FileOutputStream
import java.lang.ref.WeakReference
import android.widget.Toast
import android.content.Intent
import android.annotation.SuppressLint
import android.app.ProgressDialog
import android.net.Uri
import com.squareup.picasso.Picasso
import java.io.IOException
class BlogRecyclerAdapter :RecyclerView.Adapter<RecyclerView.ViewHolder>(){
private var items:List <BlogPost> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return BlogViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.layout_blog_list_item,parent,false)
)
}
override fun getItemCount(): Int {
return items.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when(holder){
is BlogViewHolder ->{
holder.bind(items.get(position))
}
}
}
fun submitList(blogList: List<BlogPost>){
items = blogList
}
class BlogViewHolder constructor(
itemView:View
):RecyclerView.ViewHolder(itemView){
val blogImage:ImageView =itemView.blog_image
fun bind(blogPost:BlogPost){
val requestOptions =RequestOptions()
.placeholder(R.drawable.ic_launcher_background)
.error(R.drawable.ic_launcher_background)
Glide.with(itemView.context)
.applyDefaultRequestOptions(requestOptions)
.load(blogPost.image)
.into(blogImage)
itemView.setOnClickListener{
SaveImage(itemView.context,blogPost.image.toString() );
}
}
}
}
private fun SaveImage(context: Context, MyUrl: String) {
val progress = ProgressDialog(context)
class SaveThisImage : AsyncTask<Void, Void, Void>() {
override fun onPreExecute() {
super.onPreExecute()
progress.setTitle("Processing")
progress.setMessage("Please Wait...")
progress.setCancelable(false)
progress.show()
}
override fun doInBackground(vararg arg0: Void): Void? {
try {
val sdCard = Environment.getExternalStorageDirectory()
#SuppressLint("DefaultLocale") val fileName =
String.format("%dm.png", System.currentTimeMillis())
val dir = File(sdCard.absolutePath + "/Image")
dir.mkdirs()
val myImageFile = File(dir,fileName) // Create image file
**var fos:FileOutputStream? = null**
try {
Log.d("ala",myImageFile.toString())
**fos = FileOutputStream(myImageFile)**
val bitmap = Picasso.get().load(MyUrl).get()
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)
val intent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
intent.data = Uri.fromFile(myImageFile)
context.sendBroadcast(intent)
} catch (e: IOException) {
e.printStackTrace()
} finally {
try {
fos!!.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
} catch (e: Exception) {
}
return null
}
override fun onPostExecute(result: Void) {
super.onPostExecute(result)
if (progress.isShowing) {
progress.dismiss()
}
Toast.makeText(context, "Saved", Toast.LENGTH_SHORT).show()
}
}
val shareimg = SaveThisImage()
shareimg.execute()
}
And BlogPost.class
package com.masreta87.backhussian.models
data class BlogPost(
var image:String
)
{
}
AND DataStore.class
package com.masreta87.backhussian.models
class DataSource{
companion object{
fun createDataSet(): ArrayList<BlogPost>{
val list = ArrayList<BlogPost>()
list.add(
BlogPost(
"https://firebasestorage.googleapis.com/v0/b/databaseim-56ef5.appspot.com/o/rpic%20(2).jpg?alt=media&token=138c2c3b-33ce-4a96-a7f5-74816af21809"
)
)
list.add(
BlogPost(
"https://firebasestorage.googleapis.com/v0/b/databaseim-56ef5.appspot.com/o/v1.png?alt=media&token=2e80d218-eb48-4c51-b51a-0fac43f76da7"
)
)
list.add(
BlogPost(
"https://firebasestorage.googleapis.com/v0/b/databaseim-56ef5.appspot.com/o/v10.jpg?alt=media&token=5e7207eb-1dac-41c0-bb3b-95abf9a54a2e"
)
)
list.add(
BlogPost(
"https://firebasestorage.googleapis.com/v0/b/databaseim-56ef5.appspot.com/o/v11.jpg?alt=media&token=2ab2b0c4-5ca1-4042-85c5-6d3e58181f45"
)
)
return list
}
}
}
And Mainifest
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
And 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">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:id="#+id/recycler_view"/>
</androidx.constraintlayout.widget.ConstraintLayout>
And layout_blog_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:cardElevation="10dp"
app:cardCornerRadius="2dp"
app:cardPreventCornerOverlap="false"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="610dp"
app:layout_constraintTop_toTopOf="parent"
android:id="#+id/blog_image"
android:background="#drawable/boder_image"
android:padding="10dp"
android:layout_margin="0dp"
android:adjustViewBounds="true"
android:scaleType="fitXY"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
and full error:
2020-01-15 21:34:36.509 32083-32083/? E/AndroidRuntime: FATAL
EXCEPTION: main
Process: com.masreta87.backhussian, PID: 32083
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method
kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter
result
at com.masreta87.backhussian.BlogRecyclerAdapterKt$SaveImage$SaveThisImage.onPostExecute(Unknown
Source:2)
at com.masreta87.backhussian.BlogRecyclerAdapterKt$SaveImage$SaveThisImage.onPostExecute(BlogRecyclerAdapter.kt:86)
at android.os.AsyncTask.finish(AsyncTask.java:695)
at android.os.AsyncTask.-wrap1(Unknown Source:0)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:712)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
this is full error in app
Change the parameter type in
override fun onPostExecute(result: Void)
to
override fun onPostExecute(result: Void?).
And as Akhilesh Kumar mentioned here you should also change
class SaveThisImage : AsyncTask<Void, Void, Void>()
to
class SaveThisImage : AsyncTask<Void, Void, Void?>()
This is because the doInBackground in your code returns a nullable type Void?. The return value of doInBackground is passed as an argument to onPostExcecute but your onPostExecute accepts a non null value Void instead of a nullable one Void?.
As a side-note you should use Unit instead of Void when in Kotlin
EDIT
To make your saved image appear the media database needs to be updated. The media database is updated when you restart your device or after some time passes it will show up in the save location. To update the media database immediately you can use the MediaScannerConnection object.
Try passing your saved file to this function after bitmap.compress and pass your myImageFile
/**
* Updates the Pictures gallery to include the newly created file.
* #param fileObj: file path to be scanned so that the new file will appear in the gallery
*/
private fun refreshPhoneGallery(fileObj: File)
{
/* Scan the specified file path so that the new file will appear in gallery */
MediaScannerConnection.scanFile(
yourContext,
arrayOf(fileObj.path),
null,
object : MediaScannerConnection.OnScanCompletedListener
{
override fun onScanCompleted(scannedFilePath: String?, p1: Uri?)
{
// Do whatever
}
}
)
}
Related
I'm working on a project dealing with loading data from firebase into recyclerview. recyclerview seems working just fine but when i try to scroll it until the end of the posts it always make the app crash. it's so strange to me if i don't scroll to the end post it won't crash. in logcat it show only an error "fail to acquire dataanalyzer...". i have no clue about it. please kindly help!
Code as below :
package teacher
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.amazontutoringcenter.R
import com.example.amazontutoringcenter.databinding.ActivityTeacherLessonPlanBinding
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.*
import com.google.firebase.firestore.EventListener
import com.squareup.picasso.Picasso
import student.StudentPostData
import kotlin.collections.ArrayList
class TeacherLessonPlan: AppCompatActivity() {
private lateinit var binding : ActivityTeacherLessonPlanBinding
private lateinit var auth: FirebaseAuth
private lateinit var firebaseFirestore: FirebaseFirestore
private lateinit var userRecyclerview: RecyclerView
private lateinit var studentLessonPlanAdapter: LessonPlanAdapter
private lateinit var userArrayList: ArrayList<StudentPostData>
private lateinit var studentName: String
private lateinit var studentProfileUri : String
override fun onCreate(savedInstanceState: Bundle?){
super.onCreate(savedInstanceState)
binding = ActivityTeacherLessonPlanBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
auth = FirebaseAuth.getInstance()
// post lesson plan
binding.tvStudentName.setOnClickListener {
intent = Intent(this, TeacherLessonPlanPost::class.java)
intent.putExtra("studentName", studentName)
intent.putExtra("studentProfileUri", studentProfileUri)
startActivity(intent)
}
// get passing data to display profile and name
var b: Bundle = intent.extras!!
studentProfileUri = b.getString("studentProfileUri").toString()
studentName = b.getString("studentName").toString()
Picasso.get().load(studentProfileUri).fit()
.centerCrop().into(binding.imageStudentProfile)
userRecyclerview = findViewById(R.id.recyclerViewStudentLessonPlan)
userRecyclerview.layoutManager = LinearLayoutManager(this)
userArrayList = arrayListOf()
studentLessonPlanAdapter = LessonPlanAdapter(userArrayList)
userRecyclerview.adapter = studentLessonPlanAdapter
getStudentLessonPlanPost()
}
private fun getStudentLessonPlanPost() {
val uid = auth.currentUser!!.uid
firebaseFirestore = FirebaseFirestore.getInstance()
firebaseFirestore.collection("student").document("lesson plan")
.collection("$uid")
.addSnapshotListener(object : EventListener<QuerySnapshot> {
override fun onEvent(value: QuerySnapshot?, error: FirebaseFirestoreException?) {
if(error != null){
Log.d("check error", error.message.toString())
return
}
for(dc : DocumentChange in value?.documentChanges!!){
if(dc.type == DocumentChange.Type.ADDED){
userArrayList.add(dc.document.toObject(StudentPostData::class.java))
userArrayList.sortByDescending {
it.date
}
}
}
studentLessonPlanAdapter.notifyDataSetChanged()
}
})
}
inner class LessonPlanAdapter(private val userList : ArrayList<StudentPostData>) : RecyclerView.Adapter<LessonPlanAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(
R.layout.student_lesson_plan,
parent,false)
return MyViewHolder(itemView)
}
override fun getItemCount(): Int {
return userList.size
}
inner class MyViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){
val txLessonPlanDescription : TextView = itemView.findViewById(R.id.txLessonPlanDescription)
val imageStudentLessonPlan : ImageView = itemView.findViewById(R.id.imageStudentLessonPlan)
val imageStudentProfilePost : ImageView = itemView.findViewById(R.id.imageStudentProfilePost)
val tvStudentNamePost : TextView = itemView.findViewById(R.id.tvStudentNamePost)
// date on the post
val textDate : TextView = itemView.findViewById(R.id.txLessonPlanDate)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentitem = userList[position]
holder.txLessonPlanDescription.text = currentitem.description
holder.textDate.text = currentitem.date
Picasso.get().load(currentitem.imageUri)
.into(holder.imageStudentLessonPlan)
holder.tvStudentNamePost.text = studentName
Picasso.get().load(studentProfileUri).fit()
.centerCrop().into(holder.imageStudentProfilePost)
}
}
}
<?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="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
<LinearLayout
android:id="#+id/relativeLayout"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="70dp"
android:padding="15dp"
android:elevation="10dp"
android:layout_marginBottom="0dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="5dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="#+id/imageStudentProfile"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="5dp"
android:layout_marginTop="50dp"
android:src="#drawable/ic_profile"
app:shapeAppearanceOverlay="#style/circular"
app:strokeColor="#0AF3D0"
android:layout_gravity="center_horizontal"
app:strokeWidth="1dp" />
<TextView
android:id="#+id/tvStudentName"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginLeft="10dp"
android:padding="5dp"
android:fontFamily="serif"
android:clickable="true"
android:hint="បង្ហោះកិច្ចតែងការបង្រៀន..."
android:background="#drawable/border_square"
android:textColor="#2196F3"
android:textSize="20dp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerViewStudentLessonPlan"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="#layout/student_lesson_plan">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
Since you are using the userArrayList variable globally to serve your adapter the data try to remove the LessonPlanAdapter class parameter and just use the global variable to populate it:
inner class LessonPlanAdapter() : RecyclerView.Adapter<LessonPlanAdapter.MyViewHolder>() {
...
override fun getItemCount(): Int = userArrayList.size
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentitem = userArrayList[position]
...
}
}
I think that the problem may be related to the fact that the class variable containing the data wasn't updated correctly.
That could have caused an index out of bounds exception when reaching the bottom of the list.
Solved ! I'm not sure what the problem was but I could solve it by deleting all of the documents that I have in firestore then trying to add new documents. now it's working fine. thank guys for your help !
We have looked at a number of posts and tried a few with no results.
Here is the Github link for full code.
Here is the code for the activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".activity.MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/todoRv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/AddTask"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
app:srcCompat="#android:drawable/ic_input_add"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_margin="25dp"
android:onClick="openNewTask"
/>
</RelativeLayout>
Here is the code for the activity_task.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:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context=".activity.TaskActivity">
<TextView
android:id="#+id/txtTaskName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Task Name"
android:layout_margin="14dp"
android:textSize="33sp"/>
<EditText
android:id="#+id/etTaskName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:hint="Please Enter Task Name"
android:layout_margin="14dp"
android:textSize="20sp"
android:inputType="textPersonName"
/>
<Button
android:id="#+id/saveTask"
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="34dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="saveTask"
android:text="Save Task" />
</LinearLayout>
Here is the code for the item_todo.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/txtShowTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:layout_marginLeft="15dp"
android:textSize="35sp"
android:text="Task Title Name" />
</LinearLayout>
Here is the code for the MainActivity.kt
package abc.com.onetaskadd.activity
import abc.com.onetaskadd.R
import abc.com.onetaskadd.adapter.TodoAdapter
import abc.com.onetaskadd.database.TodoDatabase
import abc.com.onetaskadd.model.TodoModel
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Adapter
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
class MainActivity : AppCompatActivity() {
val todoList = arrayListOf<TodoModel>()
var recyclerAdapter= TodoAdapter(todoList)
lateinit var layoutmanger: RecyclerView.LayoutManager
lateinit var todoRv: RecyclerView
val db by lazy {
TodoDatabase.getDatabase(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
todoRv= findViewById(R.id.todoRv)
todoRv.apply {
layoutmanger= LinearLayoutManager(this#MainActivity)
adapter=this#MainActivity.recyclerAdapter
}
db.todoDao().getAllTask().observe(this, Observer {
if (!it.isNullOrEmpty()) {
todoList.clear()
todoList.addAll(it)
recyclerAdapter.notifyDataSetChanged()
}
})
}
fun openNewTask(view: View) {
startActivity(Intent(this, TaskActivity::class.java))
}
}
Here is the code for the TaskActivity.kt
package abc.com.onetaskadd.activity
import abc.com.onetaskadd.R
import abc.com.onetaskadd.database.TodoDatabase
import abc.com.onetaskadd.model.TodoModel
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.SyncStateContract.Helpers.insert
import android.view.View
import android.widget.Button
import android.widget.EditText
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
const val DB_NAME = "todo.db"
class TaskActivity : AppCompatActivity() {
lateinit var etTaskName: EditText
lateinit var saveTask: Button
val db by lazy {
TodoDatabase.getDatabase(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_task)
etTaskName = findViewById(R.id.etTaskName)
saveTask= findViewById(R.id.saveTask)
}
fun saveTask(view: View) {
val taskName = etTaskName.editableText.toString()
GlobalScope.launch(Dispatchers.Main) {
val id = withContext(Dispatchers.IO) {
return#withContext db.todoDao ().insertTask(
TodoModel(
taskName
)
)
}
finish()
}
}
}
Here is the code for the TodoAdapter.kt
package abc.com.onetaskadd.adapter
import abc.com.onetaskadd.R
import abc.com.onetaskadd.model.TodoModel
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class TodoAdapter (val todoList: List<TodoModel>) :RecyclerView.Adapter<TodoAdapter.TodoViewHolder>(){
class TodoViewHolder(view: View):RecyclerView.ViewHolder(view)
{
fun bind(todoModel: TodoModel) {
with(itemView){
val txtShowTitle: TextView= findViewById(R.id.txtShowTitle)
txtShowTitle.text=todoModel.taskName
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
val view= LayoutInflater.from(parent.context).inflate(R.layout.item_todo, parent, false)
return TodoViewHolder(view)
}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
holder.bind(todoList[position])
}
override fun getItemCount(): Int {
return todoList.size
}
}
Here is the code for the TodoDao.kt
package abc.com.onetaskadd.database
import abc.com.onetaskadd.model.TodoModel
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
#Dao
interface TodoDao {
#Insert()
suspend fun insertTask(todoModel: TodoModel):Long
#Query("Select * From TodoModel where isFinished != -1 ")
fun getAllTask():LiveData<List<TodoModel>>
}
Here is the code for the TaskDatabase.kt
package abc.com.onetaskadd.database
import abc.com.onetaskadd.activity.DB_NAME
import abc.com.onetaskadd.model.TodoModel
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
#Database(entities = [TodoModel::class],version = 1)
abstract class TodoDatabase: RoomDatabase() {
abstract fun todoDao(): TodoDao
companion object{
#Volatile
private var INSTANCE: TodoDatabase? =null
fun getDatabase(context: Context): TodoDatabase {
val tempInsance = INSTANCE
if (tempInsance != null) {
return tempInsance
}
synchronized(this){
val instance= Room.databaseBuilder(
context.applicationContext,
TodoDatabase:: class.java,
DB_NAME
).build()
INSTANCE= instance
return instance
}
}
}
}
Here is the code for the TodoModel.kt
package abc.com.onetaskadd.model
import androidx.room.Entity
import androidx.room.PrimaryKey
#Entity
data class TodoModel(
val taskName: String,
var isFinished: Int =-1,
#PrimaryKey
var id:Long=0
)
You should replace this code in TaskDatabase.kt file
synchronized(this){
val instance= Room.databaseBuilder(
context.applicationContext,
TodoDatabase:: class.java,
DB_NAME
).fallbackToDestructiveMigration().build()
It will Solve the debug problem.
i'd like to know what i'm doing wrong over here. I'm building a CRUD app in Kotlin, and i'm using the recyclerview to make the readData page. The problem is, when i'm on the readData page doesn't show me anything, just the text views, so i debugged and when i join in the page, show this message: "Recyclerview No adapter attached; skipping layout".
Here's my code:
(i'm brazilian, so, some words are in portuguese, but you'll get it.)
verDados.kt
package com.nicolas.csrd
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import com.google.firebase.database.*
import kotlinx.android.synthetic.main.activity_ver_database.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class verDados : AppCompatActivity() {
private lateinit var database: FirebaseDatabase
private lateinit var reference: DatabaseReference
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_ver_database)
database = FirebaseDatabase.getInstance()
reference = database.getReference("usuarios")
verDados()
btn_voltar.setOnClickListener() {
startActivity(Intent(this#verDados, Dashboard::class.java))
finish()
}
}
private fun verDados() {
reference.addValueEventListener(object: ValueEventListener{
override fun onCancelled(p0: DatabaseError) {
Log.e("cancelar", p0.toString())
}
override fun onDataChange(p0: DataSnapshot) {
//Colocando os usuarios numa lista
var list = ArrayList<DatabaseModelo>()
for (data in p0.children) {
val model = data.getValue(DatabaseModelo::class.java)
list.add(model as DatabaseModelo)
}
if (list.size > 0) {
val ususariosModelo = usuariosModelo(list)
recyclerview.adapter = ususariosModelo
}
}
})
}
}
DatabaseModel
package com.nicolas.csrd
class DatabaseModelo() {
lateinit var email: String
lateinit var senha: String
constructor(email: String, senha: String) : this() {
this.email = email
this.senha = senha
}
}
usuariosModelo.kt (recyclerview adapter)
package com.nicolas.csrd
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.view.menu.ActionMenuItemView
import androidx.appcompat.view.menu.MenuView
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.usuarios_modelo.view.*
class usuariosModelo(val list: ArrayList<DatabaseModelo>): RecyclerView.Adapter<usuariosModelo.ViewHolder>() {
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val email = itemView.campo_email
val senha = itemView.campo_senha
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.usuarios_modelo, parent, false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.email.text = list[position].email
holder.senha.text = list[position].senha
}
override fun getItemCount(): Int {
return list.size
}
}
----- XML FILES -----
activity_ver_database.xml (read data page)
<?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:background="#color/dark"
tools:context=".Login">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal" >
<ImageView
android:id="#+id/btn_voltar"
android:layout_width="50dp"
android:layout_height="30dp"
android:layout_gravity="start"
android:layout_marginStart="5dp"
android:layout_marginTop="23dp"
android:src="#drawable/back_arrow" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DADOS"
android:textColor="#7ec1d1"
android:textSize="30sp"
android:textStyle="bold"
android:layout_marginTop="20dp"
android:letterSpacing="0.15"
android:fontFamily="#font/montserrat_medium"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Todos os usuários cadastrados"
android:textColor="#7ec1d1"
android:textSize="20sp"
android:textStyle="bold"
android:layout_marginTop="0dp"
android:fontFamily="#font/montserrat_thin"
/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/recyclerview"
android:layout_margin="10sp"/>
<TextView
android:id="#+id/btn_cadastrar"
android:layout_width="350dp"
android:layout_height="50dp"
android:layout_marginTop="30dp"
android:backgroundTint="#7ec1d1"
android:gravity="center_horizontal"
android:fontFamily="#font/montserrat_regular"
android:text="Deseja cadastrar alguém? Clique aqui."
android:textColor="#color/white2"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
You are getting this error because you have no defined an adaptor for the RecyclerView that you are using. Somewhere inn your onCreate method, create the adaptor and set it to the RecyclerView. Something like:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_ver_database)
recyclerView = findViewById(R.id.recyclerview)
recyclerView.apply {
adapter = usuariosModelo(listOfItems)
}
database = FirebaseDatabase.getInstance()
reference = database.getReference("usuarios")
verDados()
btn_voltar.setOnClickListener() {
startActivity(Intent(this#verDados, Dashboard::class.java))
finish()
}
}
i solve the problem just adding the tag below inside the recyclerview tag in the .xml file:
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
I hope that help y'all!
I followed a tutorial to create an application that displays data from a mysql table, if i run the app everything works without error, the application opens with the header but without content, blank page instead of the content list.
activity_main.xml :
package com.example.bingmada
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.volley.Request
import com.android.volley.Response
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import org.json.JSONArray
class MainActivity : AppCompatActivity() {
var adapter:ArticleAdapter ?=null
var articles:ArrayList<Article> ?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
articles= ArrayList()
getArticlesFromServer()
adapter = ArticleAdapter(articles!!)
var recyclerView = findViewById<RecyclerView>(R.id.recyclevirtuel)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter=adapter
}
fun getArticlesFromServer(){
var url="https://www.exemplesite.com/android/bingmada.php"
var stringRequest=StringRequest(Request.Method.GET,url,Response.Listener { response -> parseData(response) }, Response.ErrorListener { error ->
Toast.makeText(this,"Erreur de connexion ", Toast.LENGTH_SHORT).show()
})
var req=Volley.newRequestQueue(this)
req.add(stringRequest)
}
fun parseData(response:String){
var arrayJson = JSONArray(response)
for(i in 0..arrayJson.length()-1){
var currentObject=arrayJson.getJSONObject(i)
var article = Article(currentObject.getInt("id"),
currentObject.getString("nom"),
currentObject.getString("lienimg"),
currentObject.getString("ifram"))
articles?.add(article)
}
}
}
the page https://www.exemplesite.com/android/bingmada.php show :
[{"id":"1","nom":"tesmon","lienimg":"bingo1","ifram":"car1"},{"id":"2","nom":"testeds","lienimg":"bingo","ifram":"car2"},{"id":"3","nom":"test1","lienimg":"bingo3","ifram":"car3"},{"id":"4","nom":"testr","lienimg":"bingo4","ifram":"car4"},{"id":"5","nom":"test2","lienimg":"bingo5","ifram":"car5"},{"id":"6","nom":"letest","lienimg":"bingo6","ifram":"car6"},{"id":"7","nom":"test3","lienimg":"bingo7","ifram":"car7"},{"id":"8","nom":"testo","lienimg":"bingo8","ifram":"car8"},{"id":"9","nom":"test4","lienimg":"bingo9","ifram":"car9"},{"id":"10","nom":"testad","lienimg":"bingo10","ifram":"car10"},{"id":"11","nom":"test5","lienimg":"bingo11","ifram":"car11"},{"id":"12","nom":"testd","lienimg":"bingo12","ifram":"car12"},{"id":"13","nom":"test6","lienimg":"bingo13","ifram":"car13"},{"id":"14","nom":"testiu","lienimg":"bingo14","ifram":"car14"},{"id":"15","nom":"teste","lienimg":"bingo15","ifram":"car15"}]
in my page listevirtuelles.kt :
package com.example.bingmada
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
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.activity_listevirtuelles, 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.idvirtuelleli.setText(article.id)
holder.nomvisite.setText(article.nom)
holder.lieimgvisite.setText(article.lienimg)
holder.ifram.setText(article.ifram)
}
class MyViewHolder(var vue:View):RecyclerView.ViewHolder(vue){
var idvirtuelleli=vue.findViewById<TextView>(R.id.idvirtuelleli)
var nomvisite=vue.findViewById<TextView>(R.id.nom_virtuelleli)
var lieimgvisite=vue.findViewById<TextView>(R.id.lienimg)
var ifram=vue.findViewById<TextView>(R.id.ifram)
}
}
activity_main.xml page :
<?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>
a page activity_listevirtuelles.xml :
<?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/idvirtuelleli"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="id"
android:textSize="25dp"
/>
<TextView
android:id="#+id/nom_virtuelleli"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Lenom"
android:textSize="25dp"
/>
<TextView
android:id="#+id/lienimg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="lien dimage"
android:textSize="25dp"
/>
<TextView
android:id="#+id/ifram"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="codeifram"
android:textSize="25dp"
/>
</LinearLayout>
can you help me find the problem please?
If you can see the relevant data in the activity. Since it is an asynchronous process, can you apply the structure I added to connect the data with recyclerview?
class MainActivity : AppCompatActivity() {
var adapter:ArticleAdapter ?=null
var articles:ArrayList<Article> ?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
articles= ArrayList()
adapter = ArticleAdapter(articles!!) // 1 line up to changed
getArticlesFromServer()
var recyclerView = findViewById<RecyclerView>(R.id.recyclevirtuel)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter=adapter
}
fun getArticlesFromServer(){
var url="https://www.exemplesite.com/android/bingmada.php"
var stringRequest=StringRequest(Request.Method.GET,url,Response.Listener { response -> parseData(response) }, Response.ErrorListener { error ->
Toast.makeText(this,"Erreur de connexion ", Toast.LENGTH_SHORT).show()
})
var req=Volley.newRequestQueue(this)
req.add(stringRequest)
}
fun parseData(response:String){
var arrayJson = JSONArray(response)
for(i in 0..arrayJson.length()-1){
var currentObject=arrayJson.getJSONObject(i)
var article = Article(currentObject.getInt("id"),
currentObject.getString("nom"),
currentObject.getString("lienimg"),
currentObject.getString("ifram"))
articles?.add(article)
}
adapter.notifydatasetchanged() // added
}
}
Here's the minimal test case what I've managed to make.
It combines with a RecyclerView and TextView, the activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="#+id/textViewBatteryInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hi, I'm watching you!"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/my_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
With the MainActivity.kt:
package kot.bignerd.recyclerview101
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import android.view.View
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val items = arrayListOf<String>()
for (i in 10..50) {
items.add("Here's the $i th")
}
my_rv.layoutManager = LinearLayoutManager(this)
my_rv.adapter = MyListAdapter(items, this)
//my_rv.visibility = View.GONE
}
}
With a very simple adapter(MyListAdapter):
package kot.bignerd.recyclerview101
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
class MyListAdapter(val datas: List<String>, val context: Context) : RecyclerView.Adapter<MyListAdapter.InnerHolder>() {
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): MyListAdapter.InnerHolder {
var itemView: View = LayoutInflater.from(context).inflate(R.layout.item_rv, p0, false)
return InnerHolder(itemView)
}
override fun getItemCount(): Int = datas.size
class InnerHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var itemText: TextView = itemView.findViewById(R.id.item_tv)
}
override fun onBindViewHolder(p0: MyListAdapter.InnerHolder, p1: Int) {
p0?.itemText?.text = datas[p1]
}
}
The R.layout.item_rv mentioned in the adapter is (item_rv.xml):
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:id="#+id/item_cl"
android:layout_height="wrap_content">
<TextView
android:id="#+id/item_tv"
android:layout_width="0dp"
android:layout_height="50dp"
android:text="TestRV"
android:textSize="18sp"
android:gravity="center"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent" tools:layout_editor_absoluteY="16dp"
app:layout_constraintHorizontal_bias="0.0"/>
<Button
android:text="Close"
android:layout_width="86dp"
android:layout_height="wrap_content" tools:layout_editor_absoluteY="16dp"
android:id="#+id/button" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"/>
</android.support.constraint.ConstraintLayout>
I was wondering if maybe we could make the RecyclerView disappeared when I click any one of the button inside it? Just like the code my_rv.visibility = View.GONE in the MainActivity.kt:
Your adapter need to receive a Listener as an object in order to react to clicks.
Here's an example:
package kot.bignerd.recyclerview101
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
class MyListAdapter(val datas: List<String>, val context: Context, val clickListener: ClickListener) : RecyclerView.Adapter<MyListAdapter.InnerHolder>() {
public interface ClickListener {
fun onItemClicked()
}
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): MyListAdapter.InnerHolder {
var itemView: View = LayoutInflater.from(context).inflate(R.layout.item_rv, p0, false)
return InnerHolder(itemView)
}
override fun getItemCount(): Int = datas.size
class InnerHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var itemText: TextView = itemView.findViewById(R.id.item_tv)
var button: Button = itemView.findViewById(R.id. button)
fun bindView(text: String, clickListener: ClickListener) {
itemText.text = text
button.setOnClickListner {
clickListner.onItemClicked()
}
}
}
override fun onBindViewHolder(holder: MyListAdapter.InnerHolder, position: Int) {
holder.bindView(datas[position], clickListener)
}
}
Then change the signature of the activity as follow:
class MainActivity : AppCompatActivity(), ClickListener {
and implement the function as follow:
override fun onItemClicked() {
my_rv.visibility = View.GONE
}
Last, but not least, change how you initialise your adapter:
MyListAdapter(items, this, this)