第一行代码第三版天气预告,在adapter里没法正常引用xml的id。
activity.weather.xml, 用于滑动显示子控件内容
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.weather.WeatherActivity">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:id="@+id/weatherLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
android:scrollbars="none"
android:visibility="invisible">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/now" />
<include layout="@layout/forecast" />
<include layout="@layout/life_index" />
</LinearLayout>
</ScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundGravity="left"
android:clickable="true"
android:focusable="true"
android:background="@color/colorPrimary">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/placeFragment"
android:name="com.example.sunnyweather2.ui.place.PlaceFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="25dp"/>
</FrameLayout>
</androidx.drawerlayout.widget.DrawerLayout>
weatherActivity.kt 滑动菜单的逻辑,
package com.example.sunnyweather2.ui.weather
import android.content.Context
import android.icu.text.SimpleDateFormat
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.RelativeLayout
import android.widget.ScrollView
import android.widget.TextView
import android.widget.Toast
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.example.sunnyweather2.R
import com.example.sunnyweather2.logic.model.Weather
import com.example.sunnyweather2.logic.model.getSky
import java.util.Locale
class WeatherActivity : AppCompatActivity() {
val viewModel by lazy {
ViewModelProvider(this)[WeatherViewModel::class.java]
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_weather)
val drawerLayout: DrawerLayout = findViewById(R.id.drawerLayout)
val navBtn: Button = findViewById(R.id.navBtn)
navBtn.setOnClickListener {
drawerLayout.openDrawer(GravityCompat.START)
}
drawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener {
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {}
override fun onDrawerOpened(drawerView: View) {}
override fun onDrawerStateChanged(newState: Int) {}
override fun onDrawerClosed(drawerView: View) {
val manager = getSystemService(Context.INPUT_METHOD_SERVICE)
as InputMethodManager
manager.hideSoftInputFromWindow(
drawerView.windowToken,
InputMethodManager.HIDE_NOT_ALWAYS
)
}
})
PlaceAdapter.kt 对PlaceFragment所处的activity进行判断,如果是在weatheractivity中,那关闭滑动菜单,给weatheractivity赋新值并刷新天气信息;如果是在mainactivity中,保持之前的处理逻辑不变,不过这里drawerLayout爆红,应该怎么处理。
我有试过在weatheracitvity把val drawerLayout: DrawerLayout = findViewById(R.id.drawerLayout)放在全局,drawerLayout虽然能正常写了,但运行起来就闪退,日志提示到findViewbyld这里错误

在if判断中添加实例,点击又没反应,

PlaceAdapter.kt
package com.example.sunnyweather2.ui.place
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.RecyclerView
import com.example.sunnyweather2.MainActivity
import com.example.sunnyweather2.R
import com.example.sunnyweather2.logic.model.Place
import com.example.sunnyweather2.ui.weather.WeatherActivity
class PlaceAdapter(private val fragment: PlaceFragment, private val placeList: List<Place>) :
RecyclerView.Adapter<PlaceAdapter.ViewHolder>() {
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val placeName: TextView = view.findViewById(R.id.placeName)
val placeAddress: TextView = view.findViewById(R.id.placeAddress)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(
R.layout.place_item,
parent, false
)
val holder = ViewHolder(view)
holder.itemView.setOnClickListener {
val position = holder.bindingAdapterPosition
val place = placeList[position]
val activity = fragment.activity
if (activity is WeatherActivity) {
activity.drawerLayout.closeDrawers()
activity.viewModel.locationLng = place.location.lng
activity.viewModel.locationLat = place.location.lat
activity.viewModel.placeName = place.name
activity.refreshWeather()
} else {
val intent = Intent(parent.context, WeatherActivity::class.java).apply {
putExtra("location_lng", place.location.lng)
putExtra("location_lat", place.location.lat)
putExtra("place_name", place.name)
}
fragment.startActivity(intent)
fragment.activity?.finish()
}
fragment.viewModel.savePlace(place)
}
return holder
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val place = placeList[position]
holder.placeName.text = place.name
holder.placeAddress.text = place.address
}
override fun getItemCount() = placeList.size
}
在Adapter里引用activity的布局id需要使用activity的上下文。你可以在Adapter的构造方法中接收一个上下文参数,然后使用findViewById来获取id:
kotlin
class PlaceAdapter(
private val fragment: PlaceFragment,
private val placeList: List<Place>,
private val context: Context // 上下文参数
) :
RecyclerView.Adapter<PlaceAdapter.ViewHolder>() {
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val placeName: TextView = view.findViewById(R.id.placeName)
val placeAddress: TextView = view.findViewById(R.id.placeAddress)
val drawerLayout: DrawerLayout = context.findViewById(R.id.drawerLayout) // 使用上下文找到id
}
然后在创建Adapter的时候传入activity的上下文:
kotlin
val adapter = PlaceAdapter(placeFragment, viewModel.placeList, this) // 传入this作为上下文
这么做就可以在Adapter里正常使用activity的布局id了。
你说的把drawerLayout定义为全局变量的方法有个问题,那样做会导致Activity的生命周期里的onDestory方法无法调用drawerLayout的清理方法,容易导致内存泄漏。所以最好的方法还是在Adapter中通过上下文参数获取activity的实例,而不是全局持有activity的实例。