android - 使用ViewModel和LiveData改造执行API多次

标签 android api mvvm retrofit android-livedata

因此,当我执行操作单击以请求API GET时,我遇到了一个问题,我多次使用MVVM和LiveData组合从API获取值时,多次击中了端点。
下面的代码
ApiService.kt

   class ApiService {
       private var retrofit : Retrofit? = null
       private val okHttpBuilder = OkHttpClient.Builder()
           .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
           .connectTimeout(120, TimeUnit.SECONDS)
           .readTimeout(120, TimeUnit.SECONDS)
           .writeTimeout(120, TimeUnit.SECONDS)
           .retryOnConnectionFailure(false)
           .build()
   
   
       fun <S> createService(serviceClass: Class<S>?): S {
           if(retrofit == null){
               retrofit = Retrofit.Builder().addConverterFactory(GsonConverterFactory.create())
                   .baseUrl(BASE_URL)
                   .client(okHttpBuilder)
                   .build()
           }
           return retrofit!!.create(serviceClass!!)
       }
     

      val serviceGuestMerchants : GuestMerchantsService by lazy{
          createService(GuestMerchantsService::class.java)
      }
   }
介面
GuestMerchantService.kt
    interface GuestMerchantsService {
        @GET(ConstantGuestMerchants.BASE_URL_GUEST_MERCHANT)
        suspend fun getListMerchant(@Query("page") page :Int?, @Query("order-direction") orderDirection : 
        String) : ResponseListMerchant
    
        @GET(ConstantGuestMerchants.BASE_URL_GUEST_MERCHANT_DETAIL)
        suspend fun getPreviewMerchant(@Path("id") id:Int) : ResponsePreviewMerchant
    
        @GET(ConstantGuestMerchants.BASE_URL_GUEST_MERCHANT_PRODUCT_LIST)
        suspend fun getListProductByMerchant(
            @Path("id") id : Int,
            @Query("page") page : Int?) : ResponseProductByMerchant
    
        @GET(ConstantGuestMerchants.BASE_URL_GUEST_MERCHANT_STATUS)
        suspend fun getStatusMerchant(@Header("Authorization") authorization : String) : 
        ResponseGetStatusMerchant
    
        @Multipart
        @POST(ConstantGuestMerchants.BASE_URL_GUEST_MERCHANT_REQUEST_MERCHANT)
        fun registerMerchant(@Header("Authorization") authorization: String,
                             @Part fotoKtp : MultipartBody.Part, @Part fotoPemilik : MultipartBody.Part, 
                             @Part fotoToko : MultipartBody.Part,
                             @Part namaToko : MultipartBody.Part,@Part noHp : MultipartBody.Part ,
                             @Part alamat : MultipartBody.Part, @Part noKtp : MultipartBody.Part) : Call<ResponseRegisterMerchant>
    
        @DELETE(ConstantGuestMerchants.BASE_URL_GUEST_MERCHANT)
        fun deleteRequestMerchant(@Header("Authorization") authorization : String) : 
        Call<ResponseDeleteReqMerchant>
    }
View 模型
ProfileViewModel.kt
    class ProfileViewModel : ViewModel(){
    
        private val _profile = MutableLiveData<Profile>()
        val profile : LiveData<Profile>
                get() = _profile
    
        private val _status = MutableLiveData<ApiStatus>()
        val status : LiveData<ApiStatus>
            get() = _status
    
        private suspend fun getProfileUser(token : String){
            try {
                _status.postValue(ApiStatus.LOADING)
                val apiService = ApiService().serviceProfileUser
                _profile.postValue(apiService.getProfile(token).data)
                _status.postValue(ApiStatus.SUCCESS)
            }catch (e : Exception){
                Log.d("REQ_PROF_USR_FAIL", e.localizedMessage!!)
                _status.postValue(ApiStatus.FAILED)
            }
        }
    
        fun getDataProfileUser(token : String){
            viewModelScope.launch {
                getProfileUser(token)
            }
        }
    
    }
