Bing Wallpaper

마이크로소프트 사의 검색엔진 빙에서는 하루 1장의 월페이퍼를 공개한다.

아름다울 뿐 아니라, 고해상도라 이 월페이퍼를 받아주는 앱이나 pc용 프로그램이 많다. 마이크로소프트에서 20년 4월에 정식 프로그램을 출시했으니, 광고 없이 편하게 써보자.

참조

  • 다운로드 : https://www.microsoft.com/ko-kr/bing/bing-wallpaper

안드로이드 스투디오에 내장된 JRE에 인증서 추가하기

안드로이드 스투디오에 내장된 JRE에 인증서를 추가해보자.

$ keytool -import -noprompt -trustcacerts -alias aliasname -file "<인증서 파일>" -keystore "<안드로이드 스투디오 설치 경로>\Android Studio\jre\jre\lib\security\cacerts" -storepass changeit

안드로이드의 BuildConfig 활용

안드로이드는 앱을 빌드하는 과정에서 여러 파일을 자동으로 생성한다. BuildConfig 클래스도 그 중 하나로, 현재 빌드에 관한 정보를 상수 필드로 갖고 있어 코드에서 직접 참고할 수 있다.

package me.sunphiz.kotlin.myapplication;

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "me.sunphiz.kotlin.myapplication";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
}
if( BuildConfig.DEBUG )
{
    // 내 코드
}

파일은 /build/generated/source/buildConfig/.. 이하에 위치하고, <application id>.BuildConfig 의 이름을 갖는다.

기본 상수 외에 build.gradle를 통해 내가 필요한 필드를 직접 추가할 수도 있다. 이 상수는 빌드 타입에 따라 buildType 뿐 아니라 defaultConfig, productFlavors에도 선언이 가능하다. buildConfig를 여러 개 선언하다보면 번거로워진다. 이 때 Groovy의 맵 자료 구조 iteration을 이용하면, 아래처럼 buildConfig 값을 맵 형식으로 따로 정리할 수 있다.

ext {
    extraStringBuildConfig = [ NAME : '"Dog발자"' ]
    extraBooleanBuildConfig = [ KOREAN : 'true' ]
}

android {
    defaultConfig {
        ...

        extraStringBuildConfig.each{ k, v ->
            buildConfigField 'String', k, v
        }

        extraBooleanBuildConfig.each{ k, v ->
            buildConfigField 'boolean', k, v
        }
    }
    ...
}

그 밖에

참조

Glide 이미지 라이브러리 커스터마이징

Glide의 커스터마이징은 공식 문서(영문)에 더 자세히 설명되어 있다. 내게 필요한 기능이 무엇인지 참고하고, 더 자세한 내용은 꼭 공식 문서를 보자.

Glide는 Fresco, Picasso, Universal Image Loader 등과 함께 안드로이드에서 손 꼽히는 이미지 라이브러리다. Glide를 이용하면 원격지(remote)/로컬(local) 이미지를 가져와 화면에 표시할 수 있다. 가져온 이미지는 캐싱을 통해 로딩 속도를 개선할 수 있으며, 필요하다면 이미지 모서리 깎기(rounding)같은 재처리와 애니메이티드 gif도 표시할 수 있다. 따로 HTTP 라이브러리를 쓰지 않고 동작하지만, Volley나 OkHttp 라이브러리와도 호환 동작할 수 있다. 이제는 사라진 범프(Bump) 앱에서 사용할 목적으로 개발/적용한 것이 이 라이브러리의 시작으로 알려져 있다.

Glide의 사용법은 쉬울 뿐 아니라 공식 문서(영문)가 예시와 함께 친절하게 작성되어 있다. 그러므로, 여기서는 기본적인 사용방법 보다는 Glide의 AppGlideModule를 통해 Glide의 동작을 커스터마이징을 할 수 있는 고급 옵션들에 대해 살펴보자.

Glide의 고급 설정(configuration)을 위해서는 준비가 필요하다.

  1. AppGlideModule 추상클래스의 구현체 추가
  2. @GlideModule 어노테이션을 구현체에 선언
  3. 구현체 컴파일을 위해 build.gradle에 Glide 어노테이션 프로세서 추가
  4. 프로가드 설정에 AppGlideModule 클래스의 -keep 선언 추가

준비가 끝나면, 아래와 같이 구현체의 applyOptions() 안에 고급 설정을 추가할 수 있다.

@GlideModule
public class YourGlideModule extends AppGlideModule
{
    @Override
    public void applyOptions( Context _context, GlideBuilder _builder )
    {
        // 고급 설정 추가
    }
}

메모리 캐시

GlideBuilder.setMemoryCache()를 통해, 메모리 캐시 크기를 정할 수 있다. 캐싱할 화면의 갯수를 정수로 지정하거나 직접 캐시 크기를 지정할 수 있다. 화면의 갯수로 지정할 때는  앱의 가장 긴 화면을 염두하여 지정하면 같은 이미지를 원격지에서 반복적으로 로딩하지 않고 캐싱할 수 있을 것이다.

비트맵 풀

GlideBuilder.setBitmapPoolScreens()를 통해, 비트맵 캐시 크기를 정할 수 있다. 정하는 방법은 메모리 캐시와 유사하다.

디스크 캐시

GlideBuilder.setDiskCache()를 통해, 디스크 캐시를 위한 폴더 이름과 디스크 캐시 폴더의 최대 용량를 정할 수 있다. 폴더의 기본 이름은 ‘glide’, 용량은 250mb이다.

리퀘스트 옵션 기본 값 변경

GlideBuilder.setDefaultRequestOptions()에 RequestOptions 객체를 전달하는 방식으로 변경할 수 있다. Glide.with() 메소드에서 반환하는 RequestManager.apply()를 통해 매 이미지 요청마다 설정할 수도 있지만, 여기서 설정하면 모든 요청의 기본 값으로 적용된다.

이미지 저장 방식(원본만, 재처리 후 사본 만, 모두)이나, 출처(원격지만, 로컬만, 모두), 이미지의 decode 포멧 등을 명시적으로 선언할 수 있다.

로그

GlideBuilder.setLogLevel()을 통해, 로그 레벨을 조절할 수 있다. 개발할 때는 Log.DEBUG, 공개할 때는 Log.ERROR 정도가 적당해 보인다.

모든 설정을 추가한다면, 아래와 같은 코드가 될 수 있다.

@GlideModule
public class YourGlideModule extends AppGlideModule 
{
    @Override
    public void applyOptions( Context _context, GlideBuilder _builder )
    {
        // 메모리 캐시
        MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context).setMemoryCacheScreens(2).build();
        _builder.setMemoryCache(new LruResourceCache(calculator.getMemoryCacheSize()));

        // 비트맵 풀
        int bitmapPoolSizeBytes = 1024 * 1024 * 30; // 30mb
        _builder.setBitmapPool(new LruBitmapPool(bitmapPoolSizeBytes));

        // 디스크 캐시
        int diskCacheSizeBytes = 1024 * 1024 * 100; // 100 MB
        _builder.setDiskCache(new InternalCacheDiskCacheFactory(context, "cacheFolderName", diskCacheSizeBytes));

        // 리퀘스트 옵션 기본 값
        _builder.setDefaultRequestOptions(new RequestOptions().format(DecodeFormat.RGB_565).disallowHardwareBitmaps());

        // 로그 레벨
        _builder.setLogLevel(Log.DEBUG);
    }
}

그 밖에

참조