我在应用程序中难以实现适当的导航结构。我希望它的行为类似于YouTube和Instagram中的导航。我遇到的最大问题是与堆栈和碎片娱乐有关。
我目前正在使用具有多个片段的单一活动方法。我在主活动中有一个应用程序栏和底部导航视图,其中包含3个菜单项。应用程序栏上有一个菜单项,该菜单项在被选中时可导航到用户个人资料片段,而底部导航栏的每个菜单项在被选择时均可导航到不同的根片段(家庭,搜索和个人资料)。我还使用Google的firebase数据库和firestore来存储用户数据(电子邮件,uid,密码等)和照片。
我尝试过使用supportFragmentManager.beginTransaction()。replace方式和android jetpack的导航架构,但是都无法产生我需要的结果。
我能够使用supportFragmentManager方法导航到正确的目的地,但是似乎无法实现正确的向后导航结构。我试图找到实现此目的的其他代码示例,但是找不到任何有效的方法,并且这些示例中有很多都是Java代码中使用较旧方法的较旧版本,这在尝试转换为kotlin代码时很困难。
jetpack导航组件更易于使用,但我也无法使其正常运行。据我所知,当前的导航不支持多个堆栈,并且没有适当的向后导航结构,除非您添加此处提供的NavigationExtensions文件:https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample。使用此示例,我遇到以下问题:
1。向后导航不会返回原始保存的片段状态,而是重新创建一个全新的片段。
2。从应用程序栏导航到个人资料片段是可行的,但是当用户位于片段中并再次按下时会崩溃。
3。在底部导航视图中,将一组默认参数传递给用户片段项目菜单。我最初将帐户配置文件片段绑定到底部的导航菜单项(出于测试目的仍然这样做),并且将登录用户的uid设置为默认参数。使用的fragment(UserFragment)采用uid参数,并使用它从Google的firebase中获取适当的信息。我以前可以通过使用常规的jetpack导航组件(不带高级示例)并在MainActivity中添加以下代码来实现此目的:
val navArgument1 = NavArgument.Builder().setDefaultValue(uid).build()
val orderDestination = navController.graph.findNode(R.id.user_Fragment)
orderDestination?.addArgument("destinationUid",navArgument1)
然后在用户片段中,我使用以下代码获取正确的uid:
uid = arguments?.getString("destinationUid")
使用高级示例导航组件,我无法将此默认参数传递给用户片段。我不断收到类似“没有与此片段关联的导航控制器”之类的错误,并且应用程序崩溃。
class ExploreActivity : AppCompatActivity(),BottomNavigationView.OnNavigationItemSelectedListener{
override fun onNavigationItemSelected(p0:MenuItem):Boolean{
when(p0.itemId){
R.id.home->{
val homeViewFragment = HomeViewFragment()
supportFragmentManager.beginTransaction().replace(R.id.nav_host_fragment,homeViewFragment).commit()
return true
}
R.id.world->{
val publicViewFragment = PublicViewFragment()
supportFragmentManager.beginTransaction().replace(R.id.nav_host_fragment,publicViewFragment).commit()
return true
}
R.id.account->{
val userFragment = UserFragment()
val bundle = Bundle()
val uid=FirebaseAuth.getInstance().currentUser?.uid
bundle.putString("destinationUid",uid)
userFragment.arguments=bundle
supportFragmentManager.beginTransaction().replace(R.id.nav_host_fragment,userFragment).commit()
return true
}
}
return false
}
override fun onCreate(savedInstanceState:Bundle?){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_explore)
bottom_navigation_explore.setOnNavigationItemSelectedListener(this)
bottom_navigation_explore.selectedItemId=R.id.home
}
override fun onActivityResult(requestCode:Int,resultCode:Int,data:Intent?){
super.onActivityResult(requestCode,resultCode,data)
if(requestCode==UserFragment.PICK__PROFILE_FROM_ALBUM&&resultCode==Activity.RESULT_OK){
val imageUri=data?.data
val uid=FirebaseAuth.getInstance().currentUser?.uid
val storageRef=FirebaseStorage.getInstance().reference.child("userProfileImages")
.child(uid!!)
storageRef.putFile(imageUri!!).continueWithTask{task:Task<UploadTask.TaskSnapshot>->
return@continueWithTask storageRef.downloadUrl
}.addOnSuccessListener{uri->
val map=HashMap<String,Any>()
map["image"]=uri.toString()
FirebaseFirestore.getInstance().collection("profileImages").document(uid).set(map)
}
}
}
}
class UserFragment : Fragment(){
var fragmentView : View? = null
var firestore : FirebaseFirestore? = null
var uid : String? = null
var auth : FirebaseAuth? = null
var currentUserUid : String? = null
companion object{
var PICK__PROFILE_FROM_ALBUM = 10
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
fragmentView = LayoutInflater.from(activity).inflate(R.layout.activity_main,container,false)
uid = arguments?.getString("destinationUid")
firestore = FirebaseFirestore.getInstance()
auth = FirebaseAuth.getInstance()
currentUserUid = auth?.currentUser?.uid
return fragmentView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if(uid == currentUserUid) {
fragmentView?.btn_follow_signout_main?.text = "Signout"
fragmentView?.btn_follow_signout_main?.setOnClickListener {
activity?.finish()
startActivity(Intent(activity, LoginActivity::class.java))
auth?.signOut()
}
requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),1)
iv_createpost_main.setOnClickListener {
if (ContextCompat.checkSelfPermission(context!!, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){
startActivity(Intent(activity,CreatePost::class.java))
}
return@setOnClickListener
}
//add explanation of why permission is needed
if (ContextCompat.checkSelfPermission(context!!, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
iv_profilepicture_main.setOnClickListener {
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
activity?.startActivityForResult(intent, PICK__PROFILE_FROM_ALBUM)
}
}
}
else{
fragmentView?.btn_follow_signout_main?.text = "Follow +"
fragmentView?.btn_follow_signout_main?.setOnClickListener {
requestFollow()
}
}
getProfileImage()
getUserName()
}
private fun getProfileImage() {
firestore?.collection("profileImages")!!.document(uid!!).get().addOnCompleteListener { task ->
if(task.isSuccessful){
val url = task.result!!["image"]
if(url != null){
Glide.with(activity!!).load(url).into(iv_profilepicture_main)
}
else{
iv_profilepicture_main.setImageResource(R.drawable.ic_account)
}
}
}
}
private fun getUserName(){
firestore?.collection("users")!!.document(uid!!).get().addOnCompleteListener { task ->
if(task.isSuccessful){
val username = task.result!!["username"]
if(username != null){
activity?.setTitle("" + username)
}
}
}
}
}
我的项目当前是使用支持片段管理器进行设置的,但是我一直在使用它和导航组件之间来回尝试以使事情正常进行。
我还有其他两个片段与底部导航相关联,但是我只包含了相关代码,我认为这是我的问题所在。其他两个片段都有一个用户个人资料图片,单击该用户时,它将用户导航到所选个人资料。这些交易没有任何问题,因为我可以轻松地使用setOnClickListener方法应用捆绑包和参数。
总结所有内容:我正在寻找一种在整个应用程序中实施适当导航流程的方法。我遇到向后导航的问题,并且在不应该重新创建片段时遇到问题。我曾尝试使用片段管理器和android jetpack导航组件,但都没有运气。如果有任何人有关于如何使用android kotlin和最新方法实现此目的的信息,并且想分享,我将不胜感激。
谢谢。