요즘에 만들고 있는 Custom Camera & Gallery App에서 Gallery의 갱신(update)가 잘 되지 않는 문제를 해결하기 위해서 이전까지는 Activity의 생애주기(Life-cycle)를 살펴봤다. 이를 통해서 Camera Intent 실행 후 넘어왔을 때 Gallery의 배열이 update 되도록 하는 문제는 해결되었으나, 파일 삭제를 위해 따로 Intent 만들어 불러오기는 작동은 되나 쓸데없이 군더더기가 많은 듯 하였다. 그래서 gallery update 에 대하여 자료를 찾아봤더니 애초에 adapter class에 있는 notifyDataSetChanged() method를 활용하면 되는 것이었다(이걸 모르고 괜히 헛짓거리를 했네 쿨럭;;). 그런데 이전에 ListView도 그렇고 Adapter를 여기저기 활용하는데, 대체 Adapter란게 무엇인가에 대하여 제대로 살펴봐야 겠다.

1. 목적 : Adapter에 대하여 알아보자.

2. 개발 환경
 - PC : Windows 7, Android Studio 1.4.1(64-bit)
 - Phone : LG G pro Lollipop(API 21)

3. 참고자료
 1) Android Developers - Adapter Reference (http://developer.android.com/reference/android/widget/Adapter.html)

4. Adapter에 대한 이해
 1) Adapter란 무엇인가?
   Android APIs' Reference에 따르면 'Adapter' 자체는 하나의 Object(객체)로서, 보여지는 View와 그 View에 올릴 Data를 연결하는 일종의 Bridge라고 한다. 그래서 그런지 ListView Adapter에 대한 예시에서도, GalleryAdapter에 대한 예시에서도 해당 Adapter의 생성자에서 Data를 연결하고 나서 getView() method에서 해당 position에 올라갈 TextView나 ImageView를 setting 해 View로서 뿌려주는 모양이다.

[사진 1] 기본 Adapter를 상속받는 subclass들 목록이다.

 2) Adapter 에 속해 있는 method들

 
[사진 2] Adapter의 기본 public method list

  Adapter class에 속해 있는 기본 method 의 목록은 위 [사진 2]와 같다. getCount()를 통해서 Adapter가 보여주는 item의 갯수값을 int로 받을 수 있고, getItem(int position)을 통해서 position에 위치해 있는 item의 data를 받을 수도 있다. getItemId(int postion)의 경우에는 getItem(int position)과 비슷하게 position에 위치한 값을 반환하기는 하나 그 값이 Item마다 부여된 일종의 ID라고 한다. 그리고 화면에 뿌려주기 위해서 getView(int position, View convertView, ViewGroup parent)를 활용하고, 이 getView()를 통해 생성된 View의 갯수를 getViewTypeCount()로 받을 수 있다고 한다. 이 외에도 hasStableIds()를 통해서 각 Row마다 부여된 ID를 변화에 상관없이 고정할지(stable) 여부를 결정할 수 있으며, 해당 Adapter가 비었는지를 isEmpty()로 판단할 수 있다.

  한편, notifyDataSetChanged()와 같은 기능을 활용하기 위해서는 Adapter에 묶여있는 Item의 변경 여부를 감지해야 하는데 이를 감지하는 것이 말그대로 'DataSetObserver'이다. 따라서, item의 변경이 감지(notify)되도록 하기 위해서는 registerDataSetObserver(DataSetObserver observer)를 통해서 observer를 Adapter에 연결해야 한다.

5. 적용 예시

 1) CustomGalleryAdapter.java 내 registerDataSetObserver() 등의 추가


