2024년 3월 5일 화요일

Room, Retrofit, Coroutines 을 이용한 Repository pattern

 Repository pattern은 애플리케이션에 있을 수 있는 여러 데이터 소스, 애플리케이션의 데이터가 내부 데이터베이스 또는 웹 API와 같은 외부 서비스로부터 기인하는 것을 숨기는데 사용되는 추상화입니다.

이 패턴은 Android 애플리케이션을 개발할 때 널리 사용되며, 애플리케이션을 만드는 데 권장되고 있습니다.

다음 다이어그램은 Android의 일반 모바일 애플리케이션 아키텍처를 표시합니다.

액티비티와 프레그먼트는 서로 다른 ViewModel의 인스턴스를 하나 이상 가질 수 있으며 없을 수도 있습니다. 각 ViewModel 은 특정 저장소(Repository)에 대한 종속성을 가지며 이 저장소는 여러 ViewModel 에서 공유될 수 있습니다.

저장소는 정보를 검색할 데이터 소스를 알고 있습니다. 이 경우 저장소는 SQLite의 상위 계층인 Room 모델과 웹 서비스와 통신하기 위해 Retrofit 에서 제공하는 서비스 인터페이스를 알고 있습니다.

각 레이어는 아래 레이어만 알고 있으며 ViewModel 은 저장소가 누구와 상호작용하는지 모릅니다.

알림을 작성하기 위한 EditText 와 알림을 추가하는 버튼, 샘플 액티비티를 살펴보겠습니다.

 
class CreateReminderActivity : AppCompatActivity() {

    val viewModel: CreateReminderViewModel by lazy {
        val app = application as ReminderApp
        val viewModelProviderFactory =
            CreateReminderViewModelProviderFactory(
                app,
                intent
            )
        ViewModelProvider(
            this,
            viewModelProviderFactory
        )[CreateReminderViewModel::class.java]
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.createreminderactivity)

        val reminderEditText: EditText = findViewById(R.id.reminderEditTextView)
        val createReminderButton: Button = findViewById(R.id.createReminderButton)


        createReminderButton.setOnClickListener {
            createReminder(
                text = reminderEditText.text.toString()
            )
        }
    }

    private fun createReminder(text: String) {
        if (text.isEmpty()) {
            showToast(message = "Reminder text field is empty")
        } else {
            viewModel.createReminder(text = text)
        }
    }

    private fun showToast(message: String) {
        ...
    }
}



2021년 12월 29일 수요일

Android를 위한 JUnit test suite 샘플

 우리는 app/src/main/java 에 더하기와 곱셈을 위한 두 개의 static method를 갖는 Calculator class를 만들 것이다. 그리고 app/src/test/java 에 calculater 클래스에 있는 두 개의 static method를 테스트하기 위한 두 개의 test class를 만들 것이다.

코드를 작성하기 전에, 아래와 같이 junit 을 위한 gradle dependency를 추가한다.

dependencies {
    //Other dependencies.....
    //junit test compile dependency
    testCompile 'junit:junit:4.12'
}

1. Calculator.java 파일을 생성한다.

public class Calculator {

    public static int addition(int a, int b) {
        return a + b;
    }

    public static int multiplication(int a, int b) {
        return a * b;
    }

}

2. 테스트 패키지에 AddtionTest.java 를 생성한다. 이 패키지를 보이게 하려면, Build Variants를 Unit Tests로 변경한다. 모든 테스트 클래스들은 이 패키지 아래에 있다.

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import static org.junit.Assert.*;
public class AdditionTest {
    @Test
    public void additionTest() throws Exception {
        //Fail this on purpose
        int expected = 5;
        int actual = Calculator.addition(2, 2);
        assertEquals(expected, actual);
    }
}

3. 테스트 패키지에 MultiplicationTest.java 를 생성한다.

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import static org.junit.Assert.*;

public class MultiplicationTest {
    @Test
    public void multiplicationTest() throws Exception {
        int expected = 6;
        int actual = Calculator.multiplication(2, 3);
        assertEquals(expected, actual);
    }
}

4. 마지막으로, 위의 두 테스트를 하나의 테스트 슈트에 넣어서 한번에 테스트들을 수행하도록 할 것이다. MyTestSuite.java 라고 하는 Test suite 클래스를 만든다.

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({
        AdditionTest.class,
        MultiplicationTest.class
})
public class MyTestSuite {
}

4. MyTestSuite 클래스에서 우클릭해서 Run ‘MyTestSuite’ 를 선택한다.

5. 윈도우 커맨드 창을 열어 프로젝트 루트 디렉토리에서도 실행할 수 있다. 명령행에서 실행하면 MyTestSuite 클래스 조차 필요없다.

./gradlew test

2020년 9월 6일 일요일

vert.x 환경 설정하기

