저작권 안내: 저작권자표시 Yes 상업적이용 No 컨텐츠변경 No

스프링5 입문

JSP 2.3

JPA 입문

DDD Start

인프런 객체 지향 입문 강의

안드로이드의 ImageView에 출력할 수 있는 이미지 크기에 제한이 있는데, 이 제한은 장치마다 다르다. 예를 들어, 넥서스7의 경우는 2048*2048 이내의 이미지를 출력할 수 있고, 갤럭시노트10.1의 경우 4096*4096 이내의 이미지를 출력할 수 있다. 만약 제한 크기를 넘는 이미지를 ImageView를 통해 보여주려고 하면 다음과 비슷한 메시지가 로그에 출력되면서 ImageView에 이미지가 출력되지 않게 된다.


W/OpenGLRenderer(6156): Bitmap too large to be uploaded into a texture (560x6076, max=2048x2048)


ImageView에 표시할 수 있는 이미지의 제한 크기를  알아내려면 OpenGL의 glGetIntegerv() 메서드를 사용하면 된다. 이 메서드를 사용하려면 OpenGL Context를 생성해주어야 하는데, SurfaceView를 이용하면 간단하게 알아낼 수 있다.


다음은 SurfaceView와 OpenGL을 이용해서 제한 크기를 알아내는 코드 예이다.


import java.nio.IntBuffer;

import javax.microedition.khronos.egl.EGL10;

import javax.microedition.khronos.egl.EGLContext;

import javax.microedition.khronos.opengles.GL10;

import android.view.SurfaceHolder;

import android.view.SurfaceView;

...


public class SplashActivity extends Activity {


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.splash_layout);

LinearLayout layout = (LinearLayout) findViewById(R.id.body);

layout.addView(new GetMaxTextureSizeSurfaceView(this));

}


private void goHome() {

Intent intent = new Intent(this, HomeActivity.class);

startActivity(intent);

finish();

}


class GetMaxtextureSizeSurfaceView extends SurfaceView implements

SurfaceHolder.Callback {


public GetSizeSurfaceView(Context context) {

super(context);

SurfaceHolder holder = getHolder();

holder.addCallback(this);

}


@Override

public void surfaceCreated(SurfaceHolder holder) {

setMaxTextureSize();

goHome();

}


private void setMaxTextureSize() {

EGL10 egl = (EGL10) EGLContext.getEGL();

EGLContext ctx = egl.eglGetCurrentContext();

GL10 gl = (GL10) ctx.getGL();

IntBuffer val = IntBuffer.allocate(1);

gl.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, val);

int size = val.get(); // 최대 크기 구함

Constants.setMaxTextureSize(size); // Constants는 글로벌 변수 저장용

}


@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}


@Override

public void surfaceDestroyed(SurfaceHolder holder) {

}


}

}


최초로 실행되는 Activity에서 위와 같이 glGetIntegerv() 함수를 이용해서 최대 크기 값을 글로별 변수에 저장하면, 이후 Activity에서는 글로벌 변수를 이용해서 Bitmap 크기가 최대 크기를 넘어섰는지 확인할 수 있다. 만약 최대 크기를 넘어섰다면 이미지를 허용까지 줄여서 출력하면 된다.


주의할 점은 SurfaceView가 화면에 반드시 보여야 한다는 점이다. 화면에 보이지 않게 되면 관련 콜백 메서드(surfaceCreated() 등)가 호출되지 않는다. GetSizeSurfaceView는 단순히 최대 크기를 알아내기 위해 만든 것이므로 1px 정도의 크기를 갖는 Layout에 SurfaceView를 추가하는 방법으로 SurfaceView를 생성하면 화면에 영향을 거의 안 주면서 SurfaceView를 이용해서 MAX_TEXTURE_SIZE 값을 구할 수 있을 것이다.


이미지 크기를 알아내고 크기를 변경하는 방법은 다음에 정리해보겠다.



Posted by 최범균 madvirus

