问题描述
我是使用KOTLIN进行android开发的新手,我的活动包含如下图所示的片段(图像1),问题是每当我尝试将方向从potrait更改为landscape时,活动就会返回到上一个活动(就像重新启动它一样。)
我尝试将android:configChanges="orientation|screenSize|keyboardHidden"
添加到我的AndroidManifest.xml
中,它可以正常工作,但是有人说不建议使用它。
你们能告诉我还是举例说明解决此问题的最佳做法?
图像1
代码
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
title = resources.getString(R.string.title_visit)
loadFragment(VisitFragment())
navigation_menu.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
}
private val mOnNavigationItemSelectedListener =
BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.menu_visit -> {
loadFragment(VisitFragment())
title = resources.getString(R.string.title_visit)
return@OnNavigationItemSelectedListener true
}
R.id.menu_customer -> {
loadFragment(CustomerFragment())
title = resources.getString(R.string.title_customer)
return@OnNavigationItemSelectedListener true
}
R.id.menu_new_merchant -> {
loadFragment(NewMerchantFragment())
title = resources.getString(R.string.title_new_merchant)
return@OnNavigationItemSelectedListener true
}
R.id.menu_history -> {
loadFragment(HistoryFragment())
title = resources.getString(R.string.title_history)
return@OnNavigationItemSelectedListener true
}
R.id.menu_profile -> {
loadFragment(ProfileFragment())
title = resources.getString(R.string.title_profile)
return@OnNavigationItemSelectedListener true
}
}
false
}
private fun loadFragment(fragment: Fragment) {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.container,fragment)
transaction.addToBackStack(null)
transaction.commit()
}
}
VisitFragment.kt
class VisitFragment : Fragment() {
private lateinit var viewPager: ViewPager
private lateinit var tabs: TabLayout
override fun onCreateView(
inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_visit,container,false)
}
override fun onViewCreated(view: View,savedInstanceState: Bundle?) {
super.onViewCreated(view,savedInstanceState)
val fragmentAdapter = PagerAdapter(childFragmentManager)
pager.adapter = fragmentAdapter
tabs_main.setupWithViewPager(pager)
}
fun setNumber() {
val tabs = tabs_main.getTabAt(0)
val badge = tabs?.orCreateBadge
// Customize badge
badge?.number = 1
}
}
LatestVisitFragment.kt
class LatestVisitFragment : Fragment() {
lateinit var latestVisitAdapter: LatestVisitAdapter
lateinit var recyclerView: RecyclerView
private val testinstance: ArrayList<TestResponseItem> = ArrayList()
override fun onCreateView(
inflater: LayoutInflater,savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_latest_visit,savedInstanceState)
loadDataLatestVisit()
}
private fun loadDataLatestVisit(){
ApiConfig().getService()
.getUsers()
.enqueue(object : Callback<List<TestResponseItem>> {
override fun onFailure(call: Call<List<TestResponseItem>>,t: Throwable) {
Toast.makeText(context,t.localizedMessage,Toast.LENGTH_SHORT).show()
}
override fun onResponse(
call: Call<List<TestResponseItem>>,response: Response<List<TestResponseItem>>
) {
rv_latest_visit.adapter = LatestVisitAdapter(response.body())
}
})
}
}
LatestVisitAdapter.kt
class LatestVisitAdapter(val data: List<TestResponseItem>?) :
RecyclerView.Adapter<LatestVisitAdapter.MyHolder>() {
override fun onCreateViewHolder(parent: ViewGroup,viewType: Int): MyHolder {
val v =
LayoutInflater.from(parent.context).inflate(R.layout.item_latest_visit,parent,false)
return MyHolder(v)
}
override fun getItemCount(): Int = data?.size ?: 0
override fun onBindViewHolder(holder: LatestVisitAdapter.MyHolder,position: Int) {
holder.bind(data?.get(position))
}
class MyHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(get: TestResponseItem?) {
itemView.txt_merchant_name.text = get?.name
itemView.txt_owner_name.text = get?.email
val address =
"${get?.address?.street},${get?.address?.city},${get?.address?.suite},${get?.address?.zipcode}"
itemView.txt_address.text = address
}
}
}
解决方法
实际上不建议防止活动在配置更改时重新启动。
推荐的方法将通过saving and restoring UI state或using ViewModel。其中任何一种都可以解决您的问题,但是最好使用ViewModel方法。
保存和恢复UI状态
保存状态
在活动开始之前,但在发出配置更改信号之后,如果要保存活动状态,则覆盖Activity.onSaveInstanceState(Bundle)
,如果要保存片段状态,则覆盖`Fragment.onSaveInstanceState(Bundle)。
override fun onSaveInstanceState(outState: Bundle?) {
// Save your data into outState data bundle. And then make sure to
// call the super method.
super.onSaveInstanceState(outState)
}
恢复状态
由于配置更改而重新启动活动后,请还原先前保存的数据 并将其应用于用户界面。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ... inflate layout,etc...
if (savedInstanceState != null) {
// If savedInstanceState is not null,that means this activity is restoring from
// config changes. All your saved data in onSaveInstanceState() should be accessible
// from savedInstanceState bundle.
// ... restore values from savedInstanceState and apply to your views ...
} else {
// Initialize vie
}
}
使用ViewModel
这种方法是Google作为Android Jetpack库的一部分引入的相对较新的方法。
而不是覆盖onSaveInstanceState(Bundle) and checking
savedInstanceState for null,your data is persisted inside a
ViewModel`,并且可以从配置更改中保留下来。
基本
在ViewModel
中初始化数据,然后从您的活动或片段中访问它们。
class MyViewModel : ViewModel() {
var myList: List<User> = emptyList()
var currentTabIndex: Int = 0
init {
// Initialize your data here...
}
}
class MyFragment : Fragment() {
private val model by viewModels<MyViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ... inflate layout,etc...
viewPager.setCurrentItem(model.currentTabIndex,false)
// Fetch the values from `ViewModel` and apply to your fragment.
}
}
有关ViewModel
的更多信息
为了更好地使用ViewModel
,最好向official comprehensive guide学习。