개발환경 우분투18.04

1. 우분투에 java 설치하기

어떤 버전을 설치해야 하나?

openjdk-xx-jdk-headless : GUI지원 안함
openjdk-xx-jre : 자바 개발환경이 제외된 실행환경만 포함

우분투 개발환경에 설치하므로 openjdk-8-jdk 버전을 설치

2. eclipse 설치

eclipse 는 우분투 소프트웨어를 통해 설치

기존 프로젝트를 Import Project from File System or Archive 를 통해 불러옴
wizard가 maven 파일을 파싱하고 환경을 구성해줌.

3. maven 설치

우분투 쉘환경에서 빌드를 하기 위해서는 maven을 별도로 설치해야 한다.

sudo apt install maven

환경 구축후 정리하는 것이라 2번 상태에서 빌드까지 되었었던 것인지 기억이 나지 않음. 자바개발용 이클립스에서 maven을 내장하고 있는 것은 아니겠지 아마도 2번 상태에서는 빌드가 되지 않은 것으로 보임.

메이븐 설치 참고



C/C++ 용 이클립스가 설치된 곳에서는 

자바개발용 소프트웨어를 설치해야 한다.

1. 자바 언어 지원 설치

Help->Install New Software...

Oxygen - http://download.eclipse.org/releases/oxygen 와 같은 repository 경로를 이용해 설치된 이클립스 버전에서 사용할 수 있는 소프트웨어 목록을 받아온다.

Programming Languages에서 Eclipse Java Developement Tools를 체크하여 설치

CDT 에 Java 개발환경 셋팅 참고

2. maven 설치

위의 maven 설치 참고

3. m2e 설치

자바용 이클립스와는 달리 m2e를 설치하여 시스템에 설치된 maven 을 연결시켜주어야 한다.

m2e 설치 및 설정 참고

2020년 2월 10일 월요일

GStreamer 플러그인에서 unix domain 소켓 사용하기

GStreamer 플러그인 작성시 "gio/gunixsocketaddress.h" 헤더 파일을 찾지 못하는 경우가 있다.

meson 환경 빌드 하에서는

meson.build 파일에서 아래와 같이 gio-unix-2.0에 대한 dependency를 추가해준다.

glib_req = '>= 2.44.0'

glib_deps = [dependency('glib-2.0', version : glib_req, fallback: ['glib', 'libglib_dep']),
             dependency('gobject-2.0', fallback: ['glib', 'libgobject_dep']),
             dependency('gio-2.0', fallback: ['glib', 'libgobject_dep']),
             dependency('gio-unix-2.0', fallback: ['glib', 'libgobject_dep'])]

testexample = library('testoverlay',
  testoverlay_sources,
  c_args: plugin_c_args,
  dependencies : glib_deps + [pango_dep, gstvideo_dep, gst_dep, gst_base_dep, libm],
  install : true,
  install_dir : plugins_install_dir,

)

2019년 3월 2일 토요일

- Defining Plugins | Qt Core 5.12


<QtPlugin> - Defining Plugins

<QtPlugin> 헤더 파일은 플러그인들을 정의하기 위한 매크로들을 정의합니다. More...
Macros

Q_DECLARE_INTERFACE(ClassName, Identifier)
Q_IMPORT_PLUGIN(PluginName)
Q_PLUGIN_METADATA( ...)

Macro Documentation

Q_DECLARE_INTERFACE(ClassName, Identifier)

이 매크로는 주어진 Identifier (문자열 리터럴)를 ClassName이라는 인터페이스 클래스에 연결합니다. 식별자는 고유해야합니다. 예를 들어:
#define BrushInterface_iid "org.qt-project.Qt.Examples.PlugAndPaint.BrushInterface/1.0"

Q_DECLARE_INTERFACE(BrushInterface, BrushInterface_iid)
이 매크로는 일반적으로 헤더 파일의 ClassName에 대한 클래스 정의 바로 다음에 사용됩니다. 자세한 내용은 Plug & Paint 예제를 참조하십시오.
Q_DECLARE_INTERFACE를 네임 스페이스에 선언 된 인터페이스 클래스와 함께 사용하려면 Q_DECLARE_INTERFACE가 네임 스페이스 안에 있지 않은지 확인해야합니다. 예를 들어:
namespace Foo
{
struct MyInterface { ... };
}

Q_DECLARE_INTERFACE(Foo::MyInterface, "org.examples.MyInterface")

Q_IMPORT_PLUGIN(PluginName)

