춤추는 개발자

[AOS] Room + ViewModel + LiveData + RecyclerView (3) 본문

Android/study_til

[AOS] Room + ViewModel + LiveData + RecyclerView (3)

Heon_9u 2021. 6. 28. 18:37
728x90
반응형

 이번 포스팅에서는 Note를 추가하는 AddNoteActivity를 구현합니다. layout을 제작하기 전, 미리 add, save, close를 나타내는 icon을 제작하도록 하겠습니다.

 

1. res/drawable

 drawble 폴더를 마우스 우클릭하여 New -> Vector Asset을 클릭합니다. 그럼 아래 창이 나오며 Clip Art에서 원하는 icon을 선택 후, Name과 Color를 지정하면 icon을 만들 수 있습니다. 

 

 이렇게 생성한 icon을 Activity의 Top Menu에서 활용합니다. 먼저, res 폴더의 하위폴더로 menu를 생성합니다. 역시, res폴더를 마우스 우클릭하여 New -> Android Resource Directory를 클릭합니다. 그럼 아래 창에서 Resource type을 menu로 변경하여 생성합니다.

 

 

 이제 menu폴더에서 역시 마우스 우클릭으로 New -> Menu Resource Files를 클릭하여 AddNoteActivity의 메뉴인 add_note_menuMainActivity의 메뉴인 main_menu를 생성합니다.

 

<main_menu>

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    
    <item
        android:id="@+id/delete_all_notes"
        android:title="Delete all Notes"
        app:showAsAction="never"/>
        
</menu>

 

<add_note_menu>

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/save_note"
        android:icon="@drawable/ic_save"
        android:title="Save"
        app:showAsAction="ifRoom"/>

</menu>

 

 처음에 생성했던 icon을 위와 같이 menu에서 사용해줍니다. 이제부터 AddNoteActivity를 위해 layout을 제작합니다.

 

1. activity_add_note

<?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="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".AddEditNoteActivity">

    <EditText
        android:id="@+id/edit_text_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Title"
        android:inputType="text"/>

    <EditText
        android:id="@+id/edit_text_description"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Description"
        android:inputType="textMultiLine"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Priority: "
        android:layout_marginTop="8dp"
        android:textAppearance="@android:style/TextAppearance.Medium"/>

    <NumberPicker
        android:id="@+id/number_picker_priority"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

 

2. AddNoteActivity

 처음에는 Add 기능만 구현하기위해 아래와 같은 코드를 추가합니다. EXTRA_변수들은 Activity끼리 intent로 화면 전환을 하며 데이터 결과값을 받기 위한 변수로 사용합니다. saveNote() 메서드에서는 trim().isEmpty()를 통해 예외처리를 하며 마무리합니다.

 

package com.heon9u.aacproject;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.EditText;
import android.widget.NumberPicker;
import android.widget.Toast;

public class AddNoteActivity extends AppCompatActivity {
    public static final String EXTRA_TITLE =
            "com.heon9u.aacproject.EXTRA_TITLE";
    public static final String EXTRA_DESCRIPTION =
            "com.heon9u.aacproject.EXTRA_DESCRIPTION";
    public static final String EXTRA_PRIORITY =
            "com.heon9u.aacproject.EXTRA_PRIORITY";


