(안드로이드) 파일 저장하기

안드로이드는 다르 플랫폼의 디스크 기반 파일시스템과 유사한 파일 시스템을 사용한다. File객체는 건너띄는 것 없이 처음부터 끝까지 순서대로 많은 양의 데이터를 읽고 쓰는데 적합하다. 예를들어, 이미지 파일이나 네트워크를 통해 변경되어지는 것들을 저장흐넨ㄷ 좋다. 내부 또는 외부 저장장치 선택 모든 안드로이드 단말기들은 두개의 파일 저장 영역을 가지고 있다. "Internal" 과 "External" 저장장치 이 저장소의 이름들은 안드로이드 이전부터 만들어져 있던 것들입니다. 대부분의 단말기들은 내장되어 있는 비휘발성 메모리(내부 메모리)가 제공되어 있으며, 추가적으로 SD card(External Storage)와 같은 제거할 수 있는(removable) 저장장치를 가지고 있다.  내부 저장장치(Interanal Storage) 이 장치는 항상 사용할 수 있습니다. 이곳에 저장된 파일을 기본적으로는 오직 여러분의 앱에 의해서만 접속할 수 있다. 사용자가 여러분의 앱을 언인스톨할 때, 시스템은 내부저장소로부터 앱의 파일들을 모두 제거한다. 내부 저장소는 사용자든 다른 앱들이든 여러분의 파일에 접속할 수 없도록 하고 싶을때 사용하기 좋은 곳이다. 외부 저장장치(Interanal Storage) 이 장치는 항상 사용할 수는 없다. 왜냐하면 사용자가 USB저장장치처럼 외부저장소를마운트(mount) 할 수도있고, 어떤 경우에는 단말기에서 제거할 수도 있기 때문이다. 이 장치는 기본적으로 world-readable이다. 그래서 저장된 파일은 여러분의 제어밖에서(동의없이) 읽어질 수도 있다. 사용자가 여러분의 앱을 언인스톨할 때, 시스템은 여러분이 getExternalFilesDir()로 만든 디렉토리에 파일을 저장했을때만 자동으로 제거된다. 외부 저장소는 파일의 접속제한이 필요하지 않으며, 다른 앱들이나 사용자가 컴퓨터를 사용하여 접속하도록 공유하고 싶을 때 사용하기 좋은 곳이다. ...

(안드로이드) Bitmap 구현,관리하기

안드로이드에서 비트맵 관련 클래스는 android.graphics.Bitmap이다. 그래픽 관련 클래스들은 android.graphics패키지에 있으며 여기에 포함된 것이다. 그리고 객체 Factory관리를 위한 BitmapFactory클래스가 있다. BitmapFactory는 여러가지 이미지 포맷을 decode해서 bitmap으로 변환하는 함수들로 되어있는데, 그 이름들은decodeXXX로 되어있어서 쉽게 원하는 기능의 함수를 찾을수 있을 것이다. (1) BitmapFactory에서 주로 사용하고 있는함수와 옵션에 대한 설명 BitmapFactory.decodeFile() : 로컬에 존재하는 파일을 그대로 읽어올 때 쓴다. 파일 경로를 파라미터로 넘겨주면 FileInputStream을 만들어서 decodeStream을 한다.  ex) Bitmap orgImage=BitmapFactory.decodeFile("/sdcard/test.jpg"); BitmapFactory.decodeResource() : Resource폴더에 저장된 그림파일을 Bitmap으로 만들어 리턴해준다. ex) Bitmap orgImage=BitmapFactory.decodeResource(getResources(), R.drawable.test02); BitmapFactory.decodeStream() : InputStream으로부터 Bitmap을 만들어준다. BitmapFactory.Options : BitmapFactory가 사용하는 옵션클래스이다. Options객체를 생성하고 설정하고자 하는 옵션을 넣은 후 BitmapFactory의 함수 실행시 파라미터로 넘기면 된다. inSampleSize: decode시 얼마나 줄일지 설정하는 옵션인데 1보다 작을떄는 1이된다. 1보다 큰값일때 1/N만큼 이미지를 줄여서 decoding하게된다. 보통 2의 배수로 설정한다. ex) BitmapFac...

(안드로이드) 이미지 로딩 처리(메모리캐시, 디스크캐시)

