英文:
No adapter attached; skipping layout. Error with Recycler View
问题
以下是您要翻译的部分:
In my app I integrate rest api to show weather at life time, and I have problems to bind viewmodel and Recyclerview adapter in fragment to get final result and show weather. I have successful response, so I don't have problems with it.
Also I integrate locations permissions, maybe errors could be of this.
Here is the code of my xml layout and logic.
data class WeatherCurrentResponse(
@SerializedName("latitude")
var lat :Double,
@SerializedName("longitude")
var lon:Double,
@SerializedName("current_weather")
var weathercurrent:CurrentWeather,
)
data class CurrentWeather(
val time: LocalDateTime,
@SerializedName("temperature")
val temp : Int
)
@HiltViewModel
class WeatherViewModel @Inject constructor(private val repository: CurrentRepository,
private val location: TrackLocation ):ViewModel() {
private val _weatherstate = MutableLiveData<Response<WeatherCurrentResponse>>()
val weatherstate:LiveData<Response<WeatherCurrentResponse>> = _weatherstate
fun displayweatherbylocation() {
viewModelScope.launch {
try {
location.getCurrentlocation()?.let {
loc->
val result = repository.getCurrentWeather(loc.latitude,loc.longitude)
_weatherstate.value = result
}
}catch (e:ViewmodelException){
Log.d("VM EXCEPTION","Check viewmodel probably nullpointexcept")
}
}
}
}
class CurrentWeatherRecView
:RecyclerView.Adapter<CurrentWeatherRecView.WeatherListHolder>() {
var weatherlist = ArrayList<WeatherCurrentResponse>()
inner class WeatherListHolder(itemView:View) :RecyclerView.ViewHolder(itemView){
fun bind(data:WeatherCurrentResponse){
itemView.findViewById<TextView>(R.id.tempcurrent).text =
data.weathercurrent.temp.toString()
itemView.findViewById<TextView>(R.id.time).text = data.weathercurrent.time.format(
DateTimeFormatter.ofPattern("yyyy/MM/dd")
)
itemView.findViewById<TextView>(R.id.city).text =
data.lat.compareTo(data.lon).toString()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WeatherListHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.forecast_items,parent,
false)
return WeatherListHolder(view)
}
override fun getItemCount(): Int {
return weatherlist.size
}
override fun onBindViewHolder(holder: WeatherListHolder, position: Int) {
weatherlist[position].let {
holder.bind(data = it)
}
}
fun updateInfo(list:ArrayList<WeatherCurrentResponse>){
weatherlist.clear()
weatherlist.addAll(list)
notifyDataSetChanged()
}
}
@AndroidEntryPoint
class ListWeatherFragment : Fragment() {
lateinit var recView:RecyclerView
private lateinit var binding:FragmentListWeatherBinding
private val viewModel:WeatherViewModel by viewModels()
private lateinit var permissionlauncher:ActivityResultLauncher<Array<String>>
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentListWeatherBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
permissionlauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
){
recView = binding.recviewInFragment
recView.apply {
layoutManager = LinearLayoutManager(context,LinearLayoutManager.VERTICAL,
false)
val weatheradapter = CurrentWeatherRecView()
adapter = weatheradapter
viewModel.displayweatherbylocation()
viewModel.weatherstate.observe(viewLifecycleOwner) {
data->
data.body()?.let {
weatheradapter.updateInfo(
list = ArrayList()
)
}
}
}
}
permissionlauncher.launch(arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
))
}
}
英文:
In my app I integrate rest api to show weather at life time , and I have problems to bind viewmodel and Recyclerview adapter in fragment to get final result and show weather. I have successful response , so I don't have problems with it.
Also I integrate locations permissions , maybe errors could be of this.
Here is the code of my xml layout and logic.
data class WeatherCurrentResponse(
@SerializedName("latitude")
var lat :Double,
@SerializedName("longitude")
var lon:Double,
@SerializedName("current_weather")
var weathercurrent:CurrentWeather,
)
data class CurrentWeather(
val time: LocalDateTime,
@SerializedName("temperature")
val temp : Int
)
@HiltViewModel
class WeatherViewModel @Inject constructor(private val repository: CurrentRepository,
private val location: TrackLocation ):ViewModel() {
private val _weatherstate = MutableLiveData<Response<WeatherCurrentResponse>>()
val weatherstate:LiveData<Response<WeatherCurrentResponse>> = _weatherstate
fun displayweatherbylocation() {
viewModelScope.launch {
try {
location.getCurrentlocation()?.let {
loc->
val result = repository.getCurrentWeather(loc.latitude,loc.longitude)
_weatherstate.value = result
}
}catch (e:ViewmodelException){
Log.d("VM EXCEPTION","Check viewmodel probably nullpointexcept")
}
}
}
}
class CurrentWeatherRecView
:RecyclerView.Adapter<CurrentWeatherRecView.WeatherListHolder>() {
var weatherlist = ArrayList<WeatherCurrentResponse>()
inner class WeatherListHolder(itemView:View) :RecyclerView.ViewHolder(itemView){
fun bind(data:WeatherCurrentResponse){
itemView.findViewById<TextView>(R.id.tempcurrent).text =
data.weathercurrent.temp.toString()
itemView.findViewById<TextView>(R.id.time).text = data.weathercurrent.time.format(
DateTimeFormatter.ofPattern("yyyy/MM/dd")
)
itemView.findViewById<TextView>(R.id.city).text =
data.lat.compareTo(data.lon).toString()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WeatherListHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.forecast_items,parent,
false)
return WeatherListHolder(view)
}
override fun getItemCount(): Int {
return weatherlist.size
}
override fun onBindViewHolder(holder: WeatherListHolder, position: Int) {
weatherlist[position].let {
holder.bind(data = it)
}
}
fun updateInfo(list:ArrayList<WeatherCurrentResponse>){
weatherlist.clear()
weatherlist.addAll(list)
notifyDataSetChanged()
}
}
@AndroidEntryPoint
class ListWeatherFragment : Fragment() {
lateinit var recView:RecyclerView
private lateinit var binding:FragmentListWeatherBinding
private val viewModel:WeatherViewModel by viewModels()
private lateinit var permissionlauncher:ActivityResultLauncher<Array<String>>
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentListWeatherBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
permissionlauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
){
recView = binding.recviewInFragment
recView.apply {
layoutManager = LinearLayoutManager(context,LinearLayoutManager.VERTICAL,
false)
val weatheradapter = CurrentWeatherRecView()
adapter = weatheradapter
viewModel.displayweatherbylocation()
viewModel.weatherstate.observe(viewLifecycleOwner) {
data->
data.body()?.let {
weatheradapter.updateInfo(
list = ArrayList()
)
}
}
}
}
permissionlauncher.launch(arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
))
}
}
答案1
得分: 0
Instead of giving the result to your RecyclerViewAdapter
, you always give a new empty list list = ArrayList()
. You must use the received body inside your let
-block to update the RecyclerViewAdapter
.
viewModel.weatherstate.observe(viewLifecycleOwner) { data ->
data.body()?.let { body ->
weatheradapter.updateInfo(list = body)
}
}
You can simplify your Adapter by using ListAdapter. It will manage updating the list and animate any changes (see also DiffCallback for better update handling).
英文:
Here is the problem:
viewModel.weatherstate.observe(viewLifecycleOwner) {
data->
data.body()?.let {
weatheradapter.updateInfo(
list = ArrayList()
)
}
}
Instead of giving the result to your RecyclerViewAdapter
, you always give a new empty list list = ArrayList()
. You must use the received body inside your let
-block to update the RecyclerViewAdapter
.
viewModel.weatherstate.observe(viewLifecycleOwner) {
data->
data.body()?.let { body ->
weatheradapter.updateInfo(
list = body
)
}
}
You can simplify your Adapter by using ListAdapter. It will manage updating the list and animate any changed (see also DiffCallback for better update handling).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论