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:
- Request a json array from an https source
- Get the json objects for each element of the json array
- display the objects in recyclerview
but my app crashes after getting the response for my json array
CodePudding user response:
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)
