Android 복수 선택이 가능한 갤러리를 만들자 1

안녕하세요 포스팅이 조금 늦었습니다.
이번시간부터는 멀티 셀렉트가 가능한 갤러리 앱 코딩을 시작해보도록 하겠습니다.

(이번에도 전체 소스는 마지막에 첨부하도록 하겠습니다.)
먼저 프로젝트를 만들겠습니다.
다음처럼 만들어 보지요

MyGallery라고 프로젝트를 만들었습니다.
이번시간을 마치고 나면 프로젝트는 이런 모양이 될 것입니다. (no_bg.png  파일은 문서 마지막에 첨부한 전체 소스 압축파일에서 가져다 쓰시면 되겠습니다.)


자 이제 코딩을 시작해보겠습니다.

먼저 모델 클래스인 ThumbImageInfo.java 클래스를 만듭니다.
전체 소스는 다음과 같습니다.
별루 설명할건 없죠? 여기서 data 라는 변수가 앞으로 미디어스토어 DB에서 읽어올 파일의 경로를 저장하는 넘이 될것입니다.
******************************* ThumbImageInfo.java ********************************
package com.jeehun.android.mygallery;

public class ThumbImageInfo
{
  private String id;
  private String data;
  private boolean checkedState;
 
  public String getId()
  {
    return id;
  }
  public void setId(String id)
  {
    this.id = id;
  }
  public String getData()
  {
    return data;
  }
  public void setData(String data)
  {
    this.data = data;
  }
  public boolean getCheckedState()
  {
    return checkedState;
  }
  public void setCheckedState(boolean checkedState)
  {
    this.checkedState = checkedState;
  }
}
*************************************************************************************

다음은 Main.java 파일입니다.
이 Main.java 클래스에 인너 클래스로 BaseAdapter를 상속받은 이미지 어댑터를 만들어 줄 것입니다.
findThumbList() 메서드에서 미디어 스토어에 등록된 이미지들의 경로와 아이디를 가져오고 있습니다.
그리고 이 findThumbList() 메서드를 호출하는 것은 어싱크 태스크 클래스입니다. 이것으로
메인 UI스레드가 먹통되는 일 없이 조회중에 진행 상태 다이얼로그를 띄워 줄 수 있습니다.
이미지 어댑터는 그닥 특이한점은 없습니다. 베이스 어댑터를 상속받았고
속도를 높이고자 getView에서 홀더 패턴을 사용하고 있습니다. 그러나 이미지가 많을 경우
홀더패턴을 사용하는 정도로는 속도의 개선은 거의 이뤄지지 않습니다.
일단 이번시간에는 속도문제는 나중으로 미루고 미디어 스토어에서 이미지 데이터를 조회하여
그것들을 그리드 뷰를 이용해서 화면에 뿌리는 것까지만 구현하겠습니다.
************************************** Main.java *************************************
package com.jeehun.android.mygallery;

import java.io.File;
import java.util.ArrayList;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.ImageView;

public class Main extends Activity
{
  ProgressDialog mLoagindDialog;
  GridView mGvImageList;
  ImageAdapter mListAdapter;
  ArrayList<ThumbImageInfo> mThumbImageInfoList;
 
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.image_list_view);
   
    mThumbImageInfoList = new ArrayList<ThumbImageInfo>();
    mGvImageList = (GridView) findViewById(R.id.gvImageList);
   
    new DoFindImageList().execute();
  }
 
  private long findThumbList()
  {
    long returnValue = 0;
   
    // Select 하고자 하는 컬럼
    String[] projection = { MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA };
   
    // 쿼리 수행
    Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, MediaStore.Images.Media.DATE_ADDED + " desc ");

    if (imageCursor != null && imageCursor.getCount() > 0)
    {
      // 컬럼 인덱스
      int imageIDCol = imageCursor.getColumnIndex(MediaStore.Images.Media._ID);
      int imageDataCol = imageCursor.getColumnIndex(MediaStore.Images.Media.DATA);

      // 커서에서 이미지의 ID와 경로명을 가져와서 ThumbImageInfo 모델 클래스를 생성해서
      // 리스트에 더해준다.
      while (imageCursor.moveToNext())
      {
        ThumbImageInfo thumbInfo = new ThumbImageInfo();

        thumbInfo.setId(imageCursor.getString(imageIDCol));
        thumbInfo.setData(imageCursor.getString(imageDataCol));
        thumbInfo.setCheckedState(false);
       
        mThumbImageInfoList.add(thumbInfo);
        returnValue++;
      }
    }
    imageCursor.close();
    return returnValue;
  }
 
  // 화면에 이미지들을 뿌려준다.
  private void updateUI()
  {
    mListAdapter = new ImageAdapter (this, R.layout.image_cell, mThumbImageInfoList);
    mGvImageList.setAdapter(mListAdapter);
  }
 
  // ***************************************************************************************** //
  // Image Adapter Class
  // ***************************************************************************************** //
  static class ImageViewHolder
  {
    ImageView ivImage;
    CheckBox chkImage;
  }
 
  private class ImageAdapter extends BaseAdapter
  {
    private Context mContext;
    private int mCellLayout;
    private LayoutInflater mLiInflater;
    private ArrayList<ThumbImageInfo> mThumbImageInfoList;
   
    public ImageAdapter(Context c, int cellLayout, ArrayList<ThumbImageInfo> thumbImageInfoList)
    {
      mContext = c;
      mCellLayout = cellLayout;
      mThumbImageInfoList = thumbImageInfoList;
     
      mLiInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }
   
    public int getCount()
    {
      return mThumbImageInfoList.size();
    }

    public Object getItem(int position)
    {
      return mThumbImageInfoList.get(position);
    }

    public long getItemId(int position)
    {
      return position;
    }
   
    public View getView(int position, View convertView, ViewGroup parent)
    {
      if (convertView == null)
      {
        convertView = mLiInflater.inflate(mCellLayout, parent, false);
        ImageViewHolder holder = new ImageViewHolder();
       
        holder.ivImage = (ImageView) convertView.findViewById(R.id.ivImage);
        holder.chkImage = (CheckBox) convertView.findViewById(R.id.chkImage);
       
        convertView.setTag(holder);
      }

      final ImageViewHolder holder = (ImageViewHolder) convertView.getTag();
     
      if (((ThumbImageInfo) mThumbImageInfoList.get(position)).getCheckedState())
        holder.chkImage.setChecked(true);
      else
        holder.chkImage.setChecked(false);

      try
      {
        String path = ((ThumbImageInfo) mThumbImageInfoList.get(position)).getData();
       
        BitmapFactory.Options option = new BitmapFactory.Options();
       
        if (new File(path).length() > 100000)
          option.inSampleSize = 10;
        else
          option.inSampleSize = 2;
       
        Bitmap bmp = BitmapFactory.decodeFile(path, option);
        holder.ivImage.setImageBitmap(bmp); 
       
        setProgressBarIndeterminateVisibility(false);
      }
      catch (Exception e)
      {
        e.printStackTrace();
        setProgressBarIndeterminateVisibility(false);
      }
       
      return convertView;
    }
  }
  // ***************************************************************************************** //
  // Image Adapter Class End
  // ***************************************************************************************** //
 
  // ***************************************************************************************** //
  // AsyncTask Class
  // ***************************************************************************************** //
  private class DoFindImageList extends AsyncTask<String, Integer, Long>
  {
    @Override
    protected void onPreExecute()
    {
      mLoagindDialog = ProgressDialog.show(Main.this, null, "로딩중...", true, true);
      super.onPreExecute();
    }
   
    @Override
    protected Long doInBackground(String... arg0)
    {
      long returnValue = 0;
      returnValue = findThumbList();
      return returnValue;
    }

    @Override
    protected void onPostExecute(Long result)
    {
      updateUI();
      mLoagindDialog.dismiss();
    }

    @Override
    protected void onCancelled()
    {
      super.onCancelled();
    }
  }
  // ***************************************************************************************** //
  // AsyncTask Class End
  // ***************************************************************************************** //
}
**************************************************************************************

