728x90

 

본 글은 AAC의 ViewModel 용 관련 글입니다.

 

 

 

Android ViewModel Scope

 

1. Dependaceise 선언 관련 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
dependencies {
    def lifecycle_version = "2.0.0"
 
    // ViewModel and LiveData
    implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
    // alternatively - just ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // For Kotlin use lifecycle-viewmodel-ktx
    // alternatively - just LiveData
    implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
    // alternatively - Lifecycles only (no ViewModel or LiveData). Some UI
    //     AndroidX libraries use this lightweight import for Lifecycle
    implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
 
    annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // For Kotlin use kapt instead of annotationProcessor
    // alternately - if using Java8, use the following instead of lifecycle-compiler
    implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
 
    // optional - ReactiveStreams support for LiveData
    implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version" // For Kotlin use lifecycle-reactivestreams-ktx
 
    // optional - Test helpers for LiveData
    testImplementation "androidx.arch.core:core-testing:$lifecycle_version"
}
 
cs

 

2. 추가시 유의사항

implementation'android.arch.lifecycle:ViewModel:1.1.1' //이 아니라


implementation'android.arch.lifecycle:extensions:1.1.1'  //이쪽으로 추가할 것

==> ViewModel로만 연결하면, ViewModelProviders가 없음 (3번참고)

 

3. ViewModel 초기화 변경사항

  androidx.lifecycle:lifecycle-*:2.2.0-alpha03 부터는 ViewModelProviders.of()로 초기화하던 방식이 deprecated 되었다. (아래 링크 참조)

 

Lifecycle  |  Android 개발자  |  Android Developers

Lifecycle-aware components perform actions in response to a change in the lifecycle status of another component, such as activities and fragments. These components help you produce better-organized, and often lighter-weight code, that is easier to maintain

developer.android.com

  • ViewModelProviders.of() has been deprecated. You can pass a Fragment or FragmentActivity to the new ViewModelProvider(ViewModelStoreOwner) constructor to achieve the same functionality. (aosp/1009889)

 

먼저, 다음과 같은 커스텀 ViewModel 클래스가 있다고 할 때, (JAVA 방식)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
 
public class TestViewModel extends ViewModel {
 
    private MutableLiveData<String> test = new MutableLiveData<>();
 
    public MutableLiveData<String> getTest() {
        return test;
    }
 
    public void setTest(MutableLiveData<String> test) {
        this.test = test;
    }
}
 
cs

 

API 변경전 (JAVA 방식)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
public class MainActivity extends AppCompatActivity {
 
private TestViewModel viewModel;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);
      
        //Activity에서 호출시 (ViewModelProvider.AndroidViewModelFactory 사용)        
        viewModel = ViewModelProviders.of(this).get(TestViewModel.class);
    }
    
}
 
 
cs

 

 

API 변경후 (JAVA 방식)

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
public class MainActivity extends AppCompatActivity implements ViewModelStoreOwner{
 
    private ViewModelProvider.AndroidViewModelFactory viewModelFactory; 
    private ViewModelStore viewModelStore = new ViewModelStore();
 
    private TestViewModel viewModel;
 
 
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);
      
        if(viewModelFactory == null){            
           viewModelFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication());
        }
 
        viewModel = new ViewModelProvider(this, viewModelFactory).get(TestViewModel.class);
    }
    
 
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        viewModelStore.clear();
    }
 
    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        return viewModelStore;
    }
 
 
}
 
cs
728x90
728x90

 

build error message:

* What went wrong:
Execution failed for task ':app:processDebugResources'.
> Android resource linking failed
  app\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:686: AAPT: error: resource android:attr/fontStyle not found.
      
  app\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:686: AAPT: error: resource android:attr/font not found.
      
  app\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:686: AAPT: error: resource android:attr/fontWeight not found.
      
  app\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:686: AAPT: error: resource android:attr/fontVariationSettings not found.
      
  app\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:686: AAPT: error: resource android:attr/ttcIndex not found.
      
  app\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:709: AAPT: error: resource android:attr/startX not found.
      
  app\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:711: AAPT: error: resource android:attr/startY not found.
      
  app\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:713: AAPT: error: resource android:attr/endX not found.
      
  app\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:715: AAPT: error: resource android:attr/endY not found.
      
  app\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:722: AAPT: error: resource android:attr/offset not found.
      
  error: failed linking references.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 28s
23 actionable tasks: 5 executed, 18 up-to-date

 

 

해결방안:

 

- stackoverflow나 여러 블로그 등에서 찾아보면, 해결방안으로 Compile Sdk Version 누락이나 buildToolsVersion을 수정하라는 말이 나온다.

 

- 그러나 내 케이스에서는 Project Structure로 가서 확인해봐도 CompileSdkVersion이 누락되지 않았다.

또한 buildToolsVersion를 수정하는 방안 또한, 구글 정책이 변경된(buildToolsVersion을 gradle 설정에서 제거해야함) 현 시점에서는 도움이 되지 않는다.

 