public class
CustomGalleryAdapter extends BaseAdapter {
    int CustomGalleryItemBg;
    String mBasePath;
    Context mContext;
    String[] mImgs;
    Bitmap bm;
    DataSetObservable mDataSetObservable = new DataSetObservable(); // DataSetObservable(DataSetObserver)의 생성

    public String TAG = "Gallery Adapter Example :: ";

    public CustomGalleryAdapter(Context context, String basepath){
        this.mContext = context;
        this.mBasePath = basepath;

        File file = new File(mBasePath);
        if(!file.exists()){
            if(!file.mkdirs()){
                Log.d(TAG, "failed to create directory");
            }
        }
        mImgs = file.list(); 

        TypedArray array = mContext.obtainStyledAttributes(R.styleable.GalleryTheme);
        CustomGalleryItemBg = array.getResourceId(R.styleable.GalleryTheme_android_galleryItemBackground, 0);
        array.recycle();
    }

    @Override
    public int getCount() {
        File dir = new File(mBasePath);
        mImgs = dir.list();
        return mImgs.length;
    }

    @Override
    public Object getItem(int position) {
        return position;
    }

    // Adapter 내 Item에서 직접 주소를 받아오도록 method 추가.
    // 이전에는 MainActivity와 주소 및 position이 달라 비정상적인 앱의 종료가 발생한 것으로 보인다

    public String getItemPath(int position){ 
        String path = mBasePath + File.separator + mImgs[position];
        return path;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    // Override this method according to your need
    @Override
    public View getView(int index, View view, ViewGroup viewGroup)

    {
        // TODO Auto-generated method stub
        ImageView i = new ImageView(mContext);

        File dir = new File(mBasePath);
        mImgs = dir.list();
        bm = BitmapFactory.decodeFile(mBasePath+ File.separator +mImgs[index]);

        Bitmap bm2 = ThumbnailUtils.extractThumbnail(bm, 300, 300);
        i.setLayoutParams(new Gallery.LayoutParams(300, 300));
        i.setImageBitmap(bm2);
        i.setVisibility(ImageView.VISIBLE);

        i.setBackgroundResource(CustomGalleryItemBg);
        i.setScaleType(ImageView.ScaleType.FIT_CENTER);

        if (bm != null && !bm.isRecycled()) {
            bm.recycle();
        }
        return i;
    }

    @Override
    public void registerDataSetObserver(DataSetObserver observer){ // DataSetObserver의 등록(연결)
        mDataSetObservable.registerObserver(observer);
    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer){ // DataSetObserver의 해제
        mDataSetObservable.unregisterObserver(observer);
    }

    @Override
    public void notifyDataSetChanged(){ // 위에서 연결된 DataSetObserver를 통한 변경 확인
        mDataSetObservable.notifyChanged();
    }
}

 

 2) MainActivity.java에 적용

// 파일 삭제 후 notifyDataSetChanged() 적용
        builder.setPositiveButton("예", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                        File file = new File(delFilePath);
                        file.delete();
                        File temp = new File(basePath);
                        imgs = temp.list();
                        customGalAdapter.notifyDataSetChanged();
                    }
            });

 

(위 Code의 실행 결과)

     

      

 

  사실 일전의 Custom Gallery Example에서 Gallery Item Long Click시 해당 사진 파일을 삭제하는 코드를 입력했었다. 실행 결과, 파일은 삭제되기는 했지만 파일 삭제 후의 Gallery Item들의 배열이 정리되지 않았고, 원래 해당 파일이 있던 frame 내부가 null 값으로 까맣게 보이며 click 시 App.이 비정상적으로 종료되었다. 그리고 Camera Intent로 촬영 후 새로 찍은 사진이 Gallery에 넘어오지 않았다. 아무래도 file 배열이 변경된 후 Gallery Adapter를 다시 불러와야 될 것 같은데, 원래 adapter가 생성되어 있던 onCreate()를 통째로 다시 불러들여도 괜찮을지 Activity 생애주기(Life Cycle)에 대해 알아봐야 겠다.

1. 목적 : Android Activity LifeCycle(Activity 생애주기)를 이해하고 기본 구조를 알아보자.

2. 개발 환경
 - PC : Windows 7, Android Studio 1.4.1(64-bit)
 - Phone : LG G pro Lollipop(API 21)

