안드로이드 내부 메모리 파일 처리
사용한 툴 : 이클립스
사용한 버전 : API 16
첨부 파일 : AndFileTest.zip

 


내장 메모리의 저장 위치는 /data/data/패키지명/files 폴더에 저장된다.

저번 포스팅에서 자바는 스트림 형태(바이트형태)로 파일을 읽고 쓰기 때문에 FIleInputStream, FileOutputStream 클래스가 사용한다.

내장 메모리의 파일을 읽을 때 openFileInput(파일명); 메소드를 사용하고 Read메소드로 값을 읽는다.

파일을 쓸 때는 openFileOutput(파일명, 모드명); 메소드로 파일을 지정하고 Write메소드로 값을 출력한다.

openFileOutput은 추가적으로 모드를 설정해야하는데, 모드들은 다음과 같다.

Context.MODE_WORLD_WRITEABLE : 쓰기

Context.MODE_WORLD_READABLE : 읽기

Context.MODE_APPEND : 기존 파일에 추가

Context.MODE_PRIVATE : 개인

사용한 스트림 파일은 close로 닫아줘야 한다.



activity_main.xml

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.filetest.MainActivity" 
    android:orientation="vertical">
    <Button
        android:id="@+id/btnRead"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="읽기"
        />
    <Button
        android:id="@+id/btnWrite"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="쓰기"/>
</LinearLayout>
cs



MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.example.filetest;
 
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
 
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
 
public class MainActivity extends Activity {
    Button btnRead,btnWrite;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnRead = (Button) findViewById(R.id.btnRead);
        btnWrite = (Button) findViewById(R.id.btnWrite);
        btnRead.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v){
                try {
                    FileInputStream infs = openFileInput("File.txt"); //파일이 없으면 FileNotFoundException예외
                    byte[] temp = new byte[infs.available()]; //파일길이 측정하다가 예외가 발생하면 IOException예외발새
                    infs.read(temp);
                    String strData = new String(temp);
                    Toast.makeText(getApplicationContext(),strData,Toast.LENGTH_SHORT).show();
                    infs.close();
                } catch (FileNotFoundException e) {
                    Toast.makeText(getApplicationContext(),"not file exist." , Toast.LENGTH_SHORT).show();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        btnWrite.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    FileOutputStream outfs = openFileOutput("File.txt", Context.MODE_WORLD_WRITEABLE);
                    String strTemp = "Java and Andriod!";
                    outfs.write(strTemp.getBytes());
                    outfs.close();
                    Toast.makeText(getApplicationContext(),"make File!",Toast.LENGTH_SHORT).show();
                }catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}
 
cs

 


23 ~ 29 '읽기' 버튼을 눌렀을 때 파일을 읽어들여 토스트에 띄우는 온클릭리스너 등록

28 파일의 사이즈를 측정하여 그 사이즈만큼 바이트 배열을 지정한다.

30 읽은 값이 byte형태이기 때문에 String형태로 변환한다.

40 ~ 53 '쓰기' 버튼을 눌렀을 때 파일을 만드는 온클릭리스너 등록. 만들때 같은 이름이 있어도 덮어씌운다.


AndFileTest.zip



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
 
public class ByteStreamSample {
 
    public static void main(String[] args) throws IOException {
        FileInputStream in = null;
        FileOutputStream out = null;
        File inFileName = new File("dog.jpg");
        String fileName = "dog";
        String newName;
 
        for (int i=1;;i++) {
            int data = 0;
            try {
                newName = fileName+String.valueOf(i)+".jpg";
                File inFile=new File(newName);
                if(inFile.exists())
                {
                    System.out.println("FileName is exist.");
                    continue;
                }
                in = new FileInputStream(inFileName);
                out = new FileOutputStream(inFile);
 
                while (data != -1) {
                    data = in.read();
                    out.write(data);
                }
 
                System.out.println(newName + "File Copy");
 
            } catch (FileNotFoundException e) {
                System.out.println(fileName + "File not exist. Program quit");
                break;
            }
 
            in.close();
            out.close();
        }
    }
 
}
 
 
cs

 

프로젝트 내에 dog.jpg 파일을 dog1, dog2, ... 뒤에 넘버를 붙이면서 복제하는 프로그램.