댓글을 달아 주세요

  1. baeflower 2015.04.02 16:43 신고  댓글주소  수정/삭제  댓글쓰기

    감사합니다 큰 도움이 됐습니다!

특정 URL 이미지를 목록에서 보여주어야 할 때, 동일 URL 이미지를 매번 다운로드 받아 출력하면 비효율적일 뿐만 아니라 사용자에게 보여지는 응답도 느려지게 된다. 사용자에게 응답을 빠르게 보여주기 위해서는 URL 이미지를 메모리나 로컬 파일에 캐싱하도록 구현해야 한다. 이미지를 캐싱함으로써, 동일 URL 이미지를 보여주어야 할 때 다운로드 없이 빠르게 이미지를 사용자에게 보여줄 수 있게 된다.


본 글에서는 이미지를 위한 캐시를 만들어보도록 하겠다. 실제 URL로부터 이미지를 읽어와 캐시에 담고 ImageView에 다운로드 받은 이미지를 보여주는 코드는 '안드로이드에서 URL 이미지를 ImageView에 보여주기' 글을 참고하기 바란다.


이미지 캐시 기능


제공할 기능은 다음과 같다.

  • 이미지 메모리 캐시를 제공한다.
    • 메모리에 지정 개수 만큼의 이미지를 보관한다.
  • 이미지 메모리/파일의 2레벨 캐시를 제공한다. 
    • 캐시에 이미지를 보관하면 메모리와 파일에 동시에 보관된다.
    • 메모리 캐시는 보관할 수 있는 개수에 제한이 있다.
    • 파일 캐시는 보관할 수 있는 전체 크기에 제한이 있다. ('안드로이드에서 파일 캐시 구현하기' 글에서 만든 파일 캐시를 사용해서 구현한다.)
    • 메모리 캐시에 없으면, 파일 캐시로부터 이미지를 읽어온다.

2레벨 캐시를 사용할 경우 자주 사용되는 이미지는 메모리에 담고 일정 크기만큼의 이미지는 파일로도 보관한다. 이를 통해 메모리 용량의 사용을 일정 수준으로 유지하면서 동시에 네트워크 사용을 최소화해서 사용자에게 이미지를 빠르게 보여줄 수 있다.


이미지 캐시  클래스 구성


구현할 이미지 캐시의 클래스 구성은 아래와 같다.



구성요소

설명 

ImageCacheFactory

ImageCache의 생성 및 검색 기능을 제공한다. 

ImageCache

이미지 캐시를 위한 인터페이스를 제공한다. 

MemoryImageCache

메모리 기반의 이미지 캐시를 구현한다. 

FileImageCache 

파일 기반의 이미지 캐시를 구현한다.

ChainedImageCache 

캐시 체인 기능을 제공한다.


ImageCache 인터페이스


public interface ImageCache {


public void addBitmap(String key, Bitmap bitmap);


public void addBitmap(String key, File bitmapFile);


public Bitmap getBitmap(String key);


public void clear();


}


MemoryImageCache 클래스


MemoryImageCache는 내부적으로 LruCache를 사용해서 구현하였다.


package com.toonburi.app.infra.imagecache;


import java.io.File;


import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.support.v4.util.LruCache;


public class MemoryImageCache implements ImageCache {


private LruCache<String, Bitmap> lruCache;


public MemoryImageCache(int maxCount) {

lruCache = new LruCache<String, Bitmap>(maxCount);

}


@Override

public void addBitmap(String key, Bitmap bitmap) {

if (bitmap == null)

return;

lruCache.put(key, bitmap);

}


@Override

public void addBitmap(String key, File bitmapFile) {

if (bitmapFile == null)

return;

if (!bitmapFile.exists())

return;


Bitmap bitmap = BitmapFactory.decodeFile(bitmapFile.getAbsolutePath());

lruCache.put(key, bitmap);

}


@Override

public Bitmap getBitmap(String key) {

return lruCache.get(key);

}


@Override

public void clear() {

lruCache.evictAll();

}


}


