-
1-5. View(Activity)에서 ViewModel의 LiveData를 옵져빙카테고리 없음 2021. 9. 14. 18:42
- activity_memo_list.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <data> <variable name="viewModel" type="com.project.memoapp.viemodel.AndroidViewModelMemoList"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar_MemoListActivity" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:minHeight="?attr/actionBarSize" android:theme="?attr/actionBarTheme" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_MemoListActivity" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <Button android:id="@+id/btn_goto_WriteMemoActivity" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:onClick="onClick" android:text="메모추가" /> </LinearLayout> </layout>
데이터 바인딩을 사용하여 AndroidViewModel 바인딩 변수 viewModel을 선언하였는데
현재는 사용되지 않으므로 없어도 상관없다.
툴바는 없어도 상관없다. 나중에 기능을 만들기 위해서 추가해놨다.
액티비티 코드의 툴바 설정도 마찬가지
- ActivityMemoList
리싸이클러뷰와 어댑터는 다음 포스팅에서 작성
버튼을 누르면 메모 작성 액티비티로 이동. 액티비티가 종료되지 않은 채로 넘어감
onStart에서 뷰모델의 LiveData를 옵져빙하여 변경시 어댑터를 설정하고 리싸이클러뷰 다시 그리기
onRestart의 데이터베이스 쿼리
메모를 작성하고 기존 액티비티로 돌아왔을때 메모 데이터 베이스가 변경되므로 Model의 데이터베이스 쿼리를 통해 Model의 라이브 데이터를 재설정되도록하여 Model의 LiveData가 ViewModel에 통지되고
ViewModel의 LiveData가 변경되어 View에게 다시 통지된다.
안드로이드에서 기본으로 제공해주는 AndroidViewModel 팩토리를 사용하여 뷰모델 생성
class MemoListActivity : AppCompatActivity(), View.OnClickListener { lateinit private var binding: ActivityMemoListBinding private var mActionBar: ActionBar? = null lateinit private var mViewModel: AndroidViewModelMemoList lateinit private var mAdapter: AdapterMemoList override fun onCreate(savedInstanceState: Bundle?) { printLog("onCreate") super.onCreate(savedInstanceState) //시스템 configuration변경시 Activity는 recreated지만 연결된 ViewModel은 살아있음. if (savedInstanceState == null) { //액티비티가 최초로 생성될 때만 ViewModel생성 //DataBinding and return binding instance binding = DataBindingUtil.setContentView(this, R.layout.activity_memo_list) //ViewModel 초기화 mViewModel = ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory(application)) .get(AndroidViewModelMemoList::class.java) //set Toolbar setSupportActionBar(binding.toolbarMemoListActivity) mActionBar = supportActionBar } else { //시스템 configuration 변경-> 액티비티가 recreated일때 } } override fun onStart() { super.onStart() printLog("onStart") //RoomDatabase준비 mViewModel.repositoryMemo.querySelectAllDefault() //RecyclerView와 Adapter binding.recyclerMemoListActivity.layoutManager = LinearLayoutManager(this) val dataObserver: Observer<List<Memo>> = Observer { memos -> //RecyclerView 셋팅 mAdapter = AdapterMemoList(this, memos) binding.recyclerMemoListActivity.adapter = mAdapter mAdapter.notifyDataSetChanged() } mViewModel.liveMemos.observe(this, dataObserver) } //WriteMemoActivity로 갔다가 메모를 작성하고 돌아올때 다시 액티비티가 foreground된 경우 //메모를 작성했을 수도 있기때문에 Model에서 메모를 다시 뽑아오도록 한다. override fun onRestart() { super.onRestart() printLog("onRestart") mViewModel.repositoryMemo.querySelectAllDefault() //메모 작성했기 떄문에 다시 db에서 쿼리 } override fun onStop() { super.onStop() printLog("onStop") //RoomDatabase는 다른 액티비티에서 사용하므로 onStop에서는 그냥 놔둠 } override fun onDestroy() { printLog("onDestroy") super.onDestroy() } override fun onClick(v: View?) { if (v != null) { val selected: Int = v.id when (selected) { binding.btnGotoWriteMemoActivity.id -> { var intent: Intent = Intent(this, WriteMemoActivity::class.java) startActivity(intent) } } } } fun printLog(str: String) { Log.d("APPLICATIONTEST", "MemoListActivity: $str") } }
recycler_item_write_memo.xml 리싸이클러 뷰의 아이템으로 들어갈 뷰에 해당하는 layout
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingStart="3dp" android:paddingTop="2dp" android:paddingEnd="3dp" android:paddingBottom="2dp"> <androidx.cardview.widget.CardView android:id="@+id/cardView" android:layout_width="match_parent" android:layout_height="wrap_content" app:cardCornerRadius="5dp" app:cardElevation="5dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" tools:context=".ui.MemoListActivity"> <TextView android:id="@+id/tv_title" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="5" android:textSize="20sp" tools:text="제목" /> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical"> <TextView android:id="@+id/tv_createdDate" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:gravity="right" android:text="TextView" android:textSize="10sp" tools:text="2021. 08. 10" /> <TextView android:id="@+id/tv_createdTime" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:gravity="right" android:textSize="10sp" tools:text="오후 9:34" /> </LinearLayout> </LinearLayout> </androidx.cardview.widget.CardView> <ImageView android:layout_width="match_parent" android:layout_height="2dp" android:background="#e2e2e2" /> </LinearLayout>
RecyclerView.Adapter
//Adapter는 View, Adapter의 data source는 ViewModel class AdapterMemoList(val context: Context, var memos: List<Memo>) : RecyclerView.Adapter<AdapterMemoList.Holder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { val view = LayoutInflater.from(context).inflate(R.layout.recycler_item_memo, parent, false) return Holder(view) } override fun getItemCount(): Int { return memos.size } override fun onBindViewHolder(holder: Holder, position: Int) { holder.bind(memos[position]) } inner class Holder(itemView: View) : RecyclerView.ViewHolder(itemView) { val title = itemView.findViewById<TextView>(R.id.tv_title) val createdDate = itemView.findViewById<TextView>(R.id.tv_createdDate) val createdTime = itemView.findViewById<TextView>(R.id.tv_createdTime) fun bind(memo: Memo) { title.text = memo.title createdDate.text = memo.created?.substring(0, 10) createdTime.text = memo.created?.substring(11, 19) } } }
데이터 바인딩은 사용하지 않았다. 기능이 잘 동작되었기 떄문에 이제 적용해보려고 한다.
다음 포스팅- 메모를 작성 액티비티 , 그와 관련된 뷰 모델