이미지
*안드로이드에서는 LruCache를 제공한다. LruCache는 LinkedHashMap을 사용하여 최근에 사용된 object의 strong reference를 보관하고 있다가 정해진 사이즈를 넘어가게 되면 가장 최근에 사용되지 않은 놈부터 쫒아내는 LRU알고리즘을 사용하는 메모리 캐시다. 예전에는 bitmapcache에 SoftReference나 WeakReference를 사용하는 방식을 썻으나 안드로이드 2.3부터 가비지 콜렉터가 공격적으로 이놈들의 메모리를 가비지 콜렉팅하면서 몹쓸 방법이 되었다. 게다가 이 방법은 3.0이전 버전에서 매모리 해제를 제대로 못해 크래쉬 문제도 있다. 그러나 LruCache를 사용해보겠다. LruCache의 캐시 사이즈를 정하기 위해서 고려할 사항 앱에서 앞으로 메모리를 얼마나 사용해야 하는가? 얼마나 많은 이미지들이 한 화면에 보여질 것인가? 얼마나 많은 이미지들이 다음에 보여주기 위해 준비되어야 하는가? 화면 해상도가 어떻게 되는가? 각 이미지마다 메모리를 얼마나 차지하는가? 이미지는 얼마나 자주 액세스 되는가? 질보다 양? 양보다 질? 어떤 경우에는 많은 양의 저해상도 이미지를 미리 보여주고 백그라운드로 고해상도 이미지를 로드하는 방법이 좋을 수도 있다. 너무 캐시사이즈를 작게하면 오버헤드만 발생하고, 사이즈를 너무 크게하면 OutOfMemoryException을 보게 된다. <아주 큰 비트맵을 효율적으로 로딩하기> 애플리케이션의 메모리 제한에 문제없이 비트맵을 로딩하는 방법. 이미지를 표시할 UI컴포넌트는 대체적으로 이미지보다 작게 표시된다. 이떄는 이미지의 원본사이즈가 아니라 표시될 컴포넌트의 크기에 맞게 로드하는것이 이득이다. BitmapFactory클래스가 비트맵을 디코딩하기 위한 여러 메소드(decodeByteArray(), decodeFile(), decodeResource())들을 제공한다. 이 메소드들은 비트맵을 디코딩할 때 메모리할당을 시도하...

(안드로이드) 파일명으로 리소스 가져오기

리소스 접근하는 방법이 여러가지가 있지만, Bitmap testImg=BitmapFactory.decodeResource(res,R.drawable.testRes0); 이런식으로 파일 ID로 리소스를 읽어와 사용하는 방법이 보편적이다. 그러나 리소스가 많을 경우 testImg=new Bitmap[10]; for(int i=0;i<10;i++)   testImg[i]=BitmapFactory.decodeResource(res,R.drawable.tesrRes0+i); 이런식으로 ID로 연산을 하여 읽어오다보면 ID가 꼬이는 경우 문제가 발생할 여지가 있다. 파일명이 순차적으로 되어 있다고 하더라도 이런식의 접근은 좋지 않은 방법이다. 이럴경우, int tmpID; testImge=new Bitmap[10]; for(int i=0;i<10;i++) {       tmpID=res.getIdentifier("testRes"+i,"drawable","com.android.android.test");       testImg[i]=BitmapFactory.decodeResource(res,tmpID); } 이런식으로 리소스 파일명으로 ID를 알아와 접근하는 방식을 사용할 수 있다. "패키지명: 타입/ 리소스명",null,null getIdentifier("com.android.android.test:drawable/testRes",null,null); "리소스명","타입","패키지명" getIdentifier("testRes","drawable","com.android.android.test");

(안드로이드) 파일명으로 리소스 가져오기