FileImageCache 클래스


FileImageCache는 앞서 '안드로이드에서 파일 캐시 구현하기'에서 만든 파일 캐시를 이용해서 구현하였다. 코드는 다음과 같다.


public class FileImageCache implements ImageCache {

private static final String TAG = "FileImageCache";


private FileCache fileCache;


public FileImageCache(String cacheName) {

fileCache = FileCacheFactory.getInstance().get(cacheName);

}


@Override

public void addBitmap(String key, final Bitmap bitmap) {

try {

fileCache.put(key, new ByteProvider() {

@Override

public void writeTo(OutputStream os) {

bitmap.compress(CompressFormat.PNG, 100, os);

}

});

} catch (IOException e) {

Log.e(TAG, "fail to bitmap to fileCache", e);

}

}


@Override

public void addBitmap(String key, File bitmapFile) {

try {

fileCache.put(key, bitmapFile, true);

} catch (IOException e) {

Log.e(TAG, String.format("fail to bitmap file[%s] to fileCache",

bitmapFile.getAbsolutePath()), e);

}

}


@Override

public Bitmap getBitmap(String key) {

FileEntry cachedFile = fileCache.get(key);

if (cachedFile == null) {

return null;

}

return BitmapFactory.decodeFile(cachedFile.getFile().getAbsolutePath());

}


@Override

public void clear() {

fileCache.clear();

}


}


위 코드에서 유의할 점은 FileImageCache 객체를 생성할 때, 파라미터로 전달받은 cacheName을 이용해서 FileCache를 구한다는 점이다. 즉, FileImageCache의 이름과 동일한 이름을 갖는 FileCache가 존재해야 정상적으로 동작한다. 따라서, FileImageCache를 사용하기 전에 다음과 같이 이미지 캐시와 동일한 이름을 갖는 FileCache를 생성해 주어야 한다.


// onCreate 등에서 파일을 이용하는 이미지 캐시 생성 전에 초기화

FileCacheFactory.getInstance().create(cacheName, cacheSize);


ChainedImageCache 클래스


이미지 캐시와 파일 캐시를 1차/2차 캐시로 사용하기 위해 ChainedImageCache 클래스를 만들었다.


public class ChainedImageCache implements ImageCache {


private List<ImageCache> chain;


public ChainedImageCache(List<ImageCache> chain) {

this.chain = chain;

}


@Override

public void addBitmap(String key, Bitmap bitmap) {

for (ImageCache cache : chain) {

cache.addBitmap(key, bitmap);

}

}


@Override

public void addBitmap(String key, File bitmapFile) {

for (ImageCache cache : chain) {

cache.addBitmap(key, bitmapFile);

}

}


@Override

public final Bitmap getBitmap(String key) {

Bitmap bitmap = null;

List<ImageCache> previousCaches = new ArrayList<ImageCache>();

for (ImageCache cache : chain) {

bitmap = cache.getBitmap(key);

if (bitmap != null) {

break;

}

previousCaches.add(cache);

}

if (bitmap == null)

return null;


if (!previousCaches.isEmpty()) {

for (ImageCache cache : previousCaches) {

cache.addBitmap(key, bitmap);

}

}

return bitmap;

}


@Override

public final void clear() {

for (ImageCache cache : chain) {

cache.clear();

}

}


}


ChainedImageCache는 chain에 등록되어 있는 모든 ImageCache를 차례대로 실행한다. getBitmap()은 약간 복잡하다. getBitmap()은 체인을 따라 Bitmap이 존재할 때까지 탐색한다. Bitmap이 발견되면 해당 캐시 이전에 위치한 캐시들(previousCaches에 보관됨)에 Bitmap 정보를 추가해서, 이후 동일 키로 요청이 오면 체인의 앞에서 발견되도록 한다.


ImageCacheFactory 클래스


ImageCacheFactory는 캐시 생성 기능을 제공한다.


