사실 일전의 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의 실행결과)

     

 

+ Recent posts