0. 출처: https://www.edwith.org/boostcourse-android/lecture/17103/



1. 실행 결과 화면

  



2. 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
37
38
39
40
41
42
43
<?xml version="1.0" encoding="utf-8"?>
<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"
    android:gravity="center_horizontal"
    tools:context="com.tistory.qlyh8.practice.MainActivity">
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="horizontal"
        android:gravity="center">
        <Button
            android:id="@+id/button"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="사진 찍기"/>
 
        <ImageView
            android:id="@+id/image_view"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:layout_gravity="center"/>
    </LinearLayout>
 
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2">
        <com.tistory.qlyh8.practice.CameraSurfaceView
            android:id="@+id/surface_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
 
</LinearLayout>
 
cs



3. AndroidManifest.xml

인터넷 권한 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tistory.qlyh8.practice">
 
    <uses-permission android:name="android.permission.CAMERA"/>
 
    <application
        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/AppTheme">
        <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>
cs



4. CameraSurfaceView.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
package com.tistory.qlyh8.practice;
 
import android.content.Context;
import android.hardware.Camera;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
 
import java.io.IOException;
 
// SurfaceView 를 사용하여 카메라 미리 보기를 추가
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
 
    // SurfaceView 는 껍데기 역할만 하고 컨트롤은 SurfaceHolder 가 담당
    SurfaceHolder holder;
    Camera camera = null;
 
    public CameraSurfaceView(Context context) {
        super(context);
        init(context);
    }
 
    public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
 
    private void init(Context context){
        holder = getHolder();
        holder.addCallback(this);
    }
 
    // SurfaceView 가 만들어지는 시점에 호출
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // 카메라 객체 오픈
        camera = Camera.open();
        try {
            // 카메라 객체에 SurfaceView 를 미리보기로 사용
            camera.setPreviewDisplay(holder);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    // SurfaceViw 가 변경되는 시점에 호출, 화면에 보여지기 전에 크기를 결정
    @Override
    public void surfaceChanged(SurfaceHolder holder, int formatint width, int height) {
        camera.startPreview(); // 미리보기 화면에 렌즈로부터 들어온 영상을 뿌려줌
 
    }
 
    // SurfaceView 가 소멸하는 시점에 호출
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        camera.stopPreview(); // 미리보기 중지
        camera.release();   // 리소스 해제
        camera = null;
    }
 
    // 사진 찍기
    public boolean capture(Camera.PictureCallback callback){
        if(camera != null){
            camera.takePicture(nullnull, callback);
            return true;
        } else{
            return false;
        }
    }
}
 
cs



5. 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
package com.tistory.qlyh8.practice;
 
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
 
 
public class MainActivity extends AppCompatActivity {
 
    private ImageView imageView;
    private CameraSurfaceView surfaceView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        imageView = findViewById(R.id.image_view);
        surfaceView = findViewById(R.id.surface_view);
 
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                surfaceView.capture(new Camera.PictureCallback() {
                    public void onPictureTaken(byte[] data, Camera camera) {
                        // 사진 찍은 결과가 byte[]로 전달된 것을 이미지뷰로 보여주기
                        // 이미지 resizing
                        BitmapFactory.Options options = new BitmapFactory.Options();
                        // 8분의 1크기로 비트맵 객체 생성
                        options.inSampleSize = 8;
                        // 가져온 결과물을 비트맵 객체로 생성
                        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                        // 이미지뷰에 비트맵 객체 설정
                        imageView.setImageBitmap(bitmap);
                        // 사진을 찍으면 미리보기가 중지되기 때문에 다시 시작하게 함
                        camera.startPreview();
                    }
                });
            }
        });
    }
}
cs



6. build.grade (app)

위험권한이기 때문에 불필요한 코드는 추가하지 않도록 targetSdkVersion을 22로 낮춘다.



7. 참고

- Camera API: https://developer.android.com/guide/topics/media/camera

- Control the camera: https://developer.android.com/training/camera/cameradirect

- Take Photos: https://developer.android.com/training/camera/photobasics

'Android' 카테고리의 다른 글

동영상 재생하기  (0) 2018.08.23
음악 재생하기  (0) 2018.08.23
사진 찍어 보여주기  (0) 2018.08.23
인터넷 연결상태 확인하기  (0) 2018.08.19
SQLiteOpenHelper 사용해보기  (0) 2018.08.19

0. 출처: https://www.edwith.org/boostcourse-android/lecture/17103/



1. 실행 결과 화면

   