3. 참고자료
 1) Android Developers - Activity Reference (http://developer.android.com/reference/android/app/Activity.html)

4. Activity Life Cycle(Acitivity 생애 주기)의 이론

  Android Studio로 App. project를 생성해 보면 /java/'해당 packaging 명'/MainActivity.java 이 기본으로 만들어져 있고 그 안에 파일명과 같은 class가 'extends Activity' 혹은 'extends AppCompatAcitivity'을 끌고 기본 method인 onCreate(Bundle savedInstanceState)를 @Override한 채로 만들어져 있는 광경을 볼 수 있다. 이 모습을 보다보면 아무래도 C 언어에서 void main(void) 가 생성되며 시작 지점이 자동으로 지정되듯이 onCreate()가 필수적 임을 눈치로 대강 알 수 있을텐데, 실제로 'Android Developers reference'를 찾아보면 다음과 같은 순서도를 통해서 App.의 Activity에 대한 동작 구조를 파악할 수 있다.

  보시다시피 App.이 실행되면서 Activity가 시작되면 처음에 onCreate()를 통해서 Activity가 생성되고 onStart()와 onResume()을 거처 해당 Activity가 실행된다. 그러다가 해당 Activity를 sleep 시킬 때 onPause()와 onStop()을 거치게 되고, onStop() method 시점에서 사용자가 해당 Activity를 다시 실행시키고자 하면 onRestart()를, App.이 memory를 많이 잡아먹어 시스템에 의해 process kill이 됐을 때 사용자가 원할 경우 onCreate()로 넘어간다. 이런 method들을 돌고 돌던 Activity는 끝날 때가 되면 onDestory()를 통해 system에서 사라진다.

  그래서 App.의 activity의 생애주기에 따라 작동해야 할 특정한 기능이 있다면 아래와 같이 Activity class 내에 위 method()를 따로 정의해서 사용한다. 하나의 예로서, 이전에 항상 꺼지지 않는 App.을 만들기 위해서 onStop() 을 @Override하여 onStop() 내에서 onRestart()를 무조건 실행시키게 만들었었다.

public class Activity extends ApplicationContext {
    protected void onCreate(Bundle savedInstanceState);

    protected void onStart();

    protected void onRestart();

    protected void onResume();

    protected void onPause();

    protected void onStop();

    protected void onDestroy();
}

  그럼 이번 Gallery가 새로 찍은 사진이 update되지 않는 문제는 Gallery Adapter의 생성 및 연결을 onStart() method에 선언하여 @Override 해보면 되지 않을까? 아무래도 Camera Intent를 불러오면서 기존 MainActivity는 onStop()에 있어 intent가 종료되고 나면 onStart() 부터 다시 시작할 것 같았기 때문이다.

5. 실험

  이전의 Custom Gallery Example의 Gallery Adapter 선언 부분을 단순히 onStart()로 아래와 같이 옮겨봤다.

public class MainActivity extends AppCompatActivity {

    public static final int MEDIA_TYPE_IMAGE = 1;
    public static final int MEDIA_TYPE_VIDEO = 2;
    public int inSampleSize = 1;

    private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
    private Uri fileUri;
    private static String basePath;

    public float imageViewRotation = 90;
    public String TAG = "Camera Example :: ";

    private Button takePicBtn;
    private ImageView resultView;
    private TextView imgPath;
    private Gallery customGallery;
    private CustomGalleryAdapter customGalAdapter;

    private String[] imgs;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES), "MyCameraApp");
        // This location works best if you want the created images to be shared
        // between applications and persist after your app has been uninstalled.

        // Create the storage directory if it does not exist
        if (! mediaStorageDir.exists()){
            if (! mediaStorageDir.mkdirs()){
                Log.d("MyCameraApp", "failed to create directory");

            }
        }

        basePath = mediaStorageDir.getPath();

        imgPath = (TextView)findViewById(R.id.imgpath);
        resultView = (ImageView)findViewById(R.id.resultview);
        takePicBtn = (Button)findViewById(R.id.takepicbtn);
        takePicBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // create Intent to take a picture and return control to the calling application
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

                fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
                intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name

                // start the image capture Intent
                startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
            }
        });

       
        customGallery = (Gallery)findViewById(R.id.customgallery);


    }

    /* 아래와 같이 onStart()를 Override하여 Gallery Adapter 와 연관된 부분을 그대로 복사해 옮겨놓았다. */
    @Override
    protected void onStart(){
        super.onStart();

        File file = new File(basePath);
        imgs = file.list();
        for(int i=0; i<imgs.length; i++){
            imgPath.setText(imgs[i]);
        }

        customGalAdapter = new CustomGalleryAdapter(getApplicationContext(), basePath);
        customGallery.setAdapter(customGalAdapter);
        customGallery.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Bitmap bm = BitmapFactory.decodeFile(basePath+ File.separator +imgs[position]);
                Bitmap bm2 = ThumbnailUtils.extractThumbnail(bm, bm.getWidth() / inSampleSize, bm.getHeight() / inSampleSize);
                resultView.setImageBitmap(bm2);
                imgPath.setText(basePath+File.separator+imgs[position]);
            }
        });
        customGallery.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                File temp = new File(basePath+File.separator+imgs[position]);
                temp.delete();
                return false;
            }
        });
    }

  위 변경사항을 반영하여 compile/Run을 시켜봤더니 다행히 camera intent 실행 후 새로 찍은 사진이 gallery 에 반영되었다. 이제는 파일 삭제 후 Gallery update가 되도록 다른 method를 살펴봐야겠다.

