im following tutorial in youtube to create searchview use kotlin. What can be the possible solution? The code of activity doesn't show any error in the android studio but on running it shows an error.
im getting error at runtime test
E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Thread.isAlive()' on a null object reference
at com.github.barteksc.pdfviewer.PDFView.loadComplete(PDFView.java:756)
at com.github.barteksc.pdfviewer.DecodingAsyncTask.onPostExecute(DecodingAsyncTask.java:80)
at com.github.barteksc.pdfviewer.DecodingAsyncTask.onPostExecute(DecodingAsyncTask.java:27)
at android.os.AsyncTask.finish(AsyncTask.java:667)
at android.os.AsyncTask.-wrap1(AsyncTask.java)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:684)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
this is dependencies used
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
implementation 'com.google.firebase:firebase-analytics-ktx:20.0.2'
implementation 'com.google.firebase:firebase-auth-ktx:21.0.1'
implementation 'com.google.firebase:firebase-database-ktx:20.0.3'
implementation 'com.google.firebase:firebase-storage-ktx:20.0.0'
//pdf library
implementation 'com.github.mhiew:android-pdf-viewer:3.2.0-beta.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
this is PdfListAdminActivity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener
import com.rahmanadiyanto.mathlearn.databinding.ActivityPdfListAdminBinding
import java.lang.Exception
class PdfListAdminActivity : AppCompatActivity() {
//view binding
private lateinit var binding: ActivityPdfListAdminBinding
private companion object{
const val TAG = "PDF_LIST_ADMIN_TAG"
}
//category Id, Title
private var categoryId = ""
private var category =""
//array list to hold books
private lateinit var pdfArrayList: ArrayList<ModelPdf>
//adapter
private lateinit var adapterPdfAdmin: AdapterPdfAdmin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPdfListAdminBinding.inflate(layoutInflater)
setContentView(binding.root)
//get from intent, that we passed from adapter
val intent = intent
categoryId = intent.getStringExtra("categoryId")!!
category = intent.getStringExtra("category")!!
//handle click, back
binding.backBtn.setOnClickListener {
onBackPressed()
}
//set pdf category
binding.subTitleTv.text = category
//load pdf/books
loadPdfList()
//search
binding.searchEt.addTextChangedListener(object : TextWatcher{
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
try {
adapterPdfAdmin.filter.filter(s)
}
catch (e : Exception){
Log.d(TAG, "onTextChanged: ${e.message}")
}
}
override fun afterTextChanged(s: Editable?) {
}
})
}
private fun loadPdfList() {
//init array list
pdfArrayList = ArrayList()
//setup adapter
adapterPdfAdmin = AdapterPdfAdmin(this@PdfListAdminActivity,pdfArrayList)
binding.booksRv.adapter = adapterPdfAdmin
val ref = FirebaseDatabase.getInstance().getReference("Books")
ref.orderByChild("categoryId").equalTo(categoryId)
.addValueEventListener(object : ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
//clear list before adding data into it
pdfArrayList.clear()
for (ds in snapshot.children){
//get data
val model = ds.getValue(ModelPdf::class.java)
//adding to list
if (model != null) {
pdfArrayList.add(model)
Log.d(TAG, "onDataChange: ${model.title} ${model.categoryId}")
}
}
binding.booksRv.adapter = adapterPdfAdmin
}
override fun onCancelled(error: DatabaseError) {
}
})
}
}
FilterPdfAdmin
import android.widget.Filter
/*-----Use to filter data from recyclerview | search pdf from pdf list in recyclerview----*/
class FilterPdfAdmin : Filter {
//arraylist in which we want to search
private var filterList : ArrayList<ModelPdf> = ArrayList()
//adapter in which filter need to be implemented
private var adapterPdfAdmin : AdapterPdfAdmin
//constructor
constructor(filterList: ArrayList<ModelPdf>, adapterPdfAdmin: AdapterPdfAdmin) {
this.filterList = filterList
this.adapterPdfAdmin = adapterPdfAdmin
}
override fun performFiltering(constraint: CharSequence?): FilterResults {
var constraint2 = constraint //value to search
val results = FilterResults()
//value to be search should not be null and not empty
if (constraint2 != null && constraint2.isNotEmpty()){
//change to uppercase, or lowercase to avoid sensitivity
constraint2 =constraint2.toString().lowercase()
var filteredModels = ArrayList<ModelPdf>()
for (i in filterList.indices){
//validate if match
if (filterList[i].title.lowercase().contains(constraint2)){
//search value is similar to value in list, add to filtered list
filteredModels.add(filterList[i])
}
}
results.count = filteredModels.size
results.values = filteredModels
}
else{
//value is either null or empty, return all data
results.count = filterList.size
results.values = filterList
}
return results // don't miss
}
override fun publishResults(constraint: CharSequence, results: FilterResults) {
//apply filter changes
adapterPdfAdmin.pdfArrayList = results.values as ArrayList<ModelPdf>
//notify changes
adapterPdfAdmin.notifyDataSetChanged()
}
}
AdapterPdfAdmin
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Filter
import android.widget.Filterable
import androidx.recyclerview.widget.RecyclerView
import com.rahmanadiyanto.mathlearn.databinding.RowPdfAdminBinding
class AdapterPdfAdmin : RecyclerView.Adapter<AdapterPdfAdmin.HolderPdfAdmin>, Filterable{
//context
private val context: Context
//arraylist to hold pdfs
public var pdfArrayList: ArrayList<ModelPdf>
private val filterList: ArrayList<ModelPdf>
//view binding
private lateinit var binding: RowPdfAdminBinding
//filter object
private var filter : FilterPdfAdmin? = null
//constructor
constructor(context: Context, pdfArrayList: ArrayList<ModelPdf>) : super() {
this.context = context
this.pdfArrayList = pdfArrayList
this.filterList = pdfArrayList
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HolderPdfAdmin {
//bind/inflate layout row_pdf_admin.xml
binding = RowPdfAdminBinding.inflate(LayoutInflater.from(context), parent, false)
return HolderPdfAdmin(binding.root)
}
override fun onBindViewHolder(holder: HolderPdfAdmin, position: Int) {
/*------ get data, set data, handle click etc----------*/
//get data
val model = pdfArrayList[position]
val pdfId = model.id
val categoryId = model.categoryId
val title = model.title
val description = model.description
val pdfUrl = model.url
val timestamp = model.timestamp
// convert timestamp to dd/mm/yyyy format
val formattedDate = MyApplication.formatTimeStamp(timestamp)
//set data
holder.titleTv.text = title
holder.descriptionTv.text = description
holder.dateTv.text = formattedDate
//load further detail like category, pdf from url, pdf size
//load category
MyApplication.loadCategory(categoryId,holder.categoryTv)
//we don't need page number here, pas null for page number // load pdf thumbnail
MyApplication.loadPdfFromUrlSinglePage(pdfUrl,title,holder.pdfView,holder.progressBar,null)
//load pdf size
MyApplication.loadPdfSize(pdfUrl,title,holder.sizeTv)
}
override fun getItemCount(): Int {
return pdfArrayList.size // item count
}
override fun getFilter(): Filter {
if (filter == null){
filter = FilterPdfAdmin(filterList, this)
}
return filter as FilterPdfAdmin
}
//view holder class for row_pdf_admin.xml
inner class HolderPdfAdmin(itemView: View) : RecyclerView.ViewHolder(itemView){
//UI views of row_pdf_admin.xml
val pdfView = binding.pdfView
val progressBar = binding.progressBar
val titleTv = binding.titleTv
val descriptionTv = binding.descriptionTv
val categoryTv = binding.categoryTv
val sizeTv = binding.sizeTv
val dateTv = binding.dateTv
val moreBtn = binding.moreBtn
}
}