구글에서 안드로이드개발을 위한 아키텍처 컴포넌트 라이브러리 1.0 이 나왔다. 5월 말 쯤에 나왔는데 다른 것들에 관심을 갖다 연말이되어서야 확인하고 있다. ( 너무 알아야 할 것이 많아지는 것 같아 슬프다. )
간단하게 아키텍처 컴포넌트는 기존 안드로이드 개발에서 MVVM 패턴을 구현할 수 있도록 도와주는 라이브러리로 판단된다. 지금 까지 RxJava를 이용하여 Lifecycle을 Observe 하고 이를 이용해 MVVM 패턴을 구현했는데, 구글 안드로이드에서 직접 나서서 아키텍처 콤포넌트 라이브라리를 만들었다.
For Room RxJava support, add:
implementation "android.arch.persistence.room:rxjava2:1.0.0"
아직 사용은 안해봤지만, RxJava 프로젝트를 배려해주는 마음이 듬뿍 담긴 Dependency이다.
프로젝트에 적용해 볼 생각이 있는 개발자라면 아래 링크를 확인해 보면 될 것 같다.
https://developer.android.com/topic/libraries/architecture/adding-components.html
https://developer.android.com/training/data-storage/room/defining-data.html
https://developer.android.com/training/data-storage/room/accessing-data.html
우선 아키텍처 콤포넌트 소개 영상 부터
Architecture Components에서 제공하는 Components는 4가지이다. 해당 라이브러리를 공부하기 위해 특정 개인 프로젝트를 아키텍처 콤포넌트를 적용하여 MVVM 패턴을 적용하는 대 수술을 진행해 보려고한다. 우선 기본적인 내용은 알아야 진행이 가능하니 한번 공부해보자.
ROOM에 대해 알아보자 - Spring JPA에서 봤던 듯한 물건이 Android에 똭
기존 Java class를 POJO 라고 설명 하고 있다. - Plan Old Java Object
1 2 3 4 5 6 7 8 9 10 11 | public class Product{ public String name; public String barcode; public long price; public String storeName; public String imageUrl; public long checkInDate; public long checkOutDate; .. } |
기존 Java class에 ROOM의 특성을 넣었으니 RPOJO 라고 해야하는가. - Room Plan Old Java Object
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Entity public class ProductEntity implements Product{ @NonNull private @PrimaryKey String id; private String name; private long price; private String storeName; private String imageUrl; private long checkInDate; private long checkOutDate; ... } | cs |
DB 테이블의 기본 데이터 Class를 정의했으면 이제 DAO 를 만들어 보자 - Database Access Object
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @Dao public interface ProductDao{ @Insert(onConflict = IGNORE) void insert(ProductEntity data); @Insert(onConflict = IGNORE) void insertAll(List<ProductEntity> data); @Query("SELECT * From ProductEntity") List<ProductEntity> findAll(); @Update(onConflict = REPLACE) void update(ProductEntity data); @Query("DELETE FROM ProductEntity") void deleteAll(); } | cs |
ROOM Database - Dao를 정의했다고 하여 바로 사용 할 수 있는 것은 아니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | @Database(entities = {ProductEntity.class}, version = 1) @TypeConverters(DateConverter.class) public abstract class MemoDatabase extends RoomDatabase{ private static final String TAG = "MemoDatabase"; private static MemoDatabase sInstance; @VisibleForTesting public static final String DATABASE_NAME = "market-memo-db"; public abstract ProductDao productDao(); private final MutableLiveData<Boolean> mIsDatabaseCreated = new MutableLiveData<>(); public static MemoDatabase getInstance(final Context context){ return getInstance(context, new AppExecutors()); } public static MemoDatabase getInstance(final Context context, final AppExecutors executors) { if (sInstance == null) { synchronized (MemoDatabase.class) { if (sInstance == null) { sInstance = buildDatabase(context.getApplicationContext(), executors); sInstance.updateDatabaseCreated(context.getApplicationContext()); } } } return sInstance; } /** * Build the database. {@link Builder#build()} only sets up the database configuration and * creates a new instance of the database. * The SQLite database is only created when it's accessed for the first time. */ private static MemoDatabase buildDatabase(final Context appContext, final AppExecutors executors) { return Room.databaseBuilder(appContext, MemoDatabase.class, DATABASE_NAME) .addCallback(new Callback() { @Override public void onCreate(@NonNull SupportSQLiteDatabase db) { super.onCreate(db); executors.diskIO().execute(() -> { // Add a delay to simulate a long-running operation addDelay(); // Generate the data for pre-population MemoDatabase database = MemoDatabase.getInstance(appContext, executors); // insertData(database, products, comments); // notify that the database was created and it's ready to be used database.setDatabaseCreated(); }); } }).build(); } /** * Check whether the database already exists and expose it via {@link #getDatabaseCreated()} */ private void updateDatabaseCreated(final Context context) { if (context.getDatabasePath(DATABASE_NAME).exists()) { setDatabaseCreated(); } } private void setDatabaseCreated(){ mIsDatabaseCreated.postValue(true); } private static void insertData(final MemoDatabase database, final List<ProductEntity> products) { database.runInTransaction(() -> { database.productDao().insertAll(products); }); } private static void addDelay() { try { Thread.sleep(4000); } catch (InterruptedException ignored) { } } public LiveData<Boolean> getDatabaseCreated() { return mIsDatabaseCreated; } } | cs |
Android Test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | @RunWith(AndroidJUnit4.class) public class ProductDaoTest { private static final String TAG = "ProductDaoTest"; Context context; ProductDao mProductDao; @Before public void createDb() { context = InstrumentationRegistry.getTargetContext(); mProductDao = MemoDatabase.getInstance(context).productDao(); } @After public void closeDb(){ MemoDatabase.getInstance(context).close(); } @Test public void insertAndRead(){ ProductEntity product = new ProductEntity(); product.setId(UUID.randomUUID().toString()); product.setCheckInDate(0); product.setCheckOutDate(0); product.setName("Apple"); product.setStoreName("DrugStore"); Log.d(TAG, "INSERT PRODUCT : " + product); mProductDao.insert(product); Log.d(TAG, "INSERT DONE"); Log.d(TAG, "FIND ALL PRODUCT"); List<ProductEntity> list = mProductDao.findAll(); Log.d(TAG, "ALL PRODUCT" + list); assertNotNull(list); } } | cs |
정상적으로 동작하여 Success 되는 것을 확인하였다. 프로젝트 더 깔끔할 수있다는 기대감에 빨리 Android 아키텍처 컴포넌트를 적용해보고 싶다.
기존 프로젝트는 Realm DB Change이벤트를 받아 각 UI이 Rx Observable을 붙여 다른 곳에서 DB가 변경될 때 마다 UI를 업데이트 했었는데, 다음은 LiveData를 이용하여 대해 이 부분을 수정해봐야겠다.
'개발 > 안드로이드' 카테고리의 다른 글
AudioManager를 그냥 사용하면 메모리 누수 (Memory leak) 이 발생한다 (0) | 2018.03.27 |
---|---|
Android MVVM 패턴을 위한 Architecture Components library - LiveData #2 (0) | 2017.11.20 |
알아두면 좋은 Android Studio Live templates (0) | 2017.09.29 |
Nexsus & Pixel 시리즈 안드로이드 O ( 8.0 버전, API 26 ) 업데이트 (0) | 2017.09.14 |
Perl을 이용한 안드로이드 프로젝트 소스 내의 PackageName 변경 (0) | 2017.05.24 |