같은 파일 이름이 존재하는지 검사 한뒤 이미 파일이 있다면 다음 숫자로 넘긴다.

파일이름이 없다면 그 파일이름으로 dog.jpg파일을 복사한뒤 다음 숫자로 넘어간다.


중간에 나가는 설정이 없으므로 이 프로젝트를 실행한 뒤에 어느정도 시간이 지나면 강제로 중단하길 바란다.

제네릭 타입 : 타입을 파라미터로 가지는 클래스와 인터페이스. 선언시 클래스 또는 인터페이스 이름 뒤에 '< >' 부호 붙임. 일반적으로 대문자 한글자만 적는다.


장점

실행시 타입에러가 나는 것을 방지한다.

컴파일 시에 미리 타입을 강하게 체크해서 에러를 방지한다.

타입캐스트시 생기는 속도저하를 없앤다.

 

ArrayList에 저장되는 형태는 Object형태로 들어간다.
1
2
3
4
5
6
7
        List list = new ArrayList();
        list.add("hello");
        list.add("hi");
        strTemp = (String)list.get(0);
        System.out.println(strTemp);
        strTemp = (String)list.get(1);
        System.out.println(strTemp);
cs

이럴 경우 값을 얻을 때 타입케스팅을 명확히 해야하고 시간이 오래 걸린다.


 

1
2
3
4
        List<String> strList = new ArrayList();
        strList.add("hi");
        strTemp = strList.get(0);
        System.out.println(strTemp);
cs

리스트를 만들 때 제네릭을 이용하여 형을 정해주면 타입케스팅을 하지 않아도 되서 시간이 적게 걸린다.


제네릭을 클래스에도 적용할 수 있다.

Box 클래스

 

1
2
3
4
5
6
public class Box<T> {
    private T obj;
    public void set(T obj) {this.obj=obj;}
    public T get() {return obj;}
}
 
cs

 

 

메인문 내부

 

1
2
3
4
Box<String> box = new Box<String>();
box.set("test");
strTemp = box.get();
System.out.println(strTemp);
cs

 

T부분이 String로 변환되는 예제


제네릭은 여러 개 사용할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
public class Product<T, M> {
    private T kind;
    private M model;
    
    public void setKind(T kind) {this.kind=kind;}
    public void setModel(M model) {this.model=model;}
    
    public T getKind(){return kind;}
    public M getModel(){return model;}
}
cs


제네릭을 메소드에도 적용할 수 있다. 메소드에 적용할 땐 반환타입 앞에 제네릭을 선언하면 된다.

public <T> Box<T> boxing(T t);


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Util {
    public static <T> Box<T> boxing(T t){ 
        Box<T> box = new Box<T>();
        box.set(t);
        return box;
    }
    
    public static <T> boolean setData(T t){ 
        return true;
    }
    
    public static <K,V> boolean compare(Pair<K,V> p1, Pair<K,V> p2)
    {
        boolean keyCompare = p1.getKey().equals(p2.getKey());
        boolean valueCompare = p1.getValue().equals(p2.getValue());
        return keyCompare && valueCompare;
    }
}
cs


 

1
boolean result1 = Util.<Integer,String>compare(p1, p2);
cs

메소드를 사용할 때 제네릭을 명시적으로 선언해도 매개변수에 제네릭을 사용할 경우 묵시적으로 설정한다.


자바 I/O 시스템은 스트림(stream)으로 구성되어 있다.

스트림은 데이터 흐름의 추상적 개념으로 입력 스트림(input stream)은 프로그램으로의 데이터 흐름이며(파일->프로그램),

출력 스트림은(output stream)은 프로그램으로부터 나오는 데이터의 흐름을 나타낸다(프로그램->파일).


자바에서의 스트림의 형태는 바이트 스트림 클래스와 문자 스트림 클래스 두 종류가 있다.

바이트 스트림 클래스는 InputStream, OutputStream으로 입출력을 사용하고 

문자 스트림 클래스는 Reader, Writer로 입출력을 한다.


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.io.*;
 
public class FileCopy {
 
    public static void main(String[] args) throws IOException {
        File input = new File("/Users/ghdrl95/Documents/input.txt");
        File output = new File("/Users/ghdrl95/Documents/output.txt");
        
        FileInputStream in = new FileInputStream(input);
        FileOutputStream out = new FileOutputStream(output);
        
        int cTemp;
        
        while((cTemp = in.read()) != -1){
            out.write(cTemp);
        }
    }
 
}
 