执行 Action 以从ViewModel调用函数的片段
CustomerProfileFragment.kt
    class CustomerProfileFragment : Fragment() {
    
        private lateinit var adapter: AdapterUtil<ProfileMenuItem>
        private lateinit var binding: FragmentCustomerProfileBinding
        private lateinit var cacheUtil: CacheUtil
        private var auth : Login? = null
        private val viewModel : ProfileViewModel by lazy {
            ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(ProfileViewModel::class.java)
        }
    
        private val viewModelRegisterMerchant: RegisterMerchantViewModel by lazy {
            ViewModelProvider(
                this,
                ViewModelProvider.NewInstanceFactory()
            ).get(RegisterMerchantViewModel::class.java)
        }
    
        override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            //binding init
            binding = FragmentCustomerProfileBinding.inflate(inflater, container, false)
            // Setup Cache
            cacheUtil = CacheUtil()
            cacheUtil.start(context as Activity, ConstantAuth.PREFERENCES)
            // Setup Title
            (activity as AppCompatActivity?)!!.setSupportActionBar(binding.toolbar)
            binding.toolbar.title = getString(R.string.akun_saya)
    
            //After Login
            if (getAuth(cacheUtil).token!!.isNotEmpty()) {
                auth = getAuth(cacheUtil)
                Log.d("TOKEN NYA TOKEN", "${auth!!.token} TOKEN NYA TOKEN PROFILE")
                binding.llLogin.visibility=View.GONE
                setupProfileMenu()
                binding.tvRegistrasi.setOnClickListener {
                    startActivity(Intent(context, RegisterUserActivity::class.java))
                }
                //login
                binding.tvLogin.setOnClickListener {
                    startActivity(Intent(context, LoginActivity::class.java))
                }
    
    
                //Logout
                binding.tvLogout.setOnClickListener {
                    this.cacheUtil.clear()
                    startActivity(Intent(requireContext(), MainActivity::class.java))
                    requireActivity().finish()
                }
                binding.imFotoProfil.setOnClickListener {
                    ImagePicker.create(this)
                        .single()
                        .start()
                }
    
                //edit photo profile
            }else{
                binding.tvNamaAkun.text = ""
                binding.tvEmailAkun.text = ""
                Glide.with(requireContext()).load(R.drawable.ic_baseline_account_circle_24).into(binding.imFotoProfil)
            }
    
            return binding.root
        }
    
        private fun setupProfileMenu(){
            //Setup Profil Menu
            binding.rvIconmenu.layoutManager = LinearLayoutManager(context)
            adapter =
                AdapterUtil(R.layout.item_list_menu_akun,
                    listOf(
                        ProfileMenuItem(
                            "Saldo Saya",
                            R.drawable.ic_monetization
                        ),
                        ProfileMenuItem(
                            "Pusat Bantuan",
                            R.drawable.ic_help_outline
                        ),
                        ProfileMenuItem(
                            "Chat dengan Leh-Oleh",
                            R.drawable.ic_chat
                        ),
                        ProfileMenuItem(
                            "Beri Kami Nilai",
                            R.drawable.ic_star_border
                        ),
                        ProfileMenuItem(
                            "Toko Saya",
                            R.drawable.ic_store
                        )
                    ), { position, itemView, item ->
                        itemView.tv_menu!!.text = item.label
                        itemView.im_akun_icon!!.setImageResource(item.icon)
                        itemView.im_chevron_right.setImageResource(R.drawable.ic_chevron_right)
                    }, { position, item ->
                        when (position) {
                            0 -> startActivity(
                                Intent(
                                    context,
                                    CustomerSaldoSayaActivity::class.java
                                )
                            )
                            1 -> startActivity(
                                Intent(
                                    context,
                                    BantuanActivity::class.java
                                )
                            )
                            4 -> {
                                viewModelRegisterMerchant.getDataStatusMerchant(auth!!.token!!)
                                viewModelRegisterMerchant.statusMerchant.observe(
                                    viewLifecycleOwner,
                                    Observer {
                                        if (it.isVisible!!.isNotEmpty()) {
                                            if (it.isVisible == "1") {
                                                //findNavController().navigate(R.id.action_navigation_register_toko_to_navigation_toko_saya)
                                                startActivity(Intent(requireContext(), MerchantTokoSayaActivity::class.java))
                                            }
                                        } else {
                                            Log.d("DATA_STATUS", "BELUM LOGIN")
                                        }
    
                                    })
                            }
                        }
    //                    2 -> startActivity(Intent(context, ProductListActivity::class.java))
    //                    3 -> startActivity(Intent(context, ProductListActivity::class.java))
                    })
            binding.rvIconmenu.adapter = adapter
        }
    
      
    
        override fun onResume() {
            viewModel.getDataProfileUser(auth!!.token!!)
            super.onResume()
        }
    }
