**这是我的问题:**当应用程序启动时,甚至在滑动刷新时,UI
中没有显示任何内容(没有项目),但我希望UI
在应用程序启动时在recyclerView
中显示一些项目。
检索到的jsonArray不是空的,也不是null。当我运行应用程序或使用我的应用程序时,我没有得到任何应用程序崩溃或logcat中的错误。
**有趣的是:*当我点击设备上的light/dark mode
按钮切换到暗/亮模式时, 我的项目列表会正确显示在应用程序的UI中 *。但是,当我点击设备上的light/dark mode
按钮时,我注意到logcat中出现以下错误消息。
这是我的片段
class AllScoresFragment : Fragment() {
companion object {
var ScoreListASF : ArrayList<Score> = ArrayList()
}
//configure private lateinit vars
private lateinit var binding: FragmentAllScoresBinding
private lateinit var viewModel: AllScoresViewModel
private lateinit var recyclerView: RecyclerView
private lateinit var adapter : AdapterForScoreListForAllScoreFragmentForRecyclerView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentAllScoresBinding.inflate(inflater)
return binding.root)
}
@Deprecated("Deprecated in Java")
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
//initiate my viewModel
viewModel = ViewModelProvider(this)[AllScoresViewModel::class.java]
//create the observer which updates the UI
val liveScoreObserver = Observer<ArrayList<Score>>{
//update the UI
ScoreListASF = it
}
//let the observer observe my livedata through viewModel
viewModel.liveScores(context).observe(this.viewLifecycleOwner, liveScoreObserver)
//configure recyclerview for layout in this Fragment
recyclerView = binding.include.recyclerViewForScoreContent
recyclerView.setHasFixedSize(true)
recyclerView.setItemViewCacheSize(100)
recyclerView.layoutManager = LinearLayoutManager(this.context)
recyclerView.isVerticalScrollBarEnabled = true
adapter =
context?.let { AdapterForScoreListForAllScoreFragmentForRecyclerView(it, ScoreListASF) }!!
recyclerView.adapter = adapter
//configure what happens when the layout is swiped to be refreshed
val swipeToRefresh = binding.swipeToRefresh
binding.swipeToRefresh.setOnRefreshListener {
viewModel.liveScores(context).observe(this.viewLifecycleOwner, liveScoreObserver)
swipeToRefresh.isRefreshing = false
}
}
}
这是视图模型:
class AllScoresViewModel () : ViewModel() {
private val getOnlineData: GetOnlineData = GetOnlineData()
fun liveScores(context: Context?): LiveData<ArrayList<Score>> = liveData {
val data = getOnlineData.retrieveScore(context)
emit(data)
}
}
这是GetOnlineData类别:
sealed class Result<out R> {
data class Success<out T>(val data: T) : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()
}
class GetOnlineData {
suspend fun retrieveScore(context: Context?) : ArrayList<Score> {
val tempList = ArrayList<Score>()
//create and show a progress dialog; hide it when the process is done
val progressDialog = ProgressDialog(context)
progressDialog.setMessage("Loading...")
progressDialog.show()
// Get a RequestQueue
AllScoresFragment().context?.let { MySingleton.getInstance(it).requestQueue }
//run newtwork jsonRequest on background thread to avoid ANR
//retrieve json objects and add each object-set to the ArrayList<Score>()
return withContext(Dispatchers.IO){
val url = "https://..."
val jsonArrayRequest = JsonArrayRequest(
Request.Method.GET, url, null,
{ response ->
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 = url + thumbnailUrl,
pdf_url = url + pdfUrl
)
tempList.add(score)
}
//just to show/know that i get the response: all 'scores' added
//this toast shows up every single time, meaning that i get the response
Toast.makeText(context,
"success getting scores: $tempList",
Toast.LENGTH_LONG).show()
Result.Success("success getting scores: $tempList")
//hide the progress dialog upon getting response
progressDialog.hide()
} catch (e : JSONException){
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
Result.Error(e)
//hide the progress dialog upon getting error
progressDialog.hide()
}
},
{ error ->
Toast.makeText(context,
error.message,
Toast.LENGTH_SHORT)
.show()
Result.Error(error)
progressDialog.hide()
}
)
// Access the RequestQueue through my singleton class.
context?.let { MySingleton.getInstance(it).addToRequestQueue(jsonArrayRequest) }
return@withContext tempList
}
}
}
怎么回事?我做错了什么?
这就是我要做的:
1.在后台线程中从https源获取jsonArray
。
1.将所有检索到的jsonObjects
添加到ArrayList
。
1.当我的应用程序启动或滑动刷新时,使用RecyclerView
将此ArrayList
显示给UI
。
请帮帮我。我做错了什么?我会非常感激得到一个解决方案
目前编辑次数:
我编辑的片段要容纳DiffUtil
:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProvider(this)[AllScoresViewModel::class.java]
ScoreListASF = ArrayList()
//create the observer which updates the UI
val liveScoreObserver = Observer<ArrayList<Score>>{ scoreArrayList ->
//oldList
ScoreListASF = ArrayList()
//get the new list from the observer and call the adapter.insert()
// for DiffUtil to do its thing
val newList = scoreArrayList
adapter.insertItem(newList)
//tried using notifyDataSetChanged(), did not work
//adapter.notifyDataSetChanged()
}
//observe the livedata
viewModel.liveScores(context).observe(this.viewLifecycleOwner, liveScoreObserver)
//configure recyclerview for layout in SongFragment
recyclerView = binding.include.recyclerViewForScoreContent
recyclerView.setHasFixedSize(true)
recyclerView.setItemViewCacheSize(100)
recyclerView.layoutManager = LinearLayoutManager(this.context)
recyclerView.isVerticalScrollBarEnabled = true
adapter =
context?.let { AdapterForScoreListForAllScoreFragmentForRecyclerView(it, ScoreListASF) }!!
recyclerView.adapter = adapter
//what happens when swipe to refresh is initiated
val swipeToRefresh = binding.swipeToRefresh
binding.swipeToRefresh.setOnRefreshListener {
viewModel.liveScores(context).observe(this.viewLifecycleOwner, liveScoreObserver)
swipeToRefresh.isRefreshing = false
}
}
这是recyclerView的适配器:
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
}
//the function to insert the new list to let DiffUtil do its thing
fun insertItem(newItemList: ArrayList<Score>){
//should i clear the list before adding newList?
//scoreList.clear()
val diffUtil = MyDiffUtil(scoreList, newItemList)
val diffResult : DiffUtil.DiffResult = DiffUtil.calculateDiff(diffUtil)
scoreList.addAll(newItemList)
diffResult.dispatchUpdatesTo(this)
}
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
Glide
.with(holder.pdfThumbnailImage)
.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)
}
}
}
这是DiffUtil类别:
class MyDiffUtil(
private val oldListYeah : ArrayList<Score>,
private val newListYeah : ArrayList<Score>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldListYeah.size
}
override fun getNewListSize(): Int {
return newListYeah.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldItemPosition == newItemPosition
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldListYeah[oldItemPosition] == newListYeah[newItemPosition]
}
}
1条答案
按热度按时间uxhixvfz1#
所以我用
Retrofit
和DiffUtil
计算出了这个问题。任何想知道这个问题的完整详细解决方案的人都可以给我发邮件:jditechnet@gmail.com
.它现在工作得很完美!!感谢所有做出贡献的人。