2. 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
<?xml version="1.0" encoding="utf-8"?>
<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"
    android:gravity="center_horizontal"
    tools:context="com.tistory.qlyh8.practice.MainActivity">
 
    <Button
        android:id="@+id/button"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="사진 찍기"/>
 
    <ImageView
        android:id="@+id/image_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>
 
cs



3. 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.tistory.qlyh8.practice;
 
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
 
import java.io.File;
 
public class MainActivity extends AppCompatActivity {
 
    private ImageView imageView;
    private File file;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        imageView = findViewById(R.id.image_view);
        // sd 카드 폴더 참조
        File sdcard = Environment.getExternalStorageDirectory();
        file = new File(sdcard, "capture.jpg");
 
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 사진 앱 띄우기
                // 액션 정보를 전달하는 인텐트 객체 생성
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                // 파일에서부터 Uri 를 생성하여 카메라 앱에서 찍은 사진을 저장할 위치 넣음
                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
                startActivityForResult(intent, 101);
            }
        });
    }
 
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == 101 && resultCode == RESULT_OK){
            // 이미지 resizing
            BitmapFactory.Options options = new BitmapFactory.Options();
            // 8분의 1크기로 비트맵 객체 생성
            options.inSampleSize = 8;
            // 파일을 디코딩하여 비트맵 객체 생성
            Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
            // 이미지뷰에 비트맵 객체 설정
            imageView.setImageBitmap(bitmap);
        }
    }
}
cs



4. AndroidManifest.xml

sdcard 권한 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tistory.qlyh8.practice">
 
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 
    <application
        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/AppTheme">
        <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>
cs



5. build.gradle (app)

targetSdkVersion을 22로 낮추어 실행 (불필요한 코드 추가하지 않기)

'Android' 카테고리의 다른 글

음악 재생하기  (0) 2018.08.23
카메라 미리 보여주기  (0) 2018.08.23
인터넷 연결상태 확인하기  (0) 2018.08.19
SQLiteOpenHelper 사용해보기  (0) 2018.08.19
SQLite database 사용해보기  (0) 2018.08.19


static


static이 붙은 멤버변수 (클래스변수)

클래스가 메모리에 올라갈 때 이미 자동적으로 생성되기 때문에, 인스턴스를 생성하지 않아도 사용할 수 있다.

인스턴스를 생성하면 각 인스턴스들은 서로 독립적이기 때문에 서로 다른 값을 유지한다.

각 인스턴스들이 공통적으로 같은 값이 유지되어야 하는 경우에 static을 붙인다. (같은 메모리를 공유)


1
2
3
4
5
6
class Card {
    String kind;    // 카드 무늬 - 인스턴스 변수
    int number;    // 카드 숫자 - 인스턴스 변수
    static int width = 100;     // 카드  폭 - 클래스 변수
    static int height = 250;         // 카드 높이 - 클래스 변수
}
cs

각 Card 인스턴스는 자신만의 무늬(kind), 숫자(number)를 유지해야 하여 인스턴스 변수로 선언하였고

각 카드의 폭(width)과 높이(height)는 모든 인스턴스가 공통적으로 같은 값을 유지해야하므로 클래스 변수로 선언했다.

카드의 폭을 변경해야 할 경우, 모든 카드의 width을 변경하지 않고 한 카드의 width값만 변경해도 모든 카드의 width값이 변경된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class CardTest {
    System.out.println("카드 폭: " + Card.width); // 클래스변수는 객체 생성없이 직접 사용 가능
    System.out.println("카드 높이: " + Card.height); 
 
    Card c1 = new Card();
    c1. kind = "하트";
    c1. number = 7;
    System.out.println("c1의 카드 폭: " + c1.width + " c1의 카드 높이: " + c1.height);
 
    Card c2 = new Card();
    c2. kind = "스페이드"
    c2.number = 4;
    System.out.println("c2의 카드 폭: " + c2.width + " c2의 카드 높이: " + c2.height);
    
    c1.width = 50// 클래스 변수 값을 변경
    c1.height = 80;
 
    System.out.println("c1의 카드 폭: " + c1.width + " c1의 카드 높이: " + c1.height);
    System.out.println("c2의 카드 폭: " + c2.width + " c2의 카드 높이: " + c2.height);
}
cs

결과

카드 폭: 100

카드높이: 250

c1의 카드 폭: 100 c1의 카드 높이: 250

c2의 카드 폭: 100 c2의 카드 높이: 250

c1의 카드 폭: 50 c1의 카드 높이: 80

c2의 카드 폭: 50 c2의 카드 높이: 80



static이 붙은 메서드 (클래스 메서드)

인스턴스 생성없이 호출이 가능하다.


인스턴스 변수는 인스턴스를 생성해야만 존재하기 때문에 static이 붙은 메서드를 호출할 때 

