반응형

android개발하다 보면 onActivityResult로 결과를 받아오는 경우가 많습니다.

A activity에서 B activity로 startActivityForResult 로 호출 후, B activity에서의 결과를 onActivityResult로 받게 되죠.

그런데, 

implementation 'androidx.activity:activity-ktx:1.2.0-alpha04'
implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha04'

에서 다른 기능이 생겼습니다.

호출과 동시에 lambda function으로 다로 onActivityResult로 결과를 받지 않아도 됩니다.

 

일반적인 방법으로는

Intent(this@MainActivity, SubActivity::class.java).run {
                            startActivityForResult(this, REQUEST_CODE_SUBACTIVITY)
}

와 같은 방법으로 호출하면,

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)

    when (requestCode) {
        REQUEST_CODE_SUBACTIVITY -> {
            if (resultCode == Activity.RESULT_OK) {
                val resultValue = data?.getStringExtra("result") ?: ""
                binding.textCallback.text = resultValue + " Normal"
            }
        }
    }
 }

와 같이 결과를 받습니다.

 

그런데, activity-ktx:1.2.0-alpha, fragment-ktx:1.3.0-alpha에 추가된 방법으로 한다면

registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
                    when (it.resultCode) {
                        Activity.RESULT_OK -> {
                            val resultValue = it.data?.getStringExtra("result") ?: ""
                            textCallback.text = resultValue + " KTX"
                        }
                        Activity.RESULT_CANCELED -> {
                        }
                    }
                }.launch(
                        Intent(this@MainActivity, SubActivity::class.java)
                )

와 같이 진행할 수 있습니다.

onActivityResult의 override된 mehtod로 결과를 받지 않아도... 간결화된 코드로 가독성이 좋아졌다고 볼 수 있습니다.

 

StartActvityForResult이외에

StartActivityForResult
StartIntentSenderForResult
RequestMultiplePermissions
RequestPermission
TakePicturePreview
TakePicture
TakeVideo
PickContact
GetContent
...

 

 

반응형
반응형

kotlin으로 파일을 읽는 방법은 java로 할 하는 경우보다는 간단?? 한듯 합니다.

최종적으로 android하면서 사용한 방법은

fun fileRead(context: Context, fileUri: Uri): String {
        val sb = StringBuilder()
        val inputStream = context.contentResolver.openInputStream(fileUri)
        inputStream?.let {
            val reader = BufferedReader(InputStreamReader(inputStream))
            val readLines = reader.readLines()
            readLines.forEach {
                sb.append(it)
            }
            
            it.close()
        }
        return sb.toString()
    }

이지만 아래와 같은 방법들이 있습니다.

1. forEachLine

fun fileReadforEachLine(file: String): String {

        val sb = StringBuilder()

        File(file).forEachLine {
            sb.append(it)
        }

        return sb.toString()
    }

2. useLines

fun fileReadUseLines(file: String): String {
        val sb = StringBuilder()

        File(file).useLines {
            it.forEach { str ->
                sb.append(str)
            }
        }

        return sb.toString()
    }

3. bufferedReader

fun fileReadBufferedReader(file: String): String {
        val sb = StringBuilder()

        File(file).bufferedReader().readLine().forEach {
            sb.append(it)
        }

        return sb.toString()
    }

4. readLines

fun fileReadReadLines(file: String): String {
        val sb = StringBuilder()

        File(file).readLines().forEach {
            sb.append(it)
        }

        return sb.toString()
    }

5. inputStream

fun fileReadInputStream(file: String): String {
        return File(file)
            .inputStream()
            .readBytes()
            .toString(Charsets.UTF_8)
    }

6. readText

fun fileReadReadText(file: String): String {
        return File(file).readText(Charsets.UTF_8)
    }
반응형
반응형

android Pie 대응을 위해서 targetSdkVersion을 28로 변경 후  갑자기

UnknownServiceException: CLEARTEXT communication to example.com not permitted by network security policy

와 같은 오류가 나오게 경험을 하게 됩니다.


이유는 android pie부터 http가 아닌 https를 이용해야 합니다.



의 내용을 확인하면 됩니다.


간단하게 api의 도메인이 http가 아닌 https를 지원하고 http를 https로 변경만 하면 됩니다. 대부분의 회사 api들이 https를 지원하지만 그렇지 않은 경우도 있죠.

이럴 땐 http로 통신할 도메인들에 대해서 관리를 해주면 됩니다.


우선


res/xml/network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
   