public class ImageCacheFactory {


private static ImageCacheFactory instance = new ImageCacheFactory();


public static ImageCacheFactory getInstance() {

return instance;

}


private HashMap<String, ImageCache> cacheMap = new HashMap<String, ImageCache>();


private ImageCacheFactory() {

}


public ImageCache createMemoryCache(String cacheName, int imageMaxCounts) {

synchronized (cacheMap) {

checkAleadyExists(cacheName);

ImageCache cache = new MemoryImageCache(imageMaxCounts);

cacheMap.put(cacheName, cache);

return cache;

}

}


private void checkAleadyExists(String cacheName) {

ImageCache cache = cacheMap.get(cacheName);

if (cache != null) {

throw new ImageCacheAleadyExistException(String.format(

"ImageCache[%s] aleady exists", cacheName));

}

}


public ImageCache createTwoLevelCache(String cacheName, int imageMaxCounts) {

synchronized (cacheMap) {

checkAleadyExists(cacheName);

List<ImageCache> chain = new ArrayList<ImageCache>();

chain.add(new MemoryImageCache(imageMaxCounts));

chain.add(new FileImageCache(cacheName));

ChainedImageCache cache = new ChainedImageCache(chain);

cacheMap.put(cacheName, cache);

return cache;

}

}


public ImageCache get(String cacheName) {

ImageCache cache = cacheMap.get(cacheName);

if (cache == null) {

throw new ImageCacheNotFoundException(

String.format("ImageCache[%s] not founds"));

}

return cache;

}

}


createMemoryCache() 메서드는 메모리만 사용하는 ImageCache를 생성한다. createTwoLevelCache() 메서드는 1차 메모리/2차 파일 기반의 2레벨 캐시를 생성한다.


이미지 캐시 사용하기


다음은 이미지 캐시의 사용 예시이다.


-- onCreate 등 초기화 부분


// 2레벨 캐시(이미지 파일 캐시)를 사용하려면 동일 이름의 파일 캐시를 생성해 주어야 한다.

FileCacheFactory.getInstance().create(cacheName, cacheSize);


// 이미지 캐시 초기화

ImageCacheFactory.getInstance().createTwoLevelCache(cacheName, memoryImageMaxCounts);



-- 이미지 캐시 사용 부분

ImageCache imageCache = ImageCacheFactory.getInstance().getCache(cacheName);

Bitmap bitmap = imageCache.getBitmap(key);

if (bitmap != null) {

imageView.set.....

}


-- 이미지 캐시 추가 부분

imageCache.putBitmap(key, someBitmap);


실제 ImageCache를 사용하는 예제 코드는 '안드로이드에서 URL 이미지를 ImageView에 보여주기'에 있으니 이 글을 참고하면 된다.


관련자료



Posted by 최범균 madvirus

