모바일
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()가 호출된다.
프로젝트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;
}
}