<domain-config>
       
<domain includeSubdomains="true">example.com</domain>
       
<trust-anchors>
           
<certificates src="@raw/my_ca"/>
       
</trust-anchors>
   
</domain-config>
</network-security-config>


와 같은 파일을 만들어 준 뒤

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
   
<application android:networkSecurityConfig="@xml/network_security_config"
                    ...
>
        ...
   
</application>
</manifest>

와 같이 androidmanifest에 등록해 줍니다.


다른 방법은.

<base-config cleartextTrafficPermitted="true" />

을 network_security_config.xml에 등록을 해서 기본적으로 http를 지원하게 하는 방법도 있습니다. 이건 지정된 domain이외에 기본적으로.. 외부의 api 에 대해서 http를 지원하겠다고 하는 것입니다.


또 다른 방법으로는

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
   
<application android:useCleartextTraffic="true"
                    ...
>
        ...
   
</application>
</manifest>

해주는 것입니다.

자세한 설명은

android:usesCleartextTraffic


링크를 통해서 확인할 수 있습니다.


그래도.. 왠만하면 api는 https를 지원하는게 좋겠죠!!!!

반응형

'Android' 카테고리의 다른 글

goodbye? onActivityResult...  (0) 2020.05.14
kotlin file read...  (0) 2019.04.17
AndroidStudio에서 File Template이용하기.  (0) 2016.06.14
AndroidStudio에서 lombok 사용하기  (0) 2016.04.10
Dagger2 + Sqlbrite  (0) 2015.11.17
반응형

AndroidStudio에서는 live template라는 좋은 기능이 있습니다. 단순하게 재사용이 많은 코드에 대해서 매크로 같은 기능이라고 해야 할까요?? 한두단어 쳤을 때 해당 template에 따라서 코드가 작성되는 것입니다. 단적인 예를 들어서 Fragment에서 새로운 instance를 상성하기 위해서는 

이와 같은 코드를 작성한다고 했을 때 키보드를 그래도 수십번??? 의 타이핑이 필요 합니다. 하지만 live template 기능을 이용하면 

이렇게 하면 단 몇번의 타이핑으로 원하는 기본 코드를 작성할 수 있습니다.


그렇다면 File Template기능은.. java나 html..javascript등에서 자주 사용하는 코드들에 대해서 기본 template를 작성해 두고 빠르게 원하는 기본 코드를 작성하도록 해주는 기능 입니다. 기본적으로 Singleton이 되어 있는데 구성을 보면 

이와 같이 되어 있어서 코드 작성할 때 File Template의 Singleton을 선택하게 되면 "NAME"만 입력하면 위와 같은 template에 정의 된 코드들이 만들어지게 됩니다. 


그렇다면 내가 자주 사용하는 코드를 재사용 할 template를 만들어 둔다면 기본적인 코드들의 활용이 높아질 것입니다.


저같은 경우는 Android개발 시 BaseActivity라는 부모 class를 만들고 상속을 통한 하위 구현 Activity를 만들 고 있습니다. 이 부분에서 file template를 통해서 구현의 속도를 향상시키는 방법은.

new -> Edit File TEmplates...를 선택합니다.

그러면 좀전 위에서 본 File and Code Template라는 메뉴를 보실 수 있습니다.


간단하게 

이와같은 template를 만들었다고 한다면.. ${NAME} 에서 이름을 입력 받고, ${LAYOUT_RES_ID} 입력 받는다면 BaseActivity를 상속받은 위 template가 만들어 지게 됩니다. 

위에서 정의한 NAME에는 Child로.. LAYOUT_RES_ID 에서는 activity_child를 입력했습니다.


결과는 

이와 같은 코드가 만들어 집니다.


만약 Adapter나 RecyclerView같은 코드의 template를 만들어 둔다면 더 활용도가 높을 것 입니다.

개발 속도를 빠르게 하는방법은 여러가지가 있겠지만 tool에 대한 이해도를 높이는 것도 좋은 방법이지 않을 까 합니다.


다음에는 이런 template를 group화 시켜서 하나가 아닌 여러개의 파일을 한번에 만드는 방법을 알아볼까 합니다.

반응형
반응형

자바에서 코드를 작성 시 모델을 만들다 보면 constructor와 기본 getter/setter.. 그리고 상황에 따라서 builder를 만들어 사용해야 합니다.