(위 code의 실행결과)

     

 

  이전에 Camera Intent 예제를 통해서 찍은 사진을 onActivityResult()를 이용하여 바로 확인하는 code의 기본 구조를 살펴 보았다. 이번에는 앞에서 구현한 기본 기능에다가 file.lists()를 더하여 특정 Directory 내 사진을 확인할 수 있는 Custom gallery 기능을 구현해보려 한다. 자료를 찾아보니 사진의 경로를 받아 Gallery 에 연결하는 방법이 있고 GridView에 연결하는 방법 등 여러가지가 있었는데, 오늘은 Gallery 기능을 활용해 보고자 한다.

1. 목적 : Gallery의 기본 구조를 살펴보고 Custom Gallery View를 구현해 보자.

2. 개발 환경
 - PC : Windows 7, Android Studio 1.4.1(64-bit)
 - Phone : LG G pro Lollipop(API 21)

3. 참고자료
 1) Envato tuts+ - Android Gallery View Tutorial (http://code.tutsplus.com/tutorials/android-sdk-displaying-images-with-an-enhanced-gallery--mobile-11130)
 2) Android People - Android Gallery, ImageView Example (http://www.androidpeople.com/android-gallery-imageview-example)

4. 과정
  이번 예시는 일전의 Camera Intent Example에 살을 붙여 사용했다.


 1) AndroidManifest.xml에 사진을 읽고 쓸 수 있도록 permission을 다음과 같이 추가한다.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <!-- 외부 저장소 read permission -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 외부 저장소 write permission -->

 

 2) activity_main.xml과 같이 App.에서 Gallery를 보여줄 곳에 다음과 같이 Gallery 변수를 추가한다.

 


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:orientation="vertical" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <!-- Camera Intent를 실행할 Button 선언 -->
    <Button
        android:id="@+id/takepicbtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:padding="5dp"
        android:text="Take Picture" />

    <!-- 사진의 경로를 받아다 String으로 보여줄 TextView 선언 -->
    <TextView
        android:id="@+id/imgpath"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/takepicbtn"
        android:padding="10dp"
        android:text="Hello World!"/>

    <!-- 지정한 경로 내의 사진들을 보여줄 Gallery 선언 -->
    <Gallery
        android:id="@+id/customgallery"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/imgpath"></Gallery>

    <!-- Gallery 내 선택한 사진을 크게 보여줄 ImageView 선언 -->
    <ImageView
        android:id="@+id/resultview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_below="@id/customgallery" />
