آموزش های این وب سایت به صورت رایگان در دسترس است. اطلاعات بیشتر
بروز خطا
   [message]
اشتراک در سوال
رای ها
[dataList]

سوال در مورد هندل کردن دیتای API

mohammad_hasani  7 سال پیش  7 سال پیش
0 0

سلام.
وقت بخیر.

بنده آموزش های اندروید رو دیدم اما میخواستم با ساختار متفاوتی برنامه م رو بنویسم و سوالی داشتم در رابطه با هندل کردن responseی که API برمیگردونه.
من دارم MVVM استفاده میکنم. و ساختارم به این صورته که من یه درخواست میدم به API بعد یه سرویس دارم که از رتروفیت استفاده میکنه و جوابی که برمیگردونه داخل یه LiveData سیو میشه و داخل ویو ام میام اون دیتایی که برمیگرده رو observe میکنم.
حالا مساله ای داشتم اینه که وقتی مثلا یه آبجکت مشخص مثل User رو میگیرم از API مشکلی ندارم و با یه Mapper دیتای برگشتی رو به یه کلاس داخلی مثل User.kt مپ میکنم و سیوش میکنم به هر صورت. اما گاهی اوقات دیتای برگشتی دیتایی نیست که بخوام سیوش کنم الزاما. مثلا وقتی یوزر رو رجیستر میکنم فقط id یوزر برمیگرده به علاوه دو سه تا پارامتر که به یوزر ربطی نداره و فقط ازشون استفاده میکنم که بدونم صفحه بعدی ای که به کاربر باید نمایش بدم چه صفحه ای هست. حالا سوالم اینجاست که در این طور مواقع بیام یه کلاسی بسازم مثل RegisterResponse و داخل اون بریزم و با اون یه آبجکت یوزر بسازم. یا کار بهتری هست.
چون مشکلی با کار بالا هم دارم اینه که من یه UserRepository دارم که انتظار داره جواب برگشتی سرور از نوع UserEntity باشه مثلا که این کلاس یه متد داره به نام ToUser و یه آبجکت یوزر بهم برمیگردونه. اما تو این موردهای خاص من همچین چیزی رو نمیخوام. میخوام هم یه یوزر بسازم (فقط id یوزر بهم برگشت داده میشه اما باید سیو بشه) هم مثلا اون دوتا فیلد رو بگیرم و با توجه بهشون کاری انجام بدم.
حالا اون دوتا فیلد رو پیشنهادی دارین که بتونم بگیرم و کارمو باهاشون انجام بدم.
کد پایین ممکنه مشکلات جزئی داشته باشه. یه سری کلاسم استفاده میکنه که خیلی طولانی میشد اگه میخواستم همشون رو بذارم.
اما فکر میکنم کلیت پروسه رو میتونه توضیح بده.

// UserApi.kt 

internal interface UserApi {
companion object {
private const val USER = "users/"
}

@POST(USER)
fun createUser(@Body phoneNumber: String): Call<UserEntity>
}
 
// UserRepository.kt
interface UserRepository: BaseRepository {
fun createUser(phoneNumber: String): Either<Failure, User>

class Network
@Inject constructor(private val networkHandler: NetworkHandler, private val service: UserService) : UserRepository {
override fun createUser(phoneNumber: String): Either<Failure, User> {
return when (networkHandler.isConnected) {
true -> request(service.createUser(phoneNumber), { it.toUser() }, UserEntity.empty())
false, null -> Either.Left(Failure.NetworkConnection)
}
}
}
}
 
 
 
// UserEntity.kt
data class UserEntity(
private val id: Int,
private val phone_number: String,
private val first_name: String?,
private val last_name: String?,
private val melli_code: String?,
private val birth_date: Date?,
private val role: Int?,
private val gender: Int?,
val new_user: Boolean?
) {

companion object {
fun empty() = UserEntity(-1, "", null, null, null, null, null, null, null)
}

fun toUser() = User(
id,
phone_number,
first_name,
last_name,
melli_code,
birth_date,
role,
gender,
new_user
)
}
 
// User.kt
data class User(
val id: Int,
val phoneNumber: String,
val firstName: String? = "",
val lastName: String? = "",
val melliCode: String? = "",
val birthDate: Date? = Date(),
val role: Int? = 1,
val gender: Int? = -1,
val newUser: Boolean?
) {
companion object {
fun empty() = User(-1, "", null, null, null, null, null, null, null)
}
}

 
// CreateUser.kt
class CreateUser
@Inject constructor(private val userRepository: UserRepository): UseCase<User, Params>() {

override suspend fun run(params: Params): Either<Failure, User> = userRepository.createUser(params.phoneNumber)

data class Params(val phoneNumber: String)
}
 
// CreateUserViewModel.kt
class CreateUserViewModel
@Inject constructor(private val createUser: CreateUser) : BaseViewModel() {
var userData: MutableLiveData<CreateUserView> = MutableLiveData()

fun createUser(phoneNumber: String) = createUser(CreateUser.Params(phoneNumber)) {
it.either(::handleFailure, ::handleCreateUser)
}

private fun handleCreateUser(user: User) {
this.userData.value = CreateUserView(user.id, user.phoneNumber, user.newUser)
}
}
 
// CreateUserView.kt -- in esmesh bad hast va faqat data bargashti ro map mikone ke to ye live data save kone.
data class CreateUserView(
val id: Int?,
@SerializedName("phone_number") val phoneNumber: String?,
@SerializedName("new_user") val newUser: Boolean?)
 
 // CreateUserFragment.kt
 
class CreateUserFragment: BaseFragment() {

private var rootView: View? = null

@Inject
lateinit var createUserViewModel: CreateUserViewModel

@BindView(R.id.frg_create_user_et_phonenumber)
lateinit var phoneNumber: EditText

@OnClick(R.id.frg_create_user_btn_login)
fun loginClick() {
createUserViewModel.createUser(phoneNumber.text.toString())
}

override fun layoutId() = R.layout.fragment_create_user

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
appComponent.inject(this)
createUserViewModel = viewModel(viewModelFactory) {
observe(userData, ::handleRegisterUser)
failure(failure, ::handleFailure)
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return rootView ?: inflater.inflate(layoutId(), null)
}


private fun handleRegisterUser(userData: CreateUserView?) {
userData?.let {
with(userData) {
// inja karamo mikonam
Log.d("USER", "user created")
}
}
}

private fun handleFailure(failure: Failure?) {
when (failure) {
is Failure.NetworkConnection -> { notify(R.string.failure_network_connection) }
is Failure.ServerError -> { notify(R.string.failure_server_error) }
is UserFailure.NonExistentUser -> { notify(R.string.failure_user_non_existent) }
}
}
}
 
 // UserFailure.kt
class UserFailure {
class NonExistentUser: FeatureFailure()

// other failures
}
 
 برای این سوال پاسخی وجود ندارد.

پاسخگویی و مشاهده پاسخ های این سوال تنها برای اعضای ویژه سایت امکان پذیر است .
چنانچه تمایل دارید به همه بخش ها دسترسی داشته باشید میتوانید از این بخش لایسنس این آموزش را خریداری نمایید .