그런데 이런 일들을 모두 타이핑 하다 보니 보일플레이트 같은 코드들이 많이도 써야 합니다. 코드 제너레이터들이 있어서 편하게 할 수 있긴 하지만 더 편한 방법이 없을까요?

저같은 경우는 lombok을 사용해서 모델 객체들의 불필요한 보일플레이트 코드들을 줄이고 있습니다. annotation방법으로 사용하기 때문에 사용방법도 간단합니다.



1. @Getter / @Setter

기본적으로 멤버필드들에 대한 getter/setter메소드들을 만들어 줍니다.


2. @AllArgsConstructor / @NoArgsConstructor

멤버필드들이 모두 파라미터로 지정된 생성자와 빈 생성자를 만들어 줍니다.


3. @Builder

모델을 빌더 패턴으로 만들어 줍니다.


4. @ToString

toString의 override된 메소드를 만들어 줍니다.


그 외에도 여러 가지가 있지만 lombok features 에서 더 많은 것을 확인할 수 있습니다.



그럼 AndroidStudio에 적용하는 방법을 알아보도록 하죠.


1. 우선 lombok plugin을 설치해야 합니다.

Preference -> Plugins -> Browse Repositories 에서 lombok을 검색하면 Lombok Plugin이 나옵니다. 이걸 설치해 줍니다.


2. gradle에 lombok적용하기.

"""

provided "org.projectlombok:lombok:1.16.8"

"""


3. 트러블슈팅??

 - package javax.annotation does not exist

annotation does not exist...이걸 해결해 주기 위해서 gradle에 annotation을 provide해줍니다.

"""

provided 'org.glassfish:javax.annotation:10.0-b28'

"""


 - cannot find symbol class ConstructorProperties

lombok.config 설정파일을 추가해 줘야 합니다. 프로젝트와 같은 root에 lombok.config파일을 만들고

'''

lombok.anyConstructor.suppressConstructorProperties = true

'''

와 같은 내용을 추가해 줍니다.

자세한 내용은 Configuration system 에서 확인할 수 있습니다.




이와같은 과정 후에 결과를 보게 된다면

AndroidStudio의 structures view를 보게 되면

이와 같은 결과를 볼 수 있습니다.


이제 lombok을 이용해서 코드 다이어트를!!

반응형
반응형

Sqlite는 안드로이드를 사용하면서 가장 많이 사용하는 db가 아닐 까 생각됩니다. 나온지도 오래 됐고, 처음부터 안드로이드에 적용하여 사용하다보니 안정성도 보장되어 있구요. 그런데 sqlite를 안드로이드에서 이용하기 위해서는 보일플레이트 코드가 많이 들어갑니다. Helper객체와 Provier객체가 필요하죠. 상황에 따라서는 Provider객체를 만들지 않고 사용할 수도 있지만요.

이번에 사용해보면서 나름 괜찮다고 생각되는 라이브러리입니다. Square에서 나온 Sqlbrite입니다. React programming을 할 수 있도록 도와줍니다.

sqlbrite git주소에 가면 dagger를 이용한 샘플이 존재합니다. 그런데 이 샘플은 square에서 내놓은 dagger1이죠. 

그래서 전 Dagger2를 이용한 샘플을 준비해 볼 까 합니다.

이전에 Dagger2를 이용한 개발 방법을 얘기 한 적이 있습니다. 

Android 개발에서 Dagger2이용해보기.

Dagger1과 Dagger2는 DI관점에서는 차이가 없지만, 사용방법에 대해서는 조금 차이가 있습니다. 그건 

http://google.github.io/dagger/dagger-1-migration.html

의 내용을 보면 알기 쉬울 듯 합니다.

아직 library버전이 v0.x대의 버전입니다. 사실 오픈소스 라이브러리를 v1.x대가 아니라면 사용하는데 꺼려지긴 합니다. 그래서 이걸 사용하는데 믿음직한 이유가 제이크 왓슨 형님과 스퀘어에서 내놨다는 이유이지 않을 까 합니다 하하.

샘플은 

https://github.com/drcarter/Dagger2Example

에 있습니다. Sqlbrite에 있는 샘플과 같은 내용이지만 단지 Dagger2로 변경한 부분입니다.

반응형
반응형

얼마전 제 블로그의 포스트에서 Dagger2를 이용하는 방법을 간단하게 적어보았습니다.

Android 개발에서 Dagger2이용해보기.

그런데 여기서 @Scope에 대한 설명이 없었던 것 같습니다.

