好的,那我們要稍微介紹一下,Firebase,我們可以把它想成一個後端服務。並且它同時支援Android、iOS、網頁端,所以可以有效縮減我們App開發的時間。
-authentication:提供給我們辦帳號,管理授權相關的地方
-Firebase Database:雲端儲存資料
-Realtime Database:雲端儲存資料
-Storage:儲存影片/照片等等那我們就開始連接Firebase啦!
註冊並登入
https://console.firebase.google.com/u/0/
我們這邊的目的是要讓Android幫我們新增 implementation,同理順便點選並新增以下的 Clound Firestore implementation。
這樣我們就姑且完成連接啦!!
我們建立一個基本的Fragment,讓我們可以再以後的Fragment繼承,可以達到覆用的好處,而我們這次主要有兩個
1.progressBar,俗稱進度條
2.snackBar,彈出訊息框,出現在下方,比較不會阻擋使用者的視線
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_gravity="center"
android:orientation="horizontal"
android:padding="@dimen/progress_dialog_content_padding">
<ProgressBar
android:id="@+id/progress"
android:layout_width="@dimen/progress_dialog_size"
android:layout_height="@dimen/progress_dialog_size"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintEnd_toStartOf="@+id/tv_progress"/>
<com.example.petsmatchingapp.utils.JFTextView
android:id="@+id/tv_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/progress_text_margin_start"
android:layout_marginLeft="@dimen/progress_text_margin_start"
android:textSize="@dimen/progress_text_size"
android:text="@string/please_wait"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/progress"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
dimen如下
<dimen name="progress_dialog_content_padding">10dp</dimen>
<dimen name="progress_dialog_size">50dp</dimen>
<dimen name="progress_text_size">16sp</dimen>
<dimen name="progress_text_margin_start">16dp</dimen>
string如下
<string name="please_wait">Please Wait</string>
順便把等等會用到的 Snackbar顏色一起新增,color如下
<color name="colorSnackBarSuccess">#8BC34A</color>
<color name="colorSnackBarError">#F72400</color>
//首先要把class改成 open,這樣其他的 Fragment才可以繼承
open class BaseFragment : Fragment() {
//先延遲初始化剛剛的 Dialog,方便我們再不同funtion直接呼叫
private lateinit var mProgressDialog: Dialog
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View?{
return inflater.inflate(R.layout.fragment_base, container, false)
}
//建立Dialog,參數是 text,當我們別的fragment要使用的時候,直接傳入 text,就可以呼叫了
fun showDialog(text: String){
mProgressDialog = Dialog(requireActivity())
mProgressDialog.setCancelable(false)
mProgressDialog.setCanceledOnTouchOutside(false)
//把剛剛的Dialog Layout指定進去
mProgressDialog.setContentView(R.layout.dialog_progress)
mProgressDialog.findViewById<TextView>(R.id.tv_progress).text= text
mProgressDialog.show()
}
//關掉 Dialog
fun hideDialog(){
mProgressDialog.dismiss()
}
//這個是出現在下方的
fun showSnackBar(message: String, error: Boolean){
val snackBar = Snackbar.make(requireActivity().findViewById(android.R.id.content),message,Snackbar.LENGTH_LONG)
val snackBarView = snackBar.view
//如果是error訊息的話,就顯示error顏色,否則success的顏色
if(error){
snackBarView.setBackgroundColor(ContextCompat.getColor(requireContext(),R.color.colorSnackBarError))
}else{
snackBarView.setBackgroundColor(ContextCompat.getColor(requireContext(),R.color.colorSnackBarSuccess))
}
snackBar.show()
}
}
★跟 Toast 不同的是,Snackbar 隸屬於顯示中的 view,而不是以 context。這確保 Snackbar 只在有 view 顯示時才出現。在Activity中可以用findViewById(android.R.id.content) 取得contentView。
★接下來直接在LoginFragment繼承BaseFragment即可。並且要把 minSdkVersion 改成21,就可以直接呼叫BaseFragment裡面的funtion囉
我們這次透過Koin來呼叫我們的viewmodel,老實說關於service locator我還沒有很什麼研究,只是先用,有興趣的讀者們可以自己去查關於service locator,如果有什麼心得可以跟我分享呦! 或是搞不好做完還有時間? 我再來研究分享給大家
ext.koin_version = "2.2.1"
implementation"org.koin:koin-core:$koin_version"
implementation"org.koin:koin-androidx-scope:$koin_version"
implementation"org.koin:koin-androidx-viewmodel:$koin_version"
testImplementation"org.koin:koin-test:$koin_version"
//繼承 Application
class MyApp: Application() {
override fun onCreate() {
super.onCreate()
setupKoin()
}
private fun setupKoin(){
//Module是代表要填入想要實例化的東西
val viewModelModule =module{
viewModel{AccountViewModel()}
}
//初始化Koin,啟動一個全域性的Koin,並把剛剛的module放進去
startKoin{
this@MyApp
modules(
viewModelModule
)
}
}
}
我們的架構是會擁有兩個Activity,一個負責關於登入帳號/註冊相關的,另外主要活動內容的Activity,而viewModel也會分成管理帳號相關的AccountViewModel,還有主要的活動ViewModel負責管理其他數據。
private val accountViewModel: AccountViewModel by sharedViewModel()
那大家今天辛苦啦! 再過來明天就會開始做登入畫面囉 へけ