모바일

08-2. SD 카드 폴더/파일 처리 연습

동로시 2021. 2. 22. 17:32

프로젝트1: SD 카드의 이미지 파일을 보여주는 이미지 뷰어

- 리니어 레이아웃 (버튼2: 이전, 이후)

- 커스텀 위젯(sd 카드에서 가져오기)

 

<AndroidMainfest.xml>

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.file">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
        android:requestLegacyExternalStorage="true"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.File">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

sd 카드 접근 권한을 설정해준다.

 

<myImageView.java>

package com.example.file;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

public class myImageView extends View {
    String imagePath = null;

    public myImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if(imagePath != null){
            try {
                Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
                canvas.drawBitmap(bitmap, 0, 0, null);
                bitmap.recycle();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

bitmap을 이용해 해당하는 이미지를 출력한다.

 

<activity_main.xml>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:padding="10dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:layout_margin="5dp"
            android:layout_weight="1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/btn1"
            android:text="이전 그림"/>

        <Button
            android:layout_margin="5dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:id="@+id/btn2"
            android:text="다음 그림"/>
    </LinearLayout>

    <com.example.file.myImageView
        android:id="@+id/myImageView1"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content" />

</LinearLayout>

커스텀 위젯을 넣을 때는 <패키지명.클래스명> 형식으로 사용하면 된다.

 

<MainActivity.java>

package com.example.file;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {
    Button btn1, btn2;
    myImageView imageView;
    File[] imageFiles;
    String imageFname;
    int curNum = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setTitle("간단 이미지 뷰어");

        ActivityCompat.requestPermissions(this, new String[]{
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        }, MODE_PRIVATE);

        btn1 = (Button)findViewById(R.id.btn1);
        btn2 = (Button)findViewById(R.id.btn2);
        imageView = (myImageView)findViewById(R.id.myImageView1);

        imageFiles = new File(
                 "sdcard/Pictures").listFiles();
        imageFname = imageFiles[0].toString();
        imageView.imagePath = imageFname;


        btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(curNum <= 0){
                    Toast.makeText(getApplicationContext(), "첫번째 그림입니다", Toast.LENGTH_SHORT).show();
                } else{
                    curNum--;
                    imageFname = imageFiles[curNum].toString();
                    imageView.imagePath=imageFname;
                    imageView.invalidate();
                }
            }
        });

        btn2.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                if(curNum >= imageFiles.length - 1){
                    Toast.makeText(getApplicationContext(), "마지막 그림입니다", Toast.LENGTH_SHORT).show();
                } else{
                    curNum++;
                    imageFname = imageFiles[curNum].toString();
                    imageView.imagePath=imageFname;
                    imageView.invalidate();
                }
            }
        });

    }
}

invalidate()를 호출하면 imageView 클래스의 onDraw()가 호출된다.

 

프로젝트1

프로젝트2: 프로젝트1 수정

- 버튼 사이에 텍스트뷰 1개 (현재 그림 번호/전체 그림 수)

- 그림 순환

package com.example.file;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {
    TextView cur, total;
    Integer num;
    Button btn1, btn2;
    myImageView imageView;
    File[] imageFiles;
    String imageFname;
    int curNum = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setTitle("간단 이미지 뷰어");

        ActivityCompat.requestPermissions(this, new String[]{
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        }, MODE_PRIVATE);

        btn1 = (Button)findViewById(R.id.btn1);
        btn2 = (Button)findViewById(R.id.btn2);
        imageView = (myImageView)findViewById(R.id.myImageView1);
        cur = (TextView)findViewById(R.id.cur);
        total = (TextView)findViewById(R.id.total);

        imageFiles = new File(
                 "sdcard/Pictures").listFiles();
        num = imageFiles.length;
        total.setText(num.toString());
        imageFname = imageFiles[0].toString();
        imageView.imagePath = imageFname;
        imageView.invalidate();

        btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(curNum <= 0){
                    curNum = num-1;
                } else{
                    curNum--;
                }
                cur.setText(Integer.toString(curNum+1));
                imageFname = imageFiles[curNum].toString();
                imageView.imagePath=imageFname;
                imageView.invalidate();
            }
        });

        btn2.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                if(curNum >= num-1){
                    curNum = 0;
                } else{
                    curNum++;
                }
                cur.setText(Integer.toString(curNum+1));
                imageFname = imageFiles[curNum].toString();
                imageView.imagePath=imageFname;
                imageView.invalidate();
            }
        });

    }
}

근데 처음에 그림 로드할 때 계속 파일을 못 연다고 에러가 뜬다. 1, 2 일 때는 다 되는데 0 번째 그림만 그런다. 왜 그러지..

 

프로젝트3: 프로젝트1 수정

비트맵 그림 가운데 정렬하기

        if(imagePath != null){
            try {
                Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
                int width = getWidth();
                int height = getHeight();
                canvas.drawBitmap(bitmap, (width - bitmap.getWidth())/2, (height - bitmap.getHeight())/2, null);
                bitmap.recycle();
            }catch (Exception e){
                e.printStackTrace();
            }
        }

 

프로젝트4: SD카드에 일기 자동 생성

package com.example.file;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Calendar;
import java.util.Date;

public class MainActivity extends AppCompatActivity {
    DatePicker datePicker;
    EditText editText;
    Button btn;
    String strDir, fileName;
    File myDir;

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

        ActivityCompat.requestPermissions(this, new String[]{
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        }, MODE_PRIVATE);

        datePicker = (DatePicker)findViewById(R.id.datePicker);
        editText =  (EditText)findViewById(R.id.getDiary);
        btn = (Button)findViewById(R.id.btn);

        strDir = Environment.getExternalStorageDirectory().getAbsolutePath();
        myDir = new File(strDir + "/mydir");
        if(!myDir.isDirectory()){
            myDir.mkdir();
        }

        Calendar cal = Calendar.getInstance();
        int cYear = cal.get(Calendar.YEAR);
        int cMonth = cal.get(Calendar.MONTH);
        int cDate = cal.get(Calendar.DATE);
        fileName = Integer.toString(cYear) + "_" + Integer.toString(cMonth+1) + "_" + Integer.toString(cDate)
                + ".txt";
        String initStr = readDiary(fileName);
        editText.setText(initStr);
        btn.setEnabled(true);

        datePicker.init(cYear, cMonth, cDate, new DatePicker.OnDateChangedListener() {
            @Override
            public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
                fileName = Integer.toString(year) + "_" + Integer.toString(monthOfYear+1) + "_" +
                        Integer.toString(dayOfMonth) + ".txt";
                String str = readDiary(fileName);
                editText.setText(str);
                btn.setEnabled(true);
            }
        });

        btn.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                try{
                    //File curDir = new File(myDir + "/fileName");
                    FileOutputStream outFs = new FileOutputStream(myDir + "/" + fileName);
                    String str = editText.getText().toString();
                    outFs.write(str.getBytes());
                    outFs.close();
                    Toast.makeText(getApplicationContext(), fileName + "이 저장됨", Toast.LENGTH_SHORT).show();
                    btn.setText("수정하기");
                }catch(IOException e){
                }
            }
        });
    }

    String readDiary(String fName){
        String diaryStr = null;
        //File curDir = new File(myDir + fileName);
        FileInputStream inFs;
        try{
            inFs = new FileInputStream(myDir + "/" + fileName);
            byte[] txt = new byte[500];
            inFs.read(txt);
            inFs.close();
            diaryStr = (new String(txt).trim());
            btn.setText("수정하기");
        } catch (IOException e){
            editText.setHint("일기 없음");
            btn.setText("새로 저장");
        }
        return diaryStr;
    }
}