@Scope ... 실질적으로는 Dagger2에서는 @Singleton annotation을 많이 사용합니다. Singleton은 굳이 자세히 설명을 안해도 다들 잘 알고 계시리라 봅니다. 객체 주입에서 @Singleton annotation을 적용해 두면.. 전체 App의 Scope안에서 Singleton객체가 생성되어 주입 됩니다. 그렇다면 다른 custom scope는 없을까요? 물론 @Scope annotation의 custom을 만들어서 사용합니다. 예를 들어서 Activity life cycle에서만 존재할 수 있는 객체 주입을 위해선 @PerActivity라던지 아니면 fragment life cycle에서만 객체 주입이 유지될 수 잇는 @PerFragment같은 custome scope annotation을 만들어 사용할 수 있습니다.



http://fernandocejas.com/wp-content/uploads/2015/04/composed_dagger_graph1.png


그럼 @Scope 를 이용한 예를 들어 볼 까 합니다.

이전에 예를 들었던 포스트인

Fragment에서 onActivityResult 결과 받기.

의 내용을 Dagger2를 이용한 방법으로 변경할려고 합니다. 주된 내용은 기존의 내용에서 EventBus객체를 Singleton pattern으로 생성해서 사용했습니다. 그럼 Dagger2를 이용해서 해당 샘플을 변경하면 어떻게 될까요?

우선 EventBus.java 입니다.

public class EventBus extends Bus {
private Handler handler = new Handler(Looper.getMainLooper());
@Override
public void post(final Object event) {
if (Looper.myLooper() == Looper.getMainLooper()) {
super.post(event);
} else {
handler.post(new Runnable() {
@Override
public void run() {
EventBus.super.post(event);
}
});
}
}
}

보시는 것과 같이 일반 객체와 별 다를 게 없습니다.


그럼 EventBusModule.java 입니다.

@Module
public class EventBusModule {
@Singleton
@Provides
EventBus provideEventBus() {
return new EventBus();
}
}

해당 모듈에서 EventBus를 제공해줄 때 @Singleton annotation이 붙었습니다. 이건 해당 객체를 Singleton으로 제공해 준다는 겁니다.


그리고 EventBusModule의 객체를 Inject를 하기 위한 Bridge역활을 해주는 ApplicationComponent.java 입니다.

@Singleton
@Component(
modules = {
ApplicationModule.class,
EventBusModule.class
}
)
public interface ApplicationComponent {
EventBus getEventBus();
}

해당 Component도 @Singletone으로 적용해두었습니다.


해당 Component자체도 Singleton scope에서 사용하겠다는 내용 입니다.


만약 Activity life cycle에서만 사용할 수 있는 scope를 만든다면

@Scope
@Retention(RUNTIME)
public @interface PerActivity {
}

로 만든다면 원하는 scope에다가 @PerActivity annotation을 적용하면 됩니다.


예제는..

https://github.com/drcarter/RetriveActivityResult 에서 retrive_activity_result_dagger 브랜치를 보시면 됩니다.

https://github.com/drcarter/RetriveActivityResult/tree/retrive_activity_result_dagger

반응형
반응형

개발을 여러 사람과 같이 하게 되면 각자만의 코드 스타일이 다르기 때문에 코딩 컨벤션은 어느정도 필요하다는 것을 알 수 있습니다. 그렇다고 누구 한명의 기준에 맞출 수도 없는 거죠.

안드로이드 개발자 사이트에 가면 자세히도 코딩 가이드라인이 존재합니다. 사실 개발하다보면 잘 안지키긴 하죠

Code Style Guidelines for Contributors

그럼 이 가이드라인을 지킬 수 있는 설정파일도 존재합니다.

https://github.com/android/platform_development/blob/master/ide/intellij/codestyles/AndroidStyle.xml

그럼 이 설정파일을 적용하는 방법입니다.


1. https://github.com/android/platform_development/blob/master/ide/intellij/codestyles/AndroidStyle.xml에 있는 파일을 다운로드 한다.


2. codestyle에 복사하기.

 - MacOS : ~/Library/Preferences/AndroidStudio{version}/codestyles/AndroidStyle.xml

 - Linux : ~/.AndroidStudio{version}/config/codestyles/AndroidStyle.xml

 - Windows : C:\Users\XXX\.AndroidStudio{version}\config\codestyles\AndroidStyle.xml


3. Preferences (or Settings) -> Editor -> Code Style -> Scheme 



이렇게 하면 코드 스타일이 미리 적용 됩니다.


반응형

+ Recent posts