이 매크로는 PluginName이라는 플러그인을 가져옵니다.이 플러그인은 Q_PLUGIN_METADATA()를 사용하여 플러그인의 메타 데이터를 선언하는 클래스의 이름과 일치합니다.
이 매크로를 응용 프로그램의 소스 코드에 삽입하면 정적 플러그인을 사용할 수 있습니다.
Example:
Q_IMPORT_PLUGIN(qjpeg)
응용 프로그램이 빌드 될 때 정적 플러그인도 링커에 포함되어야합니다. Qt의 미리 정의 된 플러그인의 경우 QTPLUGIN을 사용하여 필요한 플러그인을 빌드에 추가 할 수 있습니다. 예를 들어:
TEMPLATE = app
QTPLUGIN += qjpeg qgif # image formats

Q_PLUGIN_METADATA( ...)

이 매크로는이 개체를 인스턴스화하는 플러그인의 일부인 메타 데이터를 선언하는 데 사용됩니다.
매크로는 객체를 통해 구현 된 인터페이스의 IID를 선언하고 플러그인의 메타 데이터가 들어있는 파일을 참조해야합니다.
Qt 플러그인의 소스 코드에는이 매크로가 정확히 하나 있어야합니다.
Example:
class MyInstance : public QObject
{
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDummyPlugin" FILE "mymetadata.json")
};
자세한 내용은 Plug & Paint 예제를 참조하십시오.
이 매크로가 나타나는 클래스는 기본 구성 가능해야합니다.
FILE은 선택적이며 json 파일을 가리 킵니다.
json 파일은 빌드 시스템이 지정한 include 디렉토리 중 하나에 있어야합니다. moc는 지정된 파일을 찾을 수 없을 때 오류와 함께 종료합니다.
이 함수는 Qt 5.0에서 처음 소개되었습니다.

2018년 6월 17일 일요일

Oreo 특성 vs Nougat


1. Picture-in-Picture 모드
2. 자동 채우기 프레임 워크
3. 공유 환경 설정에 대한 학습
4. 캐시 된 데이터에 대한 앱 별 디스크 공간 할당량 관리를 통한 공간 확보 메커니즘
5. NAN(Neighbor Awareness Networking) 지원
6. 화면의 기본 종횡비가 없어짐
7. multi-display support
8. 포인트 캡처
9. Project Treble
10. 알림 처리방식 변경
11. 오디오 subsystem 개선사항(추가 블루투스 코덱 지원, 오디오 포커스 처리 방법 변경)
12. Downloadable fonts와 adaptive icons
13. 블루투스5 지원

[참고]
https://www.androidauthority.com/android-oreo-vs-android-nougat-introduction-794696/

2017년 12월 23일 토요일

[STAN] Structure Analysis for Java > Tasks > Switching between Flat Packages and Package Trees

Switching between Flat Packages and Package Trees

자바의 패키지 컨셉은 클래스를 높은 레벨 구성단위로 그룹핑하는 기본적인 방법이다. 그러나 패키지 구조 또한 트리를 구성한다. 예를 들어, com.stan4j.db와 com.stan4j.ui 패키지는 com.stan4j의 sub-packages 이다. 이를 고려해서 STAN은 flat packages를 Flat Packages와 Package Tree 모드 사이를 토글하도록 해준다.
Java's package concept is the basic way for grouping classes into higher level units. However, the package structure also builds a tree. For example, the packages com.stan4j.db and com.stan4j.ui are sub-packages of package com.stan4j. To take this into account, STAN allows you to toggle between the flat packages Flat Packages and Package Tree modes.
  • Flat package 모드에서 STAN 완전히 super와 sub-package 관계를 무시한다. 모든 패키지들은 explorer tree 상에서 동일한 레벨로 보인다.
  • Package Tree 모드에서는 STAN은 super/sub-package 관계를 유지한다. Structure Explorer는 "normal" 패키지를 말단으로해서 전체 package 계층을 보여준다.
    • package tree는 package 뿐만 아니라 서브트리를 포함하는 package tree를 의미한다.
    • folder는 subtree 노드들만 포함하는 package tree를 의미한다.
    • leaf package는 말단 패키지를 의미한다.

Flat 대 Tree switch는 Structure Explorer에 여양을 주지는 않는다. 그 switch는 STAN이 전역적으로 다른 구조 모델을 사용하게 해준다. 그러므로, toggle은 또한 다른 뷰에서 무엇이 보이는지 무엇이 보이는지에 대해 암시를 갖는다. 예를들어
The Flat versus Tree switch does not only affect the Structure Explorer. Rather, it makes STAN use the different structure models globally. Therefore, the toggle also has implications on what is shown in other views. For example,
  • 패키지를 위한 Dependency Landscape는 다른 (flat) 패키지나 package trees 에 의존할 것이다.
  • Composition View는 오직 flat package 모드에서만 모든 package들을 포함하는 (flat) package dependency graph를 보여줄 것이다.
  • Couplings View는 오직 package tree 모드에서만 package tree node들을 사용할 것이다.
  • Query View와 Violations View는 flat package mode에서 package tree rows를 gray out 시킬 것이다.