I get no errors in building the app but when the app finally launches, it crashes right after response is gotten from the
JsonArrayRequest()
function.
these are my logcats: logcat 1 logcat 2
FATAL EXCEPTION: main
Process: com.example.scoremusplayer, PID: 19239
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object
at android.content.ContextWrapper.getApplicationContext(ContextWrapper.java:122)
at com.bumptech.glide.Glide.get(Glide.java:128)
at com.bumptech.glide.Glide.getRetriever (Glide.java:510)
at com.bumptech.glide.Glide.with(Glide.java:564)
at com.example.scoremusplayer.scoreExplore.adapter.AdapterForScoreListForAllScoreFragmentForRecyclerView.onBindViewHolder
at com.example.scoremusplayer.scoreExplore.adapter.AdapterForScoreListForAllScoreFragmentForRecyclerView.onBindViewHolder
at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder (RecyclerView.java:7065)
at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder (RecyclerView.java:7107)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline (RecyclerView.java:6012)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline (RecyclerView.java:6279)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition (RecyclerView.java:6118)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition (RecyclerView.java:6114)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
at androidx.recyclerview.widget.GridLayoutManager.LayoutChunk (GridLayoutManager.java:561)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
Below is the code in the fragment:
class AllScoresFragment : Fragment() {
companion object {
lateinit var tempList : ArrayList<Score>
fun newInstance() = AllScoresFragment()
}
private lateinit var binding: FragmentAllScoresBinding
private lateinit var viewModel: AllScoresViewModel
private lateinit var progressDialog : ProgressDialog
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentAllScoresBinding.inflate(inflater)
return binding.root
// return inflater.inflate(R.layout.fragment_all_scores, container, false)
}
@Deprecated("Deprecated in Java")
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProvider(this)[AllScoresViewModel::class.java]
binding.include.recyclerViewForScoreContent.setHasFixedSize(true)
binding.include.recyclerViewForScoreContent.layoutManager = GridLayoutManager(context, 3)
retrieveTwo()
binding.swipeToRefresh.setOnRefreshListener {
retrieveTwo()
binding.swipeToRefresh.isRefreshing = false
}
}
I can sense that the problem is coming from WHAT HAPPENS AFTER THE RESPONSE IS GOTTEN from the JsonArrayRequest
in the retrieveTwo()
function, but I cannot seem to know what I did wrong in there.
The following is the retrieveTwo()
function:
fun retrieveTwo() {
tempList = ArrayList()
progressDialog = ProgressDialog(context)
progressDialog.setMessage("Loading...")
progressDialog.show()
val pdfSiteUrl = "https://..."
// Get a RequestQueue
AllScoresFragment().context?.let { MySingleton.getInstance(it).requestQueue }
val jsonArrayRequest = JsonArrayRequest(
Request.Method.GET, pdfSiteUrl, null,
{ response ->
//Toast the response to know if response is actually gotten
Toast.makeText(context, response.toString(), Toast.LENGTH_LONG).show()
var jo : JSONObject
try {
for (i in 0 until response.length()){
jo = response.getJSONObject(i)
val id = jo.getInt("id")
val name:String = jo.getString("name")
val composer:String = jo.getString("composer")
val style:String = jo.getString("style")
val theme:String = jo.getString("theme")
val album:String = jo.getString("album")
val lang:String = jo.getString("lang")
val thumbnailUrl:String = jo.getString("thumbnail_url")
val pdfUrl: String = jo.getString("pdf_url")
val score = Score(
id = id,
name = name,
composer = composer,
style = style,
theme = theme,
album = album,
lang = lang,
thumbnail_url = pdfSiteUrl + thumbnailUrl,
pdf_url = pdfSiteUrl + pdfUrl
)
tempList.add(score)
val adapter =
context?.let {
AdapterForScoreListForAllScoreFragmentForRecyclerView(it,
tempList) }
binding.include.recyclerViewForScoreContent.adapter = adapter
progressDialog.hide()
}
} catch (e : JSONException){
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
progressDialog.hide()
}
},
{ error ->
Toast.makeText(context,
error.message,
Toast.LENGTH_SHORT)
.show()
progressDialog.hide()
}
)
// Access the RequestQueue through my singleton class.
context?.let { MySingleton.getInstance(it).addToRequestQueue(jsonArrayRequest) }
}
Below is how my Recyclerview Adapter looks like:
class AdapterForScoreListForAllScoreFragmentForRecyclerView(
private val context: Context,
private val scoreList: ArrayList<Score>
) : RecyclerView.Adapter<AdapterForScoreListForAllScoreFragmentForRecyclerView.ViewHolder>() {
class ViewHolder(binding: ScoreListForRecycleBinding) : RecyclerView.ViewHolder(binding.root){
val pdfThumbnailImage = binding.thumbnailForScore
val songTitle = binding.scoreTitleNameOfAllScoresFragment
val composerName = binding.nameOfComposerForAllScoresFragment
val genre = binding.styleForAllScoresFragment
//val for root
val root = binding.root
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)
: ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val scoreList = ScoreListForRecycleBinding.inflate(layoutInflater, parent, false)
return ViewHolder(scoreList)
}
override fun getItemCount(): Int {
return scoreList.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val scoreName = scoreList[position].name
val scoreComposer = scoreList[position].composer
val genre = scoreList[position].style
val pdfUrl = scoreList[position].pdf_url
val thumbnailImage = scoreList[position].thumbnail_url
holder.songTitle.text = scoreName
holder.composerName.text = scoreComposer
holder.genre.text = genre
if (pdfUrl.isNotEmpty()){
Glide
.with(FragmentActivity())
.load(thumbnailImage)
.placeholder(R.drawable.scoremus_icon_slash)
.into(holder.pdfThumbnailImage)
}
holder.root.setOnClickListener {
holder.root.isLongClickable = true
Toast.makeText(
context,
"opening \"${scoreName.uppercase()} composed by $scoreComposer\"...",
Toast.LENGTH_SHORT)
.show()
val intent = Intent(context, PdfActivity::class.java)
intent.putExtra("index", position)
intent.putExtra("pdfPath", scoreList[position].pdf_url)
ContextCompat.startActivity(context, intent, null)
}
}
}
Help me out please
This is what i wanna do:
but my app crashes after getting the response for my json array
if (pdfUrl.isNotEmpty()){
Glide
.with(FragmentActivity())
.load(thumbnailImage)
.placeholder(R.drawable.scoremus_icon_slash)
.into(holder.pdfThumbnailImage)
}
You are creating and passing a Fragment Activity
instance to glide
which is not attached to the application context
. When glide
is trying to access the applicationContext
, it's throwing an NPE
.
You can either pass any holder view or the context
Using view
Glide
.with(holder.pdfThumbnailImage)
.load(thumbnailImage)
.placeholder(R.drawable.scoremus_icon_slash)
.into(holder.pdfThumbnailImage)
Using context
Glide
.with(holder.pdfThumbnailImage.context)
.load(thumbnailImage)
.placeholder(R.drawable.scoremus_icon_slash)
.into(holder.pdfThumbnailImage)