cs

바이트 스트림 중 하나인 File(In,Out)putStream 이다.

File 클래스를이용해 파일의 경로를 입력하고 그것을 파일스트림에게 준다.

그리고 read()메소드를 통해 한글자씩 받아 write메소드를 통해 출력한다.

경로를 적지 않으면 프로젝트가 생성된 곳에 파일이 생성, 입력되며 파일이 없는 경우 IOexception이 발생한다.


EditText에 적힌 주소로 WebView가 접속하여 출력해주는 간단한 어플리케이션

앞에 http://를 적지 않아도 실행 되도록 설정.


MainActivity.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package com.webbrower;
 
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.EditText;
 
public class MainActivity extends AppCompatActivity {
    EditText edtUrl;
    Button btnGo, btnBack;
    WebView web;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        edtUrl = (EditText)findViewById(R.id.edtUrl);
        btnGo = (Button) findViewById(R.id.btnGo);
        btnBack = (Button) findViewById(R.id.btnBack);
        web = (WebView) findViewById(R.id.webView1);
 
        web.setWebViewClient(new CookWebViewClient());
 
        WebSettings webSet = web.getSettings();
        webSet.setBuiltInZoomControls(true);
 
        btnGo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String strTemp = edtUrl.getText().toString();
                if(!strTemp.substring(0,7).equals("http://")){
                    strTemp= "http://"+strTemp;
                }
                web.loadUrl(strTemp);
 
            }
        });
        btnBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                web.goBack();
            }
        });
    }
    public class CookWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            return super.shouldOverrideUrlLoading(view, url);
        }
    }
 
}
 
 
cs


AndroidManifest.xml 에서

<uses-permission android:name="android.permission.INTERNET"></uses-permission>
를 명시해주어야 어플내에 인터넷을 사용할 수 있다.
activity_main.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
<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:orientation="vertical"
    tools:context=".MainActivity"
    >
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <EditText
            android:id="@+id/edtUrl"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:singleLine="true"/>
        <Button
            android:id="@+id/btnGo"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="이동"/>
        <Button
            android:id="@+id/btnBack"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="이전"/>
    </LinearLayout>
    <WebView
        android:id="@+id/webView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
 
    </WebView>
</LinearLayout>
 
 
cs
 

WebBrower.zip




어플리케이션에서 아에 사용하지 않을 거라면

AndroidManifest.xml 에서 android:theme을

android:theme="@android:style/Theme.NoTitlBar" 로 수정하면 된다.


특정화면에서만 타이틀을 제거 할 때는

onCrate 메소드 안에 

requestWindowFeature(Window.FEATURE_NO_TITLE);

를 입력하면 된다.


MainActivity.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.myapplication;
 
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
 
import java.io.FileNotFoundException;
import java.io.IOException;
 
public class MainActivity extends AppCompatActivity {
    Button btnGetImage;
    ImageView imgPicture;
    private final int REQ_CODE = 200;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imgPicture = (ImageView)findViewById(R.id.imgPicture);
        btnGetImage =(Button)findViewById(R.id.btnGetImage);
        btnGetImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(Intent.ACTION_PICK);               //선택한 데이터를 반환해주는 Intent
                intent.setType(MediaStore.Images.Media.CONTENT_TYPE);         //이미지타입을 원함
                intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI); //URI 제공
                startActivityForResult(intent,REQ_CODE);                      //구분하기위한 코드번호랑 같이보냄
            }
        });
    }
 
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(requestCode == REQ_CODE)
        {
            if(resultCode == Activity.RESULT_OK)
            {
                try{
                    String name_str = getImageNameToUri(data.getData());
                    Bitmap image_bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),data.getData());
                    imgPicture.setImageBitmap(image_bitmap);
                }catch(FileNotFoundException e)
                {
 
                }catch(IOException e)
                {
 
                }catch(Exception e)
                {
 
                }
            }
        }
    }
    private String getImageNameToUri(Uri data) {
        String[] proj = {MediaStore.Images.Media.DATA};
        Cursor cursor = managedQuery(data,proj,null,null,null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        String imgPath = cursor.getString(column_index);
        String imgName = imgPath.substring(imgPath.lastIndexOf("/")+1);
        return imgName;
    }
}
 
 
cs