</LinearLayout>

 

 3) Gallery의 Frame이 될 values/attrs.xml을 생성하여 다음과 같이 정의한다. 이 부분은 추후에 GalleryAdapter에서 적용된다.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="GalleryTheme">
        <attr name="android:galleryItemBackground"/>
    </declare-styleable>
</resources>

 

 4) main이 되는 activity에서 gallery를 연결할 Adapter를 다음과 같이 customizing하여 CustomGalleryAdapter.java와 같은 파일로 정의한다. CustomGalleryHolder를 통해 ImageView를 연결할 수도 있지만 기본 example처럼 context를 받아와 ImageView를 연결하여 사용할 예정이다.

public class CustomGalleryAdapter extends BaseAdapter {
    int CustomGalleryItemBg; // 앞서 정의해 둔 attrs.xml의 resource를 background로 받아올 변수 선언
    String mBasePath; // CustomGalleryAdapter를 선언할 때 지정 경로를 받아오기 위한 변수
    Context mContext; // CustomGalleryAdapter를 선언할 때 해당 activity의 context를 받아오기 위한 context 변수
    String[] mImgs; // 위 mBasePath내의 file list를 String 배열로 저장받을 변수
    Bitmap bm; // 지정 경로의 사진을 Bitmap으로 받아오기 위한 변수

    public String TAG = "Gallery Adapter Example :: ";

    public CustomGalleryAdapter(Context context, String basepath){ // CustomGalleryAdapter의 생성자
        this.mContext = context;
        this.mBasePath = basepath;

        File file = new File(mBasePath); // 지정 경로의 directory를 File 변수로 받아
        if(!file.exists()){
            if(!file.mkdirs()){
                Log.d(TAG, "failed to create directory");
            }
        }
        mImgs = file.list(); // file.list() method를 통해 directory 내 file 명들을 String[] 에 저장

        /* 앞서 정의한 attrs.xml에서 gallery array의 배경 style attribute를 받아옴 */
        TypedArray array = mContext.obtainStyledAttributes(R.styleable.GalleryTheme);
        CustomGalleryItemBg = array.getResourceId(R.styleable.GalleryTheme_android_galleryItemBackground, 0);
        array.recycle();
    }

    @Override
    public int getCount() { // Gallery array의 객체 갯수를 앞서 세어 둔 file.list()를 받은 String[]의 원소 갯수와 동일하다는 가정 하에 반환
        return mImgs.length;
    }

    @Override
    public Object getItem(int position) { // Gallery array의 해당 position을 반환
        return position;
    }

    @Override
    public long getItemId(int position) { // Gallery array의 해당 position을 long 값으로 반환
        return position;
    }


    // Override this method according to your need
    // 지정 경로 내 사진들을 보여주는 method.
   // Bitmap을 사용할 경우, memory 사용량이 커서 Thumbnail을 사용하거나 크기를 줄일 필요가 있음

   // setImageDrawable()이나 setImageURI() 등의 method로 대체 가능
    @Override
    public View getView(int index, View view, ViewGroup viewGroup)
    {
        // TODO Auto-generated method stub
      ImageView i = new ImageView(mContext); // Gallery array에 들어갈 ImageView 생성

        // 이 부분에서부터 'options.inJustDecodeBounds=false'까지는
        // Bitmap 사용시 나타나는 memory 부족 현상을 예방하기 위한 code. 경우에 따라서는 생략해도 가능하다.
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;

        int width = options.outWidth;
        int height = options.outHeight;
        int inSampleSize = 1;
        int reqWidth = 256;
        int reqHeight = 192;
        if((width > reqWidth) || (height > reqHeight)){
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
        options.inSampleSize = inSampleSize;
        options.inJustDecodeBounds = false;


        bm = BitmapFactory.decodeFile(mBasePath+ File.separator +mImgs[index], options);
        Bitmap bm2 = ThumbnailUtils.extractThumbnail(bm, 300, 300); // 크기가 큰 원본에서 image를 300*300 thumnail을 추출.
                                                                                               // 이를 통해 view 가 까맣게 보이는 null 값을 피할 수 있었다.
        i.setLayoutParams(new Gallery.LayoutParams(300, 300));
        i.setImageBitmap(bm2);
        i.setVisibility(ImageView.VISIBLE);

        i.setBackgroundResource(CustomGalleryItemBg); // Gallery 원소의 BackGround를 생성자에서 지정한 값으로 지정
        i.setScaleType(ImageView.ScaleType.FIT_CENTER);

        if (bm != null && !bm.isRecycled()) {
            bm.recycle();
        }
        return i;
    }
}

 