注意,当调用viewModelRegisterMerchant并进行观察时,该意图执行了多次,当我看到Logcat时,该端点也被执行了多次。
我以为观察者会不断更新数据,但我不知道怎么可能
另一个类使其更清晰
启动意图时多次调用的类
MerchantTokoSaya.kt
    class MerchantTokoSayaActivity : AppCompatActivity() {
        private lateinit var binding : ActivityMerchantTokoSayaBinding
        private lateinit var auth: Login
        private val viewModel : ProfileTokoViewModel by lazy {
            ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(ProfileTokoViewModel::class.java)
        }
        private lateinit var cacheUtil: CacheUtil
        private lateinit var adapter: AdapterUtil<ProfileMenuItem>
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            binding = ActivityMerchantTokoSayaBinding.inflate(layoutInflater)
            setContentView(binding.root)
            cacheUtil = CacheUtil()
            cacheUtil.start(this, ConstantAuth.PREFERENCES)
            if (getAuth(cacheUtil).token!!.isNotEmpty()) {
                auth = getAuth(cacheUtil)
                Log.d("TOKEN NYA TOKEN", "${auth.token} TOKEN NYA TOKEN")
                getDataProfileToko()
    
                binding.tvUbahAkun.setOnClickListener {
                    val intent = Intent(this, RegisterMerchantFragment::class.java)
                    intent.putExtra(ConstantProfileMerchant.DATA_EDIT_PROFILE_TOKO, ConstantProfileMerchant.ACTION_EDIT_PROFILE_TOKO)
                    startActivity(intent)
                    finish()
                }
                title = "Toko Saya"
    
                //Setup Profil Menu
                binding.rvIconmenu.layoutManager = LinearLayoutManager(this)
                adapter =
                    AdapterUtil(R.layout.item_list_menu_akun,
                        listOf(
                            ProfileMenuItem(
                                "Kelola Barang",
                                R.drawable.ic_card_giftcard
                            ),
                            ProfileMenuItem(
                                "Kelola Pesanan",
                                R.drawable.ic_assignment
                            ),
                            ProfileMenuItem(
                                "Pesan Masuk",
                                R.drawable.ic_chat
                            ),
                            ProfileMenuItem(
                                "Keuangan",
                                R.drawable.ic_monetization
                            )
                        ), { position, itemView, item ->
                            itemView.tv_menu!!.text = item.label
                            itemView.im_akun_icon!!.setImageResource(item.icon)
                            itemView.im_chevron_right.setImageResource(R.drawable.ic_chevron_right)
                        }, { position, item ->
                            when (position) {
                                0 -> startActivity(
                                    Intent(
                                        this,
                                        MerchantKelolaBarangActivity::class.java
                                    )
                                )
                                1 -> startActivity(
                                    Intent(
                                        this,
                                        KelolaPesananActivity::class.java
                                    )
                                )
    //                    2 -> startActivity(Intent(context, ProductListActivity::class.java))
    //                    3 -> startActivity(Intent(context, ProductListActivity::class.java))
                            }
                        })
                binding.rvIconmenu.adapter = adapter
    
                //init profil picture
                binding.imFotoProfil.setImageResource(R.drawable.ic_home_black_24dp)
            }else {
                startActivity(Intent(this, LoginActivity::class.java))
            }
        }
    
        private fun getDataProfileToko(){
            viewModel.getDataProfileToko(auth.token!!)
            viewModel.toko.observe(this, Observer {
                binding.tvNamaAkun.text = it.marketName
                Glide.with(this).load(it.authorUri).circleCrop().into(binding.imFotoProfil)
                Glide.with(this).load(it.marketUri).into(binding.imageViewHeader)
            })
        }
    
    
    }
util类保存共享的首选项
CacheUtil.kt
    class CacheUtil {
        private var sharePref: SharedPreferences? = null
    
        fun start(activity: Activity, PREFS: String) {
            sharePref = activity.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
        }
    
        fun destroy() { this.sharePref = null }
    
        fun <T> set(PREFS: String, value: T) {
            this.sharePref?.let {
                with(it.edit()) {
                    putString(PREFS, Gson().toJson(value))
                    Log.d("CACHE UTIL", PREFS)
                    apply()
                }
            }
        }
    
        fun clear() {
            this.sharePref?.edit()?.clear()?.apply()
        }
    
        fun get(PREFS: String): String? {
            if (sharePref != null) return sharePref!!.getString(PREFS, null)
            return null
        }
    }
RegisterMerchantViewModel.kt
    class RegisterMerchantViewModel : ViewModel(){
    
        private val _statusMerchant = MutableLiveData<DataGetStatusMerchant>()
        val statusMerchant : LiveData<DataGetStatusMerchant>
            get() = _statusMerchant
    
        private val _status = MutableLiveData<ApiStatus>()
        val status : LiveData<ApiStatus>
            get() = _status
    
    
        private val apiService = ApiService().serviceGuestMerchants
    
        fun getDataStatusMerchant(token: String) {
            viewModelScope.launch {
                getStatusMerchant(token)
            }
        }
    
        private suspend fun getStatusMerchant(token: String) {
            try {
                _status.postValue(ApiStatus.LOADING)
                _statusMerchant.postValue(apiService.getStatusMerchant(token).data)
                _status.postValue(ApiStatus.SUCCESS)
            } catch (e: Exception) {
                Log.d("ERROR_REQ_STATUS", e.localizedMessage!!)
                _status.postValue(ApiStatus.FAILED)
            }
    
        }
    
    
    }

最佳答案

我解决了这个问题,所以我将oncreateView内的所有代码移到onviewcreated上,并将viewModelRegisterMerchant.getDataStatusMerchant(auth !!。token !!)移到项目外部。

关于android - 使用ViewModel和LiveData改造执行API多次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64790099/

相关文章:

android - 自定义透明对话框(windowBackground 不存在?)

android - "Up"的正确处理方式 Navigation according to guidelines

api - 从 Google Play 获取应用详细信息

html - OAuth 在 iframe 中不起作用

c# - MVVM 解决方案结构

php - 使用 PHP 向钛(跨平台)开发的 android 应用程序发送推送通知

android - React Native 添加 Picker 数组

api - 如何代表卖家使用亚马逊产品广告 API

wpf - 将 <object property ="{StaticResource key}".../> 中的 Key 绑定(bind)到一个值

c# - WPF:单击按钮打开新窗口