버튼을 눌렀을 때 Intent를 생성하여 보내는데,

타입과 데이터를 명시해 줌으로써 갤러리에 접근하는 것을 알려주고, 경로값을 가져오는데 사용할 URI를 받을 수 있도록 한다.

다른 Activity에서 선택한 정보를 가져오기 위해서는 startActivityForResult메소드를 써야하는데 그 이유는 아래와 같다.

requestCode가 0보다 클 경우 호출한 Activity가 종료될 때 현재 Activity가 onActivityResult()메소드에 반환이 되는 것이다.

onResume() 메소드 이전에 호출되는 onActivityResult 매개변수 속성 설명은 아래와 같다.

requestCode : startActivityForResult()메소드에서 보낸 코드값

resultCode : RESULT_CANCELED 나 RESULT_OK 값이 반환됨. (직접 만든 액티비티에선 setResult로 선택가능)

data : 인탠트 타입으로 오는 데이터.


먼저 requestCode가 같은지 확인하고, 잘 작동되었는지 확인(resultCode가 RESULT_OK인지 확인)

한뒤 data를 처리를 하면된다.


도움자료

http://ankyu.entersoft.kr/Lecture/android/gallery_01.asp


app-debug (4).apk

MyApplication.zip



동작순서

(1) 베팅 할사람 선택 (또는 레이싱 시작하고싶으면 '4' 입력 -> (4))

(2) 말과 베팅금액 선택

(3) 리스트에 베팅금액 저장되고 (1)로 돌아감

(4) 말이 달리면서 도착한 말이 차례대로 Grade 클래스에 저장됨

(5) 말이 전부 다 달렸는지 확인. 아직 달리고있으면 (5) 계속. 다 끝나면 순위 출력

(6) 베팅에 성공한 사람에게 베팅금액의 두배를 줌.

(7) (1)로 돌아감


각 말들은 쓰레드를 상속(Extend)받아서 HorseManager클래스에서 동시에 시작한다.

HorseManager는 쓰레드가 종료됬는지 확인하면서 현재 거리를 출력, 

말들은 일정거리를 넘을 때까지 랜덤값+기본속도값을 현재거리에 더하다가 도착하면 순위를 등록한다.

각 쓰레드가 Grade에 접근할 때 동시접근을 막기위해 Synchronized 키워드를 붙였다.


압축해제 후 이클립스에서 열면 바로 사용 가능.


(MAC에서 압축해서 PC에서 열면 MACOS라는 파일이 있을 수 있는데 무시하면된다.)


HorsePart.zip




첫번째 EditText (+,-,*,/) 두번째 EditText = (계산 결과에 출력)

실수연산 가능

직접타이핑 + 버튼을 눌러서 숫자기입

값이 안들어가있을 경우 값을 입력하라는 토스트 입력

0으로 나눌 경우 0으로 나눌 수 없다는 토스트와 함께 두번째 EditText 삭제


app-debug (3).apk


http://www.objectaid.com


ObjectAid 에서 지원하는 UML 다이어그램를 이클립스에서 사용하는 방법

1. Help -> Install New Software를 누른다.


2. Add... 버튼을 누른뒤 주소창에 http://www.objectaid.com/update 를 입력한 뒤 OK버튼을 누른다. (이름은 자유롭게 기입한다.)


3. 중앙에 뜨는 ObjectAid UML Explorer를 체크하고 finish를 누른다. 그다음부터 동의버튼을 눌러서 설치한뒤 재시작을 하면 설치가 완료 된다.


이제 File - New - Other... 를 누르면 ObjectAid UML Diagram이 나타난다



저장할 폴더 위치, 파일 이름과 각종 설정 값들을 설정하고 Finish를 누른다.
처음엔 흰 화면만 나오게되는데 이곳에 오른쪽 클릭을 하면 Add -> Java Classifier 로 클래스를 추가할 수있다.
Layout Diagram은 클래스 다이어그램을 정렬해 주는 기능이 있다.


이클립스에 등록된 프로젝트 내에서 검색을 하므로 클래스를 선택할 때 아래 폴더 위치로 프로젝트 이름을 확인하면서 넣으면 된다.



▲ Class Diagram을 사용한 예


+ Recent posts