 5) MainActivity.java와 같이 App. 에서 Gallery를 보일 부분에 다음과 같이 앞서 정의해 둔 Gallery와 Adapter를 선언하고 연결한다.


public class MainActivity extends AppCompatActivity {

    public static final int MEDIA_TYPE_IMAGE = 1;
    public static final int MEDIA_TYPE_VIDEO = 2;
    public int inSampleSize = 1;

    private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
    private Uri fileUri;
    private static String basePath;

    public float imageViewRotation = 90;
    public String TAG = "Camera Example :: ";

    private Button takePicBtn;
    private ImageView resultView;
    private TextView imgPath;
    private Gallery customGallery;
    private CustomGalleryAdapter customGalAdapter;

    private String[] imgs;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       // App.을 실행하자 마자 지정한 경로의 생성 및 접근에 용이하도록 아래와 같이 생성
        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES), "MyCameraApp");
        // This location works best if you want the created images to be shared
        // between applications and persist after your app has been uninstalled.

        // Create the storage directory if it does not exist
        if (! mediaStorageDir.exists()){
            if (! mediaStorageDir.mkdirs()){
                Log.d("MyCameraApp", "failed to create directory");
//                return null;
            }
        }

        basePath = mediaStorageDir.getPath();

        imgPath = (TextView)findViewById(R.id.imgpath);
        resultView = (ImageView)findViewById(R.id.resultview);
        takePicBtn = (Button)findViewById(R.id.takepicbtn);
        // Button click시, Camera Intent를 불러 옴 
        takePicBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // create Intent to take a picture and return control to the calling application
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

                fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
                intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name

                // start the image capture Intent
                startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
            }
        });

        File file = new File(basePath);
        imgs = file.list();
        for(int i=0; i<imgs.length; i++){
            imgPath.setText(imgs[i]);
        }

        customGallery = (Gallery)findViewById(R.id.customgallery); // activity_main.xml에서 선언한 Gallery를 연결
        customGalAdapter = new CustomGalleryAdapter(getApplicationContext(), basePath); // 위 Gallery에 대한 Adapter를 선언
        customGallery.setAdapter(customGalAdapter); // Gallery에 위 Adapter를 연결
        // Gallery의 Item을 Click할 경우 ImageView에 보여주도록 함
        customGallery.setOnItemClickListener(new AdapterView.OnItemClickListener() { 
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Bitmap bm = BitmapFactory.decodeFile(basePath+ File.separator +imgs[position]);
                Bitmap bm2 = ThumbnailUtils.extractThumbnail(bm, bm.getWidth() / inSampleSize, bm.getHeight() / inSampleSize);
                resultView.setImageBitmap(bm2);
                imgPath.setText(basePath+File.separator+imgs[position]);
            }
        });
        // Gallery의 Item을 LongClick할 경우 해당 File을 삭제하도록 함.
      // 이 부분에서 동작은 하나, 삭제 후 결과가 View에 반영이 안되어 추가 보완 필요

        customGallery.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                File temp = new File(basePath+File.separator+imgs[position]);
                temp.delete();
                return false;
            }
        });
    }

 

(위 Code의 실행 결과)

  

  

 

 

 

+ Recent posts