- 해당 에러가 일어난 프로젝트가 오래된 프로젝트라, 기존에 appcompt, support library 등 연결한 library쪽에서 해당 리소스 레퍼런스를 링크하지 못한다는 의미인데, 이제 이런건 AndroidX를 통해서 자동으로 찾아가도록 수정하는 것이 좋은 것 같다.

 

- 즉, (target은 그대로 놔두고) compileSdkVersion을 28로 수정한다.

   app폴더에 커서를 두고 Refactor > Migrate to AndroidX ... 를 선택해서 변경한다.

 

 

 

 

 

 

 

 

 

728x90
728x90

 

Title: Android Jetpack: Understand the CameraX Camera-Support Library (Google I/O'19)

Speaker(s): Vinit Modi, James Fung, Franklin Wu, Trevor McGuire

 

 

 

1. 카메라 개발은 어렵습니다. 이유는?

- 앱에서 다양한 OS별로 신경써야함

- 저가형 entry부터 고가의 flagship까지 일관성이 있어야함

- 카메라 API의 복잡성

 

 

2. (testlab에서 테스트 다 하면서 개발했다는) CamaraX

 - 현 시장의 90%에 가까운 기기에서 호환됨

 - target SDK가 API 21 이상이면 사용 가능

 - Camera1 Api 및 Camera2 Legay Layer와 일관되게 제공됨.

 - 사용하기 쉬워짐

 - Lifecycle aware: Preview, Image Analysis, Caputre 기능 -> 각 개별 thread 필요 없어짐

 - 

CameraX 이전, CameraX 이후 동작

 

3. 사용 예제

 

1) Preview

/*display preview on screen*/

//configure preview
val previewConfig = PreviewConfig.Builder().build()

//create preview
val preview = Preview(previewConfig)

preview.setOnPreviewOutputUpdateListener {
    PreviewOutput : Preview.PreviewOutput? ->
    // your code here. e.g. use previewOutput?.surfaceTexture
    // and post to a GL renderer.
}

//attach preview to lifecycle
CameraX.bindToLifecycle(this as LifecycleOwner, preview)

 

2) Image Analysis

 

//configure image analysis

//set resolution
val imageAnalysisConfig = ImageAnalysisConfig.Builder()
    .setTargetResolution(Size(1280, 720))
    .build()

//create image analysis
val imageAnalysis = ImageAnalysis(imageAnalysisConfig)

//attach output
imageAnalysis.setAnalyzer({ image : ImageProxy, rotationDegrees : Int ->
    val cropRect = image.cropRect
    //insert your code here
})

//attach image analysis & preview to lifecycle
CameraX.bindToLifecycle(this as LifecycleOwner, imageAnalysis, preview)

 

 

 

 3) Image Capture

 

/*configure image capture*/

//manage rotation
val imageCaptureConfig = ImageCaptureConfig.Builder()
    .setTargetRotation(windowManager.defaultDisplay.rotation)
    .build()

//create image capture
val imageCapture = ImageCapture(imageCaptureConfig)

//bind all use cases
CameraX.bindToLifecycle(this as LifecycleOwner, imageCapture, imageAnalysis, preview)

 

//on user action save a picture
fun onClick() {
    val file = File(...)
    imageCapture.takePicture(file,
        object : ImageCapture.OnImageSavedListener {
            override fun onError(error: ImageCapture.UserCaseError,
                                message: String, exc: Throwable?){
                // insert your code here 
            }
            override fun onImageSaved(file: File) {
                // insert your code here
            }
        })
}

 

 

 

Reference

https://www.youtube.com/watch?v=kuv8uK-5CLY

 

728x90
728x90

2019/09/02 - [Dev/Android] - [Android] 데이터 바인딩 개념 및 라이브러리 비교(Android Data Binding Library, Kotlin Android Extensions)

 

 

안드로이드 앱개발 시

데이터바인딩 설정하는건 정말 간단한데, 그것마저도 가끔씩 까먹어서 요약글 적어놓습니다.

 

 

1. build.gradle (app)

1
2
3
4
5
6
7
8
android{
 
  dataBinding {
      enabled = true
  }
 
}
 
cs

 

2. XML layout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
 
  <data>
        <variable
            name="activity"
            type="패키지경로.MainActivity"/>
 
    </data>
 
 
<LinearLayout
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical"/>
 
</layout>
 
cs

 

3. Java

1
2
3
4
5
6
7
8
9
10
MainActivityLayoutBinding databinding;
 
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
 
   databinding = DataBindingUtil.setContentView(this, R.layout.main_activity_layout);
   databinding.setActivity(this);
 
}
cs

 

 

 

 

 

Reference

 

Android Jetpack:Empower your UI with Android Data Binding

Data Binding Library is a support library that enables you to bind UI elements in your layouts to data sources in your app using a…

medium.com

 

728x90

+ Recent posts