บทความนี้ไม่เน้นความสวยงามเน้อ เน้นความเข้าใจโครงสร้างและโฟว์การทำงานของ MVP ครับ #For dev
ติดตั้ง dependencies
build.gradle (Module : app)
// RETROFIT ... NETWORK LIBRARY
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
// RETROFIT .. CONVERTER & ADAPTER
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
// RX-ANDROID
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
วาง Layout แบบนู๊ปๆ >_<
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:id="@+id/edtUsername"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="username :"
android:inputType="text" />
<EditText
android:id="@+id/edtPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="password : "
android:inputType="textPassword" />
<Button
android:id="@+id/btnRegister"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Register" />
</LinearLayout>
MainActivity.kt
class MainActivity : AppCompatActivity(), MainActivityPresenter.View {
private var presenter: MainActivityPresenter? = null
private var progressBar: ProgressBar? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
presenter = MainActivityPresenter(this)
val edtUsername = findViewById<EditText>(R.id.edtUsername)
val edtPassword = findViewById<EditText>(R.id.edtPassword)
// setup Progress bar
initProgressBar()
// Update ตัวแปร username , password แบบทีละตัวอักษร
edtUsername.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(char: CharSequence, start: Int, before: Int, count: Int) {
presenter!!.updateUsername(char.toString()) // เรียกใช้ method updateUsername ใน presenter
}
override fun afterTextChanged(s: Editable) {
hideProgressBar()
}
})
edtPassword.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(char: CharSequence, start: Int, before: Int, count: Int) {
presenter!!.updatePassword(char.toString()) // เรียกใช้ method updatePassword ใน presenter
}
override fun afterTextChanged(s: Editable) {
hideProgressBar()
}
})
// คลิก Register
btnRegister.setOnClickListener {
presenter!!.submitRegister() // เรียกใช้ method submitRegisterใน presenter
}
}
private fun initProgressBar() {
progressBar = ProgressBar(this, null, android.R.attr.progressBarStyleSmall)
progressBar!!.isIndeterminate = true
val params = RelativeLayout.LayoutParams(Resources.getSystem().displayMetrics.widthPixels, 250)
params.addRule(RelativeLayout.CENTER_IN_PARENT)
this.addContentView(progressBar, params)
showProgressBar()
}
// รอเรียกใช้จากฝั่ง presenter
override fun showProgressBar() {
progressBar!!.visibility = View.VISIBLE
}
override fun hideProgressBar() {
progressBar!!.visibility = View.INVISIBLE
}
}
MainActivityPresenter.kt
class MainActivityPresenter(private val view: View) {
private val user: User = User() // แยก Model User สำหรับการทำงานในโมดูล User
fun updateUsername(username: String) {
user.username= username
}
fun updatPassword(password: String) {
user.password= password
}
fun submitRegister(){
val response = user.register() << Response โผล่นี่
val response = user.register() << Response โผล่นี่
..
..
// สั่งอัพเดท View อะไร บลาๆ แล้วแต่ชอบเลยครับ
}
// ตัวอย่างการใช้ Interface ส่งข้อมูลกลับไปที่ MainActivity.kt
interface View {
fun showProgressBar()
fun hideProgressBar()
}
}
User.kt
class User {
var username = ""
var password = ""
var password = ""
fun getUserProfile(): String {
return "Username: $usrename\n Password : $password"
}
fun register() : Boolean{
val post = PostWithBody(username, password) // Format ก้อนข้อมูลที่จะส่งออก
val retrofit = Retrofit.Builder().addConverterFactory(
GsonConverterFactory.create(GsonBuilder().create()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl("https://jsonplaceholder.typicode.com/").build()
val userApi = retrofit.create(UserApi::class.java)
val response = userApi.registerMember(post)
response.observeOn(AndroidSchedulers.mainThread()).subscribeOn(IoScheduler()).subscribe {
Log.e("TEST:", it.toString())
..
..
..
// ไปต่อกันเองเน้อ
}
return true
}
..
..
..
// ตรงนี้อาจจะมีฟังก์ชั่น Login() มา เพิ่มเติมได้นะ
}
Interface ของ Retrofit
UserApi.kt
interface UserApi {
@POST("/posts") // ส่งข้อมูลแบบ Post Request ไปที่ https://jsonplaceholder.typicode.com/posts
fun registerMember(@Body data: PostWithBody): Observable<RegisterResponse> // ข้อมูลที่ส่งออก , ข้อมูลที่รับเข้า
}
Format ของ Object ที่ใช้ รับ, ส่งกับ Server
ถ้าทำเป็นทีมก็ ตะโกนถาม Backend เอ้ยๆ อันนี้ๆๆๆๆ ปะวะ ( แล้วก็ตั้งผิดอยู่ดี >_<" )
PostWithBody.kt
data class PostWithBody(
@SerializedName("username") val username: String, // ทำไมต้องใส่ SerializedName
@SerializedName("password") val password: String
)
RegisterResponse.kt
data class RegisterResponse(
@SerializedName("response") val response: String
..
..
)