    private EditText editTextTitle;
    private EditText editTextDescription;
    private NumberPicker numberPickerPriority;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_note);

        editTextTitle = findViewById(R.id.edit_text_title);
        editTextDescription = findViewById(R.id.edit_text_description);
        numberPickerPriority = findViewById(R.id.number_picker_priority);

        numberPickerPriority.setMinValue(1);
        numberPickerPriority.setMaxValue(10);

        getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close);
        setTitle("Add Note");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater menuInflater = getMenuInflater();
        menuInflater.inflate(R.menu.add_note_menu, menu);
        return true;
    }

    private void saveNote() {
        String title = editTextTitle.getText().toString();
        String description = editTextDescription.getText().toString();
        int priority = numberPickerPriority.getValue();

        if(title.trim().isEmpty() || description.trim().isEmpty()) {
            Toast.makeText(this, "Please insert title and description", Toast.LENGTH_SHORT).show();
            return;
        }

        Intent data = new Intent();
        data.putExtra(EXTRA_TITLE, title);
        data.putExtra(EXTRA_DESCRIPTION, description);
        data.putExtra(EXTRA_PRIORITY, priority);

        setResult(RESULT_OK, data);
        finish();
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()) {
            case R.id.save_note:
                saveNote();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
} 

 

 Activity를 추가한 경우, 반드시 AndroidManifest에 추가한 Activity를 등록해야합니다. 아래와 같이 activity를 등록하며, MainActivity의 하위 Activity로 등록합니다.

 

<activity android:name=".AddEditNoteActivity"
	android:parentActivityName=".MainActivity">
</activity>

 

 

3. Acitivity 전환을 위한 작업

 이제 MainActivity에서 AddNoteActivity로 페이지 전환을 위한 Button과 로직 구현만 남았습니다. 각 파일마다 추가되는 코드는 아래와 같습니다.

 페이지 전환 시, 결과 데이터가 필요한 경우에는 startActivityForResult와 onActivtiyForResult를 오버라이딩하여 구현합니다. 하지만, 해당 방법은 스케일이 커질수록 분기해야하는 코드가 많아 가독성이 떨어집니다. 이를 위해 Android와 Fragment에 도입된 새로운 API를 적용하는 것을 구글에서 권장하고 있습니다.

 해당 방법은 추후에 포스팅할 예정이고, 기존 방법을 통해 구현하도록 하겠습니다.

 

<activity_main>의 FloationButton

<com.google.android.material.floatingactionbutton.FloatingActionButton
    android:id="@+id/button_add_note"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_add"
    android:layout_gravity="bottom|end"
    android:layout_margin="32dp"/>

 

<MainActivity>의 startActivityForResult

package com.heon9u.aacproject;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import com.google.android.material.floatingactionbutton.FloatingActionButton;

import java.util.List;

public class MainActivity extends AppCompatActivity {

    public static final int ADD_NOTE_REQUEST = 1;

    private NoteViewModel noteViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FloatingActionButton buttonAddNote = findViewById(R.id.button_add_note);
        buttonAddNote.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, AddNoteActivity.class);
                startActivityForResult(intent, ADD_NOTE_REQUEST);
            }
        });

        RecyclerView recyclerView = findViewById(R.id.recycler_view);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setHasFixedSize(true);
        NoteAdapter adapter = new NoteAdapter();
        recyclerView.setAdapter(adapter);
        noteViewModel = new ViewModelProvider(this).get(NoteViewModel.class);
        noteViewModel.getAllNotes().observe(this, new Observer<List<Note>>() {
            @Override
            public void onChanged(List<Note> notes) {
                adapter.setNotes(notes);
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if(requestCode == ADD_NOTE_REQUEST && resultCode == RESULT_OK) {
            String title = data.getStringExtra(AddNoteActivity.EXTRA_TITLE);
            String description = data.getStringExtra(AddNoteActivity.EXTRA_DESCRIPTION);
            int priority = data.getIntExtra(AddNoteActivity.EXTRA_PRIORITY, 1);

            Note note = new Note(title, description, priority);
            noteViewModel.insert(note);

            Toast.makeText(this, "Note saved", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "Note not saved", Toast.LENGTH_SHORT).show();
        }
    }
} 

 

 

 여기까지 Note를 추가하는 기능을 완성했습니다. 다음 포스팅에서는 기존 Note객체를 편집하는 Edit 기능을 추가합니다. 이때, Note를 클릭하는 이벤트 처리와 함께 AddNoteActivity, MainActivity, NoteAdapter의 코드 수정이 있습니다. 기존 코드와 수정된 코드를 비교하며 각 메서드들을 왜 구현하는지, 호출하는지 이해하시길 바랍니다.

 

 

728x90
반응형