1

我很难在我的应用程序中实现正确的导航结构。我希望它的行为类似于 YouTube 和 Instagram 中的导航。我遇到的最大问题是 backstack 和片段娱乐。

我目前正在使用具有多个片段方法的单个活动。我有一个应用栏和底部导航视图,在主要活动中设置了 3 个菜单项。应用栏有一个菜单项,在选中时导航到用户配置文件片段,并且底部导航的每个菜单项在选中时导航到不同的根片段(主页、搜索和配置文件)。我还使用 google 的 firebase 数据库和 firestore 来存储用户数据(电子邮件、uid、密码等)和照片。

我尝试使用 supportFragmentManager.beginTransaction().replace 方式和 android jetpack 的导航架构,但都无法产生我需要的结果。

我能够使用 supportFragmentManager 方式导航到正确的目的地,但似乎无法实现正确的向后导航结构。我试图找到实现它的其他代码示例,但找不到任何可行的方法,并且这些示例中的很多都是 Java 代码中的旧版本,带有不推荐使用的方法,这使得在尝试转换为 kotlin 代码时变得困难。

喷气背包导航组件更容易使用,但我也无法让它正常运行。据我所知,当前导航不支持多个 backstacks,并且没有适当的向后导航结构,除非您添加此处提供的 NavigationExtensions 文件:https ://github.com/googlesamples/android-architecture-components/tree/master/导航高级示例。使用此示例,我遇到了以下问题:

1.向后导航不会回到原来保存的fragment状态,而是重新创建一个全新的fragment。

2.从应用栏导航到配置文件片段有效,但是当用户在片段内并再次按下它时会崩溃。

3.将一组默认参数传递给底部导航视图中的用户片段项目菜单。我最初将帐户配置文件片段绑定到底部导航菜单项(仍用于测试目的),并将登录用户的 uid 设置为默认参数。使用的片段(UserFragment)采用 uid 参数并使用它从 google 的 firebase 获取正确的信息。我以前可以通过使用常规的喷气背包导航组件(没有高级示例)并在 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 方法轻松应用包和参数。

TL;博士

总结一切:我正在寻找一种方法来在我的应用程序中实现正确的导航流程。我在向后导航和不应该重新创建片段时遇到问题。我尝试过使用片段管理器和 android jetpack 导航组件,但都没有运气。如果有人有任何关于如何使用 android kotlin 和最新方法实现这一点的信息,并愿意分享,我将不胜感激。

谢谢。

4

0 回答 0