인스턴스가 생성되어 있을 수도 있고, 그렇지 않을 수 있기 때문에 인스턴스 변수의 사용을 허용하지 않는다.

반대로, 인스턴스 변수나 인스턴스 메서드에서는 static이 붙은 멤버들을 사용하는 것이 가능하다.

인스턴스 변수가 존재한다는 것은 static이 붙은 변수가 이미 메모리에 존재한다는 것을 의미하기 때문이다.


메서드 안에서 인스턴스 변수를 필요로 한다면, static을 붙일 수 없지만 

인스턴스 변수를 필요로 하지 않는다면, 가능하면 static을 붙이는 것이 좋다.

static을 안 붙인 메서드는 실행 시 호출되어야 할 메서드를 찾는 과정이 추가적으로 필요하기 때문에 시간이 더 걸린다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MyMath {
    long a, b;
 
    long add() { return a+b; }    // 인스턴스 메서드
    static long add(long a, long b) { return a+b; }    // static 메서드, 인스턴스 변수와 관계없이 매개변수만으로 작업이 가능
}
 
class MathTest {
    public static void main(String args[]){
        // 인스턴스 메서드는 객체 생성 후에 호출이 가능
        MyMath mm = new MyMath();
        mm.a = 200L;
        mm.b = 100L;
        System.out.println("인스턴스 메서드: " + mm.add());
 
        // static 메서드 호출
        System.out.println("static 메서드: " + MyMath.add(200L, 100L));
    }
}
cs

결과

인스턴스 메서드: 300

static 메서드: 300



static이 붙은 블록 (클래스 블록)

클래스 내부에 만들 수 있는 초기화 블록으로, 메서드와 같이 조건문과 반복문 등을 자유롭게 사용할 수 있다.

클래스가 초기화될 때 한번만 실행되고, main() 보다 먼저 수행된다. (MyTest1 예제)

초기화 작업이 복잡해 변수 초기화만으로는 부족한 경우 사용한다. (MyTest2 예제)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MyTest1 {
    static {    // static 블록
        System.out.println("static{ }");
    }
 
    {     // 인스턴스 블록
        System.out.println("인스턴스{ }"); 
    }
 
    pulic MyTest1() {
        System.out.println("생성자");
    }
 
    public static void main(String args[]){
        System.out.println("main() 시작");
        MyTest1 mt = new MyTest1();
    }
}
cs

결과

static { }

main() 시작

인스턴스 { }

생성자


1
2
3
4
5
6
7
8
9
10
11
12
13
class MyTest2 {
    static int[] arr = new int[10];
 
    static {    // static 블록
        for(int i=; i<arr.length ; i++){
            arr[i] = i;
        }
    }
 
    public static void main(String args[]){
        System.out.println("arr[1]: " + arr[1]);
    }
}
cs



final


final이 붙은 멤버변수

한 번만 초기화가 가능한 변수이다. 상수를 만들 때 이용한다.


final이 붙은 메서드

오버라이드하거나 숨길 수 없는 메서드이다.


final이 붙은 클래스

상속 계층 구조에서 마지막(final) 클래스인, 상속할 수 없는 클래스로, 확장될 수 없다.


1
2
3
4
5
6
7
final class MyFinal {    // 조상이 될 수 없는 클래스
    final int MAX_SIZE = 10;    // 값을 변경할 수 없는 멤버변수(상수) 
    
    final void getMaxSize() {    // 오버라이딩 할 수 없는 메서드
        return MAX_SIZE;
    }
}
cs



static final

static final을 붙여서, 해당 클래스를 쓸 때 변하지 않고 계속 일관된 멤버 상수로 쓸 것임을 지정한다. 


늘 같은 값을 가질 객체이기 때문에, 

인스턴스를 생성할 때마다 매번 새로 메모리를 잡고 초기화시키지 않고 

한 번만 메모리를 잡고 하나의 메모리 공간을 쓸 수 있게 한다.


예를 들어, 학교 점수 클래스에서 최대 점수를 100으로 만든다면

public static final int MAX_SCORE = 100;

으로 나타낼 수 있다.




참고 출처

http://rockdrumy.tistory.com/214

- 자바의 정석 책

'Java' 카테고리의 다른 글

객체지향 프로그래밍 (Object-Oriented Programming)  (0) 2018.11.26
객체지향 설계  (0) 2018.11.15
직렬화 (Serialization)  (0) 2018.08.04
Overloading (오버로딩)  (0) 2018.07.28
Overriding (오버라이딩, 재정의)  (0) 2018.07.28

+ Recent posts