댓글을 달아 주세요

  1. bluepoet 2013.01.31 17:35 신고  댓글주소  수정/삭제  댓글쓰기

    저도 이번 스타앱 리뉴얼때, 프로게이머 프로필 이미지쪽을 구현할 예정이었는데

    이번 포스팅이 많이 참고가 되겠네요.

    특히나, 체인을 이용한 캐시 구현방법은 참 신선하네요.

    근데, previousCaches에 정보를 넣고 활용하는 쪽은 좀 어렵네요.

    동일 키로 요청이 오면 어떻게 체인의 앞에서 발견되도록 하는 건지 궁금합니다.

  2. andu 2013.05.16 13:28 신고  댓글주소  수정/삭제  댓글쓰기

    FileImageCache 클래스에서 fileCache.clear()가 사용되는데,

    FileCache 클래스에는 clear()가 없네요. 새로 추가된 메소드인가요?

  3. truelifer 2013.10.10 17:13 신고  댓글주소  수정/삭제  댓글쓰기

    좋은 포스팅 감사합니다.
    저도 한가지 의문이 있는건, bluepoet 님이 문의하신 것 처럼 동일 키로 요청이 오면 어떻게 체인의 앞에서 발견되도록 하는건지 궁금합니다.
    코드를 보니 previousCaches 를 따로 저장하지 않고 getBitmap() 함수가 끝나면 previousCaches 가 소멸될 것 같은데..

    • 최범균 madvirus 2013.10.11 09:09 신고  댓글주소  수정/삭제

      previousCaches 라는 로컬 변수는 사라지지만, previousCache에 담은 객체는 chain 필드에 보관되어 있는 ImageCache 입니다.
      getBitmap() 메서드를 보시면, chain에 있는 ImageCache를 차례대로 탐색하면서 해당 ImageCache가 key에 해당하는 비트맵을 갖고 있는 지 확인을 합니다. 갖고 있으면, for 루프를 나오고, 아니면 (로컬 변수인) previousCaches에 ImageCache를 추가합니다.

      발견된 Bitmap이 없으면 그냥 null을 리턴하고, 발결된 Bitmap이 있으면, previousCaches에 담아 두었던 ImageCache들의 addBitmap을 호출해서 비트맵을 추가해줍니다. 여기서 previousCaches에는 chain에서 비트맵이 발견되기 전까지의 ImageCache 목록을 갖고 있게 되죠. 따라서, chain의 특정 ImageCache에서 비트맵이 발견되면, 그 ImageCache 이전에 있던 ImageCache들에 비트맵을 추가하게 됩니다.

  4. winterCha 2013.10.17 16:38 신고  댓글주소  수정/삭제  댓글쓰기

    정말 감사합니다 아주 투통이 사라지는 캐쉬 로직이네요
    태클아닌 태클 하나.....

    checkAlreadyExists 를 표현 하고 싶으신것 같은데 r이 빠졌네요
    쏘리욤

    madvirus fan 입니다 최범균님 책으로 참 많은 것을 공부 했었던 기억이

    존경합니다.

  5. cs만두 2014.05.19 22:22 신고  댓글주소  수정/삭제  댓글쓰기

    안녕하세요 안드로이드에 관심이 많은 대학생 개발자입니다!
    몇달전 프로젝트를 진행하면서 bitmap OOM관련 이슈때문에 고민을 하다가 AUIL 라이브러리를 사용해서 해결했습니다. 그러면서 꼭 시간나면 이미지 로더 관련해서 공부해봐야겠다 생각했는데 이렇게 좋은 글을 만나서 너무 좋습니다.
    좋은 글 감사합니다! 열심히 공부하겠습니다!!!!!!

  6. 이승화 2014.05.23 16:59 신고  댓글주소  수정/삭제  댓글쓰기

    감사합니다. 덕분에 좀더 쉽게 코딩할수 있게 되었습니다.
    책도 많이 쓰셨던데 짱~ 이십니다ㅋ

  7. 최형식 2015.03.25 14:07 신고  댓글주소  수정/삭제  댓글쓰기

    지도 앱을 만들고 있습니다. svg파일로 하든 png로 하든 비트맵으로 변경해서 보여주려고 합니다. 사이즈가 크다 보니 타일처럼 짤라서 화면밖의 타일들은 캐시로, 이미지가 움직이면 캐시에서 불러오고 이런식으로 하고싶은데 어떤 방법이 있나요?

  8. 최수혁 2015.05.22 11:03 신고  댓글주소  수정/삭제  댓글쓰기

    안녕하세요?
    이 글 보고 안드로이드 이미지 캐시를 완벽하게 구현하였습니다.
    그런데 문제가 하나 있습니다.

    A라는 이름으로 캐시를 하나 창조해서 다운로드 해서 이미지를 모두 넣었습니다.
    그 다음 액티비티에서 B라는 이름으로 캐시를 하나 또 창조했는데 다운로드되지 않고 있습니다.
    캐시창조할때에는 모두 오류가 없는데 이상하게 onResult에는 안들어오네요..

    B와 A의 순서를 바꾸어도 역시 2번째는 작동을 안합니다.

    왜그럴가요?

    도저히 원인을 못찾겠네요.

    • 최범균 madvirus 2015.05.23 00:47 신고  댓글주소  수정/삭제

      코드를 바꾸지 않으셨다면, 코드에 버그가 있는 거겠죠. 지금은 졸려서 코드가 눈에 잘 안 들어오네요. 좀 맨 정신에 코드 보고 답글 달아보렵니다.

안드로이드에서 2회 연속 백버튼을 눌러서 앱을 종료시키는 경우가 흔한데, 이 기능은 많이 사용되므로 다음과 같이 별도 클래스로 기능을 분리하면 향후 기능 재사용이 편리하다.


public class BackPressCloseHandler {


private long backKeyPressedTime = 0;

private Toast toast;


private Activity activity;


public BackPressCloseHandler(Activity context) {

this.activity = context;

}


public void onBackPressed() {

if (System.currentTimeMillis() > backKeyPressedTime + 2000) {

backKeyPressedTime = System.currentTimeMillis();

showGuide();

return;

}

if (System.currentTimeMillis() <= backKeyPressedTime + 2000) {

activity.finish();

toast.cancel();

}

}


private void showGuide() {

toast = Toast.makeText(activity, "\'뒤로\'버튼을 한번 더 누르시면 종료됩니다.",

Toast.LENGTH_SHORT);

toast.show();

}


}


BackPressCloseHandler의 구현은 간단하다.

  • backKeyPressedTime은 백버튼이 눌린 마지막 시간을 기록한다.
  • onBackPressed() 메서드는 현재 시간이 마지막 백버튼 누른 시간으로부터 
    • 2초 이상 지났으면, 마지막 백버튼 눌린 시간을 현재 시간으로 갱신하고 showGuide()를 실행한다.
    • 2초 이상 지나지 않았으면, Activity를 종료한다.
    • 참고로, 2초는 Toast.LENGTH_SHORT의 기본 값이다.
  • showGuide() 메서드는 Toast를 이용해서 메시지를 출력한다.

2회 연속 백버튼 누를 때 종료시키고 싶은 Activity가 있다면, 다음과 같이 사용한다.

  • BackPressCloseHandler 타입의  backPressCloseHandler 필드를 추가한다.
  • onCreate() 메서드에서 BackPressCloseHandler 객체를 생성해서 필드에 할당한다.
  • onBackPressed() 메서드에서 backPressCloseHandler.onBackPressed()를 호출한다.
아래 코드는 실제 적용한 코드의 일부를 발췌한 것이다.


public class HomeActivity extends Activity ... {


private BackPressCloseHandler backPressCloseHandler;


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.home_layout);

...

backPressCloseHandler = new BackPressCloseHandler(this);

}


@Override

public void onBackPressed() {

backPressCloseHandler.onBackPressed();

}

}


Posted by 최범균 madvirus

댓글을 달아 주세요

  1. morcavon 2014.04.14 22:58 신고  댓글주소  수정/삭제  댓글쓰기

    유용한 정보 감사합니다 :-)

  2. Thankx 2015.05.28 21:12 신고  댓글주소  수정/삭제  댓글쓰기

    감사합니다. ㅜ.ㅜ~

  3. 므시칸곰틔군 2015.08.04 11:27 신고  댓글주소  수정/삭제  댓글쓰기

    정보 감사합니다.

  4. 전동화 2016.12.19 14:25 신고  댓글주소  수정/삭제  댓글쓰기

    좋은 정보 감사합니다.

필자는 Maven을 너무 좋아하기에 안드로이드 개발도 Maven 프로젝트로 관리하고 싶었다. 그래서 구글링을 좀 했고, 영어로 된 걸 매번 보고 싶지 않아 나중을 위해 한글로 정리해둔다.


M2E를 위한 Android Connector 설치