Main.java에서 사용하는 레이아웃 파일은 따로 설명하지는 않겠습니다.
문서 마지막에 덧붙일 이번시간 전체 소스코드를 다운로드 받으셔서 참고해주시기 바랍니다.
아무튼 코딩을 마치고 실행시켜 보면 다음과 같은 화면이 뜨게 됩니다.


이미지는 제대로 나옵니다만 속도가 매우 느리고 체크박스는 아직 체크되지도 않습니다.
다음 시간에는 이 갤러리 앱의 속도를 개선해보도록 하겠습니다.
전체소스 : MyGallery_01.zip

도움이 되셨다면 리플 하나 남겨주시는 센스!! ^^

by 선지헌 | 2011/06/28 23:58 | Android | 트랙백 | 덧글(15)

트랙백 주소 : http://jeehun.egloos.com/tb/4077813
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Commented by 칼빈 at 2011/07/25 23:15
감사합니다^^
Commented by 늑대군 at 2012/02/17 13:48
정말 감사합니다. 도움이 많이 되었어요.
Commented at 2012/07/02 18:50
비공개 덧글입니다.
Commented by 준휘 at 2012/07/21 11:12
감사합니다. 미디어 서버에 접근하여 content 가져오는 것을 고민하고 있었는데 유용하게 쓸께요.
Commented by 조남두 at 2012/10/10 09:43
정말 많은 도움됐네요 자료 감사히 쓸께용
Commented at 2013/03/14 21:28
비공개 덧글입니다.
Commented at 2013/09/26 17:55
비공개 덧글입니다.
Commented by 감사합니다 at 2014/03/20 16:40
잘쓸게요~~
Commented by 벤지 at 2014/07/27 16:59
감사합니다...공부중인데, 큰도움이 되었어요...
Commented by AsycTask at 2014/11/16 03:18
죄송한데... 어싱크 태스크를 사용하는 이유가 프로그래스바를 띄우기 위해서 인가요???
갤러리 호출시 프로그래스바를 막대형으로 다이얼로그 안쓰고 띄우려고 하는데...
단지 어싱크 태스크의 개념이 아무리 봐도 이해가 잘되지 않아서 질문드립니다...
가능하다면 답변부탁드립니다.^^

좋은 자료 감사합니다(__)
Commented by hyoek at 2015/03/25 11:22
좋은자료 감사합니다.
Commented by 초짜공부중 at 2015/06/22 10:59
감사합니다. 많이 알아갑니다.
Commented at 2015/08/05 02:00
비공개 덧글입니다.
Commented by 엠와플 at 2015/08/31 13:19
대단하십니다. 엄청난 도움이 됐습니다.
고맙습니다.
Commented by 왕초보 at 2015/10/10 16:44
안녕하세요 글 잘보고있습니다.
제가 진짜 시작한지 얼마안되서요..
올려져있는 소스파일을 다운로드 받아서 압축파일까진 풀었는데
그다음에 어떻게 열어야할지 모르겠네요..기초적인건데 알려주실 수 있나요??

:         :

:

비공개 덧글

◀ 이전 페이지다음 페이지 ▶