리소스 접근시 여러가지 방법이 있겠지만 Bitmap testImg = BitmapFactory.decodeResource(res, R.drawable.testRes0); 이런식으로 파일 ID로 리소스를 읽어와 사용하고 있었습니다. 그런데 리소스가 많을 경우  testImg = new Bitmap[10]; for(int i = 0; i < 10; i++)         testImg[i] = BitmapFactory.decodeResource(res, R.drawable.testRes0+i); 이런식으로 ID로 연산을 하여 읽어오다보면 ID가 꼬이는 경우 문제가 발생할 여지가 많더군요. 파일명이 순차적으로 되어 있다고 하더라도 이런식의 접근은 안좋은 방법인것으로 알고 있습니다. 이럴경우 int tmpID; testImg = new Bitmap[10]; for(int i = 0; i < 10; i++) {        tmpID = res.getIdentifier( "testRes"+i, "drawable" , "com.androidpub.android.test");        testImg[i] = BitmapFactory.decodeResource(res, tmpID); } 이런식으로 리소스 파일명으로 ID를 알아와 접근하는 방식을 사용할 수 있습니다. "패키지명 : 타입 / 리소스명", null, null getIdentifier("com.androidpub.android.test:drawable/testRes", null, null); 또는 "리소스명", "타입", "패키지명" getIdentifier("testRes", "drawable", "com.androidpub.android.test"...

(안드로이드) 스타트서비스와 바운드서비스 개요

*안드로이드 서비스 클래스는 애플리케이션이 백그라운드 작업을 시작시켜 수행할 수 있게 특별히 설계되었다. 작업을 빨리 수행하고 종료하는 브로드캐스트 수신자와 다르게, 서비스는 실행 시간이 길면서 사용자 인터페이스를 필요로하지 않는 작업을 수행하도록 설계되었다. <스타트 서비스> 스타트 서비스는 다른 애플리케이션 컴포넌트(예를들어, 액티비티나 브로드캐스트 수신자)에 의해 론칭된다. 그리고 서비스가 중단되거나 리소스 해제를 위해 안드로이드 런타임 시스템에 의해 소멸될 때까지 백그라운드로 무한정 실행된다. 이 서비스는 자신을 시작시킨 애플리케이션이 더 이상 포그라운드에 있지 않아도 계속 실행된다. 심지어는 실제로 서비스를 시작시킨 컴포넌트가 소멸될 경우에도 계속 실행된다. 기본적으로 이 서비스는 자신이 론칭되었던 애플리케이션 프로세스와 동일한 메인 스레드에서 실행된다. 이것을 로컬서비스 라고 한다. 따라서 CPU를 많이 사용하는 작업들은 그 서비스의 새로운 스레드에서 수행되도록 하는 것이 중요하다. 그리고 별도의 프로세스에서 서비스가 실행되는 것을 원격서비스 라고하며, 이때는 매니페스트 파일에 구성 변경을 해야 한다. 매니페스트 파일의 설정으로 서비스가 특별히 private(론칭된 프로세스 전용)으로 구성되지 않는다면 그 서비스는 같은 안드로이드 장치의 다른 컴포넌트에 의해 시작될 수 있다. 이때는 한 액티비티가 다른 액티비티를 론칭하는 방법과 똑같이 인텐트 매커니즘을 사용하면 된다. 스타트 서비스는 startService()메소드를 호출하여 론칭하며, 시작되는 서비스를 식별하는 인텐트 객체를 인자로 전달한다. 스타트 서비스는 작업을 완료한 후 stopSelf()를 호출하여 자신을 중단시켜야 한다. 또한, stopService()메소드를 호출하면 실행 중인 서비스를 다른 컴포넌트에서 중단시킬 수 있다. 이때는 중단될 서비스아 일치하는 인텐트를 인자로 전달한다. <인텐트 서비스> IntentService클...

(안드로이드) Recycler뷰와 Toolbar 연동시키기

** CoordinatorLayout의 뷰 계층 구조에 속한 특정 뷰의 스크롤 액션을 기준으로 앱바의 요소들이 사라지거나 나타나게 하기 위해 CoorinatorLayout을 사용할 수 있다.  예를들어, RecyclerView의 리스트 항목을 스크롤할 때 그렇게 될 수 있다. 그리고 이렇게 하려면 스코롤이 생기는 요소와 그로 인해 연동되는 요소 모두의 속성을 설정해야 한다. 스크롤이 생기는 요소(여기서는 RecyclerView)의 경우에는 android:layout_behavior(또는 app:layout_bahavior)속성을 appbar_scrolling_view_behavior로 설정해야 한다. < android.support.v7.widget.RecyclerView android :id= "@+id/recycler_view" android :layout_width= "match_parent" android :layout_height= "match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> < android.support.design.widget.AppBarLayout android :layout_width= "match_parent" android :layout_height= "wrap_content" android :theme= "@style/AppTheme.AppBarOverlay" > < android.support.v7.widget.Toolbar android :id= "@+id/toolbar" android :layout_width= "...