먼저 할 일은 이클립스에 설치한 Maven 플러그인과 ADT를 연결하는 위해 Android Connector를 설치하는 것이다. 설치를 하려면 Preferences > Android/Discovery > Open Catalog 메뉴를 실행한 뒤, 아래 그림이 나올 때 android로 검색하면 된다.



검색 결과로 나온 Android Connector를 선택한 뒤 설치하자.


Android용 Archetype 추가 (옵션)


Android Connector를 설치 후, pom.xml 파일에 maven-android-plugin을 설정하면 해당 프로젝트를 ADT와 연동해 준다. 하지만, pom.xml 파일을 처음부터 만들면 (다소) 귀찮을 수 있는데, 그걸 대신 해주는 archetype을 추가해주면 좀 더 편하게 pom.xml 파일을 생성할 수 있다.


Archetype 타입을 추가해주는 방법은 간단하다. New > Maven Project > Next > Select an Archetype 화면에서 [Add Archetype...] 버튼을 클릭한다. 그런 다음 아래와 같이 정보를 입력하고 [OK] 버튼을 클릭하면 해당 Archetype이 추가된다.


* Group Id: de.akquinet.android.archetypes

* Artifact Id: android-quickstart

* Version: 1.0.8


안드로이드 프로젝트 생성하기


안드로이드 프로젝트를 생성하는 방법은 간단하다. 앞서 생성한 android-quickstart Archetype을 이용해서 안드로이드 프로젝트를 생성하면 된다. android-quickstart Archetype을 선택하면 아래 그림과 같은 화면이 나온다. platform의 값에 사용할 안드로이드 플랫폼 버전을 입력해주면 된다.



프로젝트를 생성하면 잠시 후 아래 그림과 같이 Maven 프로젝트가 ADT와 연동된 것을 확인할 수 있다. 아래 그림을 보면 자원 관리를 위한 res 폴더, 자동 생성되는 파일을 위한 gen 폴더 등이 생성된 것을 확인할 수 있다.



생성된 pom.xml 파일을 maven-android-plugin 설정 및 플랫폼 버전 정보 등이 포함된 것을 확인할 수 있다.


<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.madvirus</groupId>

    <artifactId>NetworkExplorer</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>apk</packaging>

    <name>NetworkExplorer</name>


    <properties>

        <platform.version>2.3.2</platform.version>

    </properties>


    <dependencies>

        <dependency>

            <groupId>com.google.android</groupId>

            <artifactId>android</artifactId>

            <version>${platform.version}</version>

            <scope>provided</scope>

        </dependency>

    </dependencies>


    <build>

        <plugins>

            <plugin>

                <groupId>com.jayway.maven.plugins.android.generation2</groupId>

                <artifactId>android-maven-plugin</artifactId>

                <version>3.1.1</version>

                <configuration>

                    <androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>

                    <assetsDirectory>${project.basedir}/assets</assetsDirectory>

                    <resourceDirectory>${project.basedir}/res</resourceDirectory>

                    <nativeLibrariesDirectory>${project.basedir}/src/main/native</nativeLibrariesDirectory>

                    <sdk>

                        <platform>10</platform>

                    </sdk>

                    <undeployBeforeDeploy>true</undeployBeforeDeploy>

                </configuration>

                <extensions>true</extensions>

            </plugin>


            <plugin>

                <artifactId>maven-compiler-plugin</artifactId>

                <version>2.3.2</version>

                <configuration>

                    <source>1.6</source>

                    <target>1.6</target>

                </configuration>

            </plugin>

        </plugins>

    </build>

</project>




참고로, Android Connector와 android-maven-plugin인에 대한 보다 자세한 내용이 궁금하면 아래 사이트를 방문해서 확인하면 된다.


Posted by 최범균 madvirus

댓글을 달아 주세요

  1. 예감 2013.07.29 12:09 신고  댓글주소  수정/삭제  댓글쓰기

    Maven관련 자료 잘보고 갑니다^^