[스터디] 안드로이드 스튜디오

11 분 소요

  • Alt + Enter :: 라이브러리를 자동으로 찾아줌

액티비티 :: 앱을 만드는데 필수 요소 임

  • MainActivity 클래스 :: AppCompatActivity 클래스를 상속함

  • 생명주기 :: onCreate()로 생성, startActivity()로 시작, finish()로 끝. onPause() - 액티비티가 화면에 보이지 않을 때 처리하고 싶은 코드수행

    https://s3-us-west-2.amazonaws.com/secure.notion-static.com/62c886ce-8166-4299-a092-b6184311ff32/image_(2).png

  • 액티비티 상태 3가지 :: 실행(Resumed) - 일시정지(Paused) - 중지(Stopped)

  • 앱 실행시 MainActivity 설정된 xml (참고 :: https://recipes4dev.tistory.com/67)

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/89f15235-46df-486b-8339-448dc03b6758/Untitled.png

AndroidManifest.xml 은 프로젝트 설정 파일

(참고 :: https://hyeonstorage.tistory.com/151)

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a018d672-efaf-41f0-9714-69489aee1d10/Untitled.png

  • 안드로이드 어플리케이션을 구성하는 컴포넌트들(Activity, Service, Broadcast Receiver, Content Provider)을 기술하는 곳

컴포넌트들 - Service

컴포넌트들 - Broadcast Receiver

컴포넌트들 - Content Provider

위젯

컨테이너뷰 — 리사이클러뷰 :: 어댑터, 데이터셋 개념 필요

프래그먼트 — 화면 영역을 나눔

알림 기능

인텐트 (intent) — 어떤 의도를 가지고 무엇인가를 전달하는 역할, 특정 앱을 실행하거나 데이터를 전달하는 역할을 함

  • 액션 :: 전화를 걸거나 웹 페이지를 보는 등의 동작을 의미함
  • 데이터 :: 동작을 수행하기 위해 필요한 값
  • 카테고리 :: 수행할 액션에 대한 추가적인 정보
  • 타입 :: 수행할 인텐트 데이터의 명시적인 타입 (video, mpeg)
  • 컴포넌트 이름 :: 대상 컴포넌트의 완전한 클래스 이름
  • 추가 정보 :: 인텐트를 다루는 컴포넌트에 추가적으로 전달할 한 쌍의 키와 값
  • 인텐트는 액티비티를 실행하는 용도로 만들어진 것은 아님. 액티비티와 서비스, 그리고 브로드캐스트 등의 안드로이드 컴포넌트를 실행하고 데이터를 전달하는 용도로 만들어진 것, 하지만 액티비티 실행이 가장 많음.

setContentView()

  • setContentView(R.layout.activity_main); // 메인 액티비티에서 setContentView 를 호출해야 화면이 메모리에 올라오고 그 안에 있는 컴포넌트를 사용할 수 있음

TextView에서

@String/greeting :: 아이디화 해서 문자열 저장함. (참고 :: https://nanstrong.tistory.com/279)

res 폴더/ values / String.xml에 추가됨 — open editor에서 언어 설정 가능함

언어 버튼을 클릭하여 각 나라별 글로 넣을 수 있음.

단위 : dp (이미지), sp (텍스트)

Toast :: 도움말 팁 보여주기

Toast.makeText(this, “ButtonClick”, Toast.LENGTH_LONG).show();

다른 scope에 있어 위의 this를 쓸 수 없을 때 getApplicationContext()을 호출한다.

그림은 drawable 폴더에 반드시 소문자로 넣어야 함.

v24는 태블릿용

if (id.equals("admin") && pw.equals("admin")) {
    Intent intent = new Intent(this, FirstActivity.class);
    startActivity(intent);
} else {
    Toast.makeText(this, "아이디와 패스워드가 올바르지 않습니다.",
            Toast.LENGTH_SHORT).show();
}

컴포넌트 네 가지.

컴포넌트 에는

  1. 엑티비티[안드로이드] 컴포넌트 #1 - 액티비티(Activity)2. 서비스[안드로이드] 컴포넌트 #2 - 서비스3. 브로드캐스트 리시버[안드로이드] 컴포넌트 #3 - 브로드캐스트 리시버4. 컨텐츠 프로바이더[안드로이드] 컴포넌트 #4 - 컨텐츠 프로바이더

출처:

https://namsieon.com/262

[남시언닷컴]

컴포넌트 #1 - 액티비티

우선 액티비티 라는 용어부터 잠깐 적어볼까 합니다.

안드로이드 서적에 보면 Activity 를 “ 액티비티 “ 라고도 표기하기도 하고

또 어떤 서적에서는 Activity를 “ 활동 “ 이라고 부르기도 하더군요 ;;;

어쨋든 저는 Activity 를 “액티비티” 로 표기하도록 하겠습니다.

액티비티(Activity) 는 하나의 사용자 인터페이스를 나타내는 단위입니다.

하나의 어플리케이션에는 여러개의 액티비티가 존재할 수 있는데요, 이들 액티비티들은 하나의 결합된 UI를 형성하기 위해 함께 동작하지만, 각각의 액티비티들은 다른 액티비티와 독립되어 있습니다. 각각의 액티비티는 Activity 클래스의 하위 클래스로 구현됩니다. ( 즉, Activity 클래스를 상속하는 것입니다 )

하나의 어플리케이션은 한 개 또는 여러개의 액티비티를 가집니다.

현재의 액티비티에서 다른 액티비티를 시작하면 액티비티가 이동되지요.

또, 각각의 액티비티에는 draw(그리기) 가 가능한 하나의 윈도우가 기본적으로 제공되는데요, 윈도우 내의 컨텐츠는 뷰(View) 클래스의 계층구조에 의해 만들어지게 됩니다.

그리고, 각각의 뷰는 윈도우 내의 특정 하나의 사각형 영역을 제어하죠.

부모 (parent) 뷰는 자식들( children ) 의 레이아웃을 포함하고 구조화 하게 됩니다.

계층구조 중 최하단의 뷰는 자신이 제어하는 사각형 영역을 그리며 그 영역에 국한된 사용자 액션에 대해 책임을 집니다.

이처럼 뷰는 액티비티와 사용자간의 상호작용이 이루어지는 영역입니다.

안드로이드는 버튼, 텍스트필드, 체크박스, 라디오버튼, 스크롤바, 메뉴, 리스트 등의 이미 만들어져 있는 수많은 뷰를 가지고 있습니다.뷰는 Activity.setContentView() 메소드로 액티비티 윈도우 내에 위치하게 됩니다.

https://t1.daumcdn.net/cfile/tistory/192E1B0B4C5E90EE37

이 컨텐츠 뷰는 뷰의 계층구조 중 최상위에 있는 뷰 객체입니다.

출처:

https://underclub.tistory.com/263

[남시언닷컴]

컴포넌트 #2 - 서비스

네 가지의 컴포넌트 중 두번째인 서비스 컴포넌트 입니다.

서비스는 보여지는 사용자 인터페이스(UI) 를 가지지 않고 백 그라운드(background)에서 실행되는 컴포넌트 입니다.

무슨 말인고 하니… 서비스는 사용자가 다른 작업을 하는 중에도 백 그라운드에서 음악을 재생하거나 데이터를 처리하는 등의 작업을 하는 역할이죠. 또한 어떤 결과를 처리하여 그것을 원하는 액티비티에게 제공할 수도 있습니다.

각각의 서비스는 Service 클래스를 상속합니다.

https://t1.daumcdn.net/cfile/tistory/1629F91F4C5EA25171

음악을 재생하는 음악재생 플레이어는 서비스의 일종인데, 사용자가 음악을 선택하고 재생, 되감기, 다음곡 등의 작업을 할 수 있는 하나 또는 여러개의 액티비티가 있을 수 있겠죠.

하지만 음악을 재생하는 그 자체는 액티비티에 의해 제어되면 안됩니다.

왜냐하면 사용자가 음악 플레이어 화면을 벗어나서 다른 작업 중에도 음악은 계속 재생되어야 하기 때문이죠. 그렇게 되기 위해서는 액티비티는 백 그라운드에서 실행되는 하나의 서비스를 시작해야 됩니다.실행되고 있는 서비스에 접속하거나 서비스를 실행하여 접속하는 것도 가능합니다.음악 재생 플레이어라면 서비스에 접속하여 음악을 멈추거나, 재생하거나, 다음곡으로 넘어가는 등의 UI를 통해 사용자와 서비스가 커뮤니케이션 할 수 있게 됩니다.액티비티와 다른 컴포넌트들 처럼 , 서비스도 어플리케이션 프로세스의 메인 스레드 내에서 실행되는데요, 서비스가 다른 컴포넌트의 방해를 받지 않기 위해 또 다른 스레드를 만들어서 작동하기도 합니다.

출처:

https://underclub.tistory.com/265

[남시언닷컴]

컴포넌트 #3 - 브로드캐스트 리시버

네 가지의 컴포넌트 중 세 번째 컴포넌트 인 브로드캐스트 리시버 입니다.

브로드 캐스트 리시버( Broadcast receiver ) 는 아무것도 하지 않는 컴포넌트 입니다.

브로드캐스트 공지( announcement ) 를 수신하고 응답하는 역할만을 수행합니다.

배터리 부족, 사진 촬영이 됨, 언어 설정이 바뀜 등의 시스템 코드에서 발생되는 브로드캐스트는 어플리케이션에서도 발생시킬 수가 있습니다.

어플리케이션은 여러개의 공지에 응답하는 여러개의 브로드캐스트 리시버를 가질 수 있으며,

모든 리시버는 BroadcastReceiver 클래스를 상속합니다.

https://t1.daumcdn.net/cfile/tistory/1723F2254C5EB13D29

브로드캐스트 리시버는 사용자 인터페이스는 보여주지 않지만, 그것이 수신한 정보에 응답하는 액티비티를 실행하거나 ,

노티피케이션 매니저 ( notification manager )

를 통해 사용자에게 알려 줄 수 있습니다.

노티피케이션을 이용하여 모바일 기기의 진동, 사운드 재생 등의 방법으로 사용자에게 알려 줄 수 있고, 일반적으로는 상태바 ( status bar ) 내에 아이콘을 표시하여 사용자에게 알려주곤 합니다.

출처:

https://underclub.tistory.com/266

[남시언닷컴]

컴포넌트 #4 - 컨텐츠 프로바이더

네 가지의 컴포넌트 중 네번째인 컨텐츠 프로바이더 입니다.

컨텐츠 프로바이더 ( Content Provider : CP ) 는 특정 어플리케이션의 데이터 SET 을 만드는 역할을 합니다. 그 데이터는 파일, SQLite 데이터베이스 등의 내부에 저장되어 있는 데이터이지요.

CP 는 자신이 제어하는 데이터를 다른 어플리케이션에서도 쓸 수 있도록 하는 사명을 가집니다.

CP 는 ContentProvider 클래스를 상속받아 구현합니다.

https://t1.daumcdn.net/cfile/tistory/152D0E234C600D71E0

하지만

어플리케이션은 이런 메소드를 직접 호출하는 대신, 컨텐츠 리졸버 ( ContentResolver ) 객체를 사용하여 그것의 메소드를 호출하게 됩니다

.

컨텐츠 리졸버는 어떠한 CP 와도 통신할 수 있으며,

프로세스간의 통신 ( IPC : Inter Progress Communication ) 을 위해 프로바이더와 협력하는 구조입니다.

특정 컴포넌트에 의해 처리되는 요청은 안드로이드가 그 컴포넌트의 어플리케이션 프로세스를 실행하거나 시작하고, 그 컴포넌트에 맞는 인스턴스를 활성화 하거나 생성하게 되죠.

출처:

https://underclub.tistory.com/267

[남시언닷컴]

뷰의 개요

View = 안드로이드 UI의 기본적인 구축 요소

= 화면에 보이는 컨트롤이나 위젯 등 UI 구성요소를 의미함.

= 사용자의 눈에 보이는 화면 구성요소

View Group > Layout들 / AdapterView / ToolBar

요즘에는 listview 대신 ~을 많이 쓰라고 함.

안드로이드 View 클래스 계층도

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/0a08e104-6880-4613-b19c-08399ec6900b/Untitled.png

SystemClock.sleep(1000);

Adapter = View + Data ⇒ 데이터를 보여주기 위한 view :: ListView, GridView

  1. 어댑터를 상속한 어댑터 클래스를 정의한다. - 메서드 getView(int position)
  2. 리스트뷰를 생성한다
  3. 자료목록을 준비하고 어댑터를 생성한다.
  4. 리스트뷰에 어댑터를 연결한다.
  5. 리스트뷰가 어댑터의 getVew(0)을 호출한다.
  6. getView(0) 자료 목록 0번째의 자료를 가져와서 화면 레이아웃에 데이터를 넣는다
  7. 자료 목록의 갯수만큼 리스트뷰가 어댑터의 getView(position)을 호출한다.
  8. getView(postion) 자료 목록 position 번째의 자료를 가져와서 화면 레이아웃에 데이터를 넣는다.
  9. 자료 목록의 모든 자료를 원하는 형식으로 리스트뷰에 표시한다.
// 기초적인 회원 등록 및 로그인 로직

package com.example.edittexttest;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private EditText editText_id;
    private EditText editText_pw;
    private Button button_login;
    private Button button_register;
    private List<Member> memberList;    // 회원 등록시 회원 정보(id,pw) 저장할 리스트

    public MainActivity() {
        this.editText_id = null;
        this.editText_pw = null;
        this.button_login = null;
        this.button_register = null;
//        this.user_id = null;
//        this.user_pw = null;
        memberList = new ArrayList<>();

    }

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

        this.editText_id = (EditText) this.findViewById(R.id.editText_id);
        this.editText_pw = (EditText) this.findViewById(R.id.editText_pw);
        this.button_login = (Button) this.findViewById(R.id.button_login);
        this.button_register = (Button) this.findViewById(R.id.button_register);

        button_login.setOnClickListener(v -> {
            String str_id = editText_id.getText().toString();
            String str_pw = editText_pw.getText().toString();

            if(str_id.equals("") || str_pw.equals("")) {
                Toast.makeText(this, "ID와 Password 모두 입력되어야 합니다.", Toast.LENGTH_SHORT).show();
//            } else if(str_id.equals(user_id) && str_pw.equals(user_pw)){
//                Toast.makeText(this, user_id+"님 환영합니다.", Toast.LENGTH_SHORT).show();
            } else if (isMember(str_id,str_pw)) {
                Toast.makeText(this, str_id+"님 환영합니다.", Toast.LENGTH_SHORT).show();
            } else{
                Toast.makeText(this, "ID와 Password가 잘못되었습니다.", Toast.LENGTH_SHORT).show();
            }
        });

        button_register.setOnClickListener(v -> {
            String str_id = editText_id.getText().toString();
            String str_pw = editText_pw.getText().toString();

            if(str_id.equals("") || str_pw.equals("")){ // id, pw 입력 여부 확인
                Toast.makeText(this, "ID와 Password 모두 입력되어야 합니다.", Toast.LENGTH_SHORT).show();
            }else{
//                user_id = editText_id.getText().toString();
//                user_pw = editText_pw.getText().toString();
                if(addMember(str_id, str_pw)){
                    Toast.makeText(this, "ID와 Password가 등록되었습니다.", Toast.LENGTH_SHORT).show();
                }else{ // Member 추가가 실패한 이유 :: ID 중복 --> 중복 메시지
                    Toast.makeText(this, "ID가 중복됩니다. 다른 ID를 넣어주세요", Toast.LENGTH_SHORT).show();
                }
            }

        });

    }

    public boolean addMember(String id, String pw){
        if(memberList.stream().anyMatch(m->m.inMember(id)))     // ID 중복 여부 체크
            return false;
        else {
            memberList.add(new Member(id, pw)); // ID 중복이 없을 때 list에 추가
            return true;
        }
    }
    public boolean isMember(String id, String pw){      // ID와 PW가 모두 맞는지 확인
        return (memberList.stream().anyMatch(m->m.isMember(id,pw)));
    }
}

class Member {   // 회원 정보를 담을 클래스
    String id;
    String pw;

    public Member(String id, String pw) {
        this.id = id;
        this.pw = pw;
    }

    public boolean isMember(String id, String pw){
        return id.equals(this.id) && pw.equals(this.pw);
    }

    public boolean inMember(String id){
        return id.equals(this.id);
    }
}

위 예시에서 stream().anyMatch()을 사용했음. [참고 :: Stream find, match 사용 방법 및 예제 ( https://codechacha.com/ko/java8-stream-find-match/) ]

New→ vector asset — 이미지 선택 가능 / 이후 아래와 같이 src에서 해당 파일 지정

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/957e8f93-e594-40aa-9db4-692e48c6136c/Untitled.png

  • android:layout_weight=”1” // 각 요소마다 가중치를 1로 주면 같은 비율로 배치가 된다.

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/4ceea6c4-5c33-4a3f-a28b-96c852fefd49/Untitled.png

인텐트 실습

MainActivity —> ResultActivity

버튼 클릭 이벤트에서 Intent를 생성하여 매개변수 정보를 넣고(putExtra메서드) startActivity()에 인텐트를 넣어서 호출

public class MainActivity extends AppCompatActivity {

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

        ImageButton imageButton = findViewById(R.id.imageButton);
        imageButton.setOnClickListener(v->{
            Intent intent = new Intent(this, ResultActivity.class);
            String height = ((EditText)findViewById(R.id.editText_height)).getText().toString();
            String weight = ((EditText)findViewById(R.id.editText_weight)).getText().toString();
            intent.putExtra("height",height);
            intent.putExtra("weight",weight);
            this.startActivity(intent);
        });
    }
}

받는 쪽에서는 getIntent()함수를 통해 인텐트를 받고 getStringExtra()로 매개변수를 전달받음

public class ResultActivity extends AppCompatActivity {

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

        Button button_return = findViewById(R.id.button_return);
        button_return.setOnClickListener(v->{
//            Toast.makeText(this,"리턴", Toast.LENGTH_LONG).show();
            this.finish();
        });
        Double height = Double.valueOf(this.getIntent().getStringExtra("height"));
        Double weight = Double.valueOf(this.getIntent().getStringExtra("weight"));

        double BMI = weight / Math.pow(height/100, 2);
//        Toast.makeText(this,String.valueOf(BMI),Toast.LENGTH_LONG).show();
        TextView textView_result = findViewById(R.id.textView_result);
        ImageView imageView = findViewById(R.id.imageView);
        if (BMI >= 35.0){
            textView_result.setText("고도 비만");
            imageView.setImageResource(R.drawable.ic_baseline_sentiment_very_dissatisfied_24);
            imageView.setColorFilter(Color.parseColor("#55ff0000"));
        }else if (BMI >= 30.0){
            textView_result.setText("2단계 비만");
            imageView.setImageResource(R.drawable.ic_baseline_sentiment_dissatisfied_24);
            imageView.setColorFilter(Color.parseColor("#55ff0000"));
        }else if (BMI >= 25.0){
            textView_result.setText("1단계 비만");
            imageView.setImageResource(R.drawable.ic_baseline_sentiment_satisfied_24);
            imageView.setColorFilter(Color.parseColor("#55ff0000"));
        }else if (BMI >= 23.0){
            textView_result.setText("과체중");
            imageView.setImageResource(R.drawable.ic_baseline_sentiment_satisfied_alt_24);
//            imageView.setColorFilter(Color.parseColor("#55ff0000"));
        }else if (BMI >= 18.0){
            textView_result.setText("정상");
            imageView.setImageResource(R.drawable.ic_baseline_sentiment_very_satisfied_24);
//            imageView.setColorFilter(Color.parseColor("#FF8BC34A"));
        }else {
            textView_result.setText("저체중");
            imageView.setImageResource(R.drawable.ic_baseline_sentiment_dissatisfied_24);
//            imageView.setColorFilter(Color.parseColor("#55ff0000"));
        }
    }
}

AndroidManifest.xml에 아래와 같이 부모 Activity를 설정하면 화면 좌상단에 (←) 표시가 생김. 이전 페이지로 이동가능

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a35e9fa2-2f61-44b8-9b85-c6d9e9ad8784/Untitled.png

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d19560d6-b484-4829-be88-3e091633b49a/Untitled.png

Canvas 실습

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d9f1a8a3-5d28-46a3-b757-1f2bdffd62c9/Untitled.png

MainActivity에서 layout대신 View를 상속받은 객체를 불러온다

(나만의 view를 만들면 레이아웃 제약이 없기에 맘대로 canpas로 paint 할 수 있다)

public class MainActivity extends AppCompatActivity {

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

        MyGraphView myGraphView = new MyGraphView(this);
        this.setContentView(myGraphView);
    }
}

생성자 (context)와 onDraw(canvas)를 반드시 호출해야 함.

public class MyGraphView extends View {

    public MyGraphView(Context context) {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setColor(Color.BLUE);

//        canvas.drawLine(10,10,300,10,paint);
//        paint.setStrokeWidth(10);
//        canvas.drawLine(30,30,500,30,paint);
//        paint.setColor(Color.RED);
//        canvas.drawLine(60,60,500,60,paint);
//        paint.setColor(Color.GRAY);
//        Rect rect = new Rect(10,50,110,150);
//        canvas.drawRect(rect,paint);
//        paint.setColor(Color.CYAN);
//        paint.setStyle(Paint.Style.STROKE);
//        canvas.drawCircle(100,100,50,paint);
        paint.setStrokeWidth(1);
        paint.setTextSize(20.0f);
        canvas.drawText("일본 올림픽 열어봐라",150.0f, 300.0f,paint);
        paint.setStrokeWidth(10);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.BLUE);
        canvas.drawCircle(100,100,50,paint);
        paint.setColor(Color.BLACK);
        canvas.drawCircle(220,100,50,paint);
        paint.setColor(Color.RED);
        canvas.drawCircle(340,100,50,paint);
        paint.setColor(Color.YELLOW);
        canvas.drawCircle(160,160,50,paint);
        paint.setColor(Color.GREEN);
        canvas.drawCircle(280,160,50,paint);

    }
}

mp3 플레이어

res 폴더에 raw 폴더를 만들어 주고 mp3파일을 넣는다. MediaPlayer:: 싱글톤, 나중에 release 를 해 줘야 함.

public class MainActivity extends AppCompatActivity {
    private Switch music_player;
    private MediaPlayer mediaPlayer;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.music_player = findViewById(R.id.switch1);
        this.mediaPlayer = MediaPlayer.create(this,R.raw.file_example_mp3_700kb);
        this.music_player.setOnClickListener( v -> {
            if(music_player.isChecked()) {
                mediaPlayer.start();
            }else{
                mediaPlayer.pause();
            }
        });

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        this.mediaPlayer.release();

    }
}

  • 핸드폰 연결 Android>SDK>platform-tools 에 cmd로 들어가서 —— 잘 안됨 (이런 방법도 있었다 )
  • 사진 보정
  • :: 가로로 강제적으로 고정
  • 경사도 측정 (tilt 센서)
public class MainActivity extends AppCompatActivity implements SensorEventListener {
    private SensorManager sensorManager;
    private SlideView slideView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 가로 모드 고정하기
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); // 가로로 됨
//        setContentView(R.layout.activity_main);
//        this.sensorManager.getDefaultSensor(SensorManager.SENSOR_DELAY_FASTEST);
        this.slideView = new SlideView(this);
        setContentView(slideView);
    }

    @Override
    public void onSensorChanged(SensorEvent event){
        this.slideView.onSensorEvent(event);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }
}

public class SlideView extends View {
    private Paint greenPaint, blackPaint;
    private float center_x, center_y, x_coord, y_coord;

    public SlideView(Context context) {
        super(context);
        this.greenPaint = new Paint();
        this.blackPaint = new Paint();
        this.greenPaint.setColor(Color.GREEN);
        this.blackPaint.setColor(Color.BLACK);
        this.center_x = 0;
        this.center_y = 0;
        this.x_coord = 0;
        this.y_coord = 0;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        this.center_x = this.getWidth() /2;
        this.center_y = this.getHeight() /2;

        // 검은색 원을 그린다
        canvas.drawCircle(center_x,center_y,100.0f, blackPaint);
        // 녹색 원을 그린다
        canvas.drawCircle(center_x,center_y,100.0f, greenPaint);
        // 십자선을 하나 그린다
        canvas.drawLine(center_x-20.0f, center_y, center_x+20.0f, center_y, blackPaint);
        canvas.drawLine(center_x, center_y-20.0f, center_x, center_y+20.0f, blackPaint);

        canvas.drawCircle(center_x,center_y,100.0f, blackPaint);
        canvas.drawCircle(x_coord +center_x,y_coord + center_y,100.0f, greenPaint);
        canvas.drawLine(center_x-20.0f, center_y, center_x+20.0f, center_y, blackPaint);
        canvas.drawLine(center_x, center_y-20.0f, center_x, center_y+20.0f, blackPaint);

    }

    public void onSensorEvent(SensorEvent event){
        this.x_coord = event.values[0]*20; // x 축 값
        this.y_coord = event.values[1]*20;  // y 축 값
        this.invalidate();      // 화면 갱신 -- 에니메이션 효과를 줄 때 꼭 사용
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) { // 화면이 바뀔 때 마다 호출됨
        super.onSizeChanged(w, h, oldw, oldh);
        this.center_x = w / 2.0f;
        this.center_y = h / 2.0f;
    }
}

  • SimpleDB — SQLiteOpenHelper 클래스 사용
public class MainActivity extends AppCompatActivity {

    private UserDBHelper userDBHelper;
    private SQLiteDatabase sqldb;
    private EditText editText_Name, editText_Numbers, editText_View_Name, editText_View_Numbers;
    private Button button_init, button_input, button_search;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.userDBHelper = new UserDBHelper(this, "SimpleDB", null, 1);
        this.editText_Name = findViewById(R.id.editText_Name);
        this.editText_Numbers = findViewById(R.id.editText_Numbers);
        this.editText_View_Name = findViewById(R.id.editText_View_Name);
        this.editText_View_Numbers = findViewById(R.id.editText_View_Numbers);
        button_init = findViewById(R.id.button_init);
        button_input = findViewById(R.id.button_input);
        button_search = findViewById(R.id.button_search);
        editText_View_Name.setClickable(false);
        editText_View_Numbers.setClickable(false);
        button_init.setOnClickListener(view->{
            sqldb = userDBHelper.getWritableDatabase();
            userDBHelper.onUpgrade(sqldb,1,2);
            Toast.makeText(this, "초기화", Toast.LENGTH_LONG).show();
            sqldb.close();
        });
        button_input.setOnClickListener(view->{
            sqldb = userDBHelper.getWritableDatabase();  // DB 쓰기
            sqldb.execSQL("INSERT INTO GroupTable VALUES ('" + editText_Name.getText().toString()+"',"+ editText_Numbers.getText().toString()+ ");");
            Toast.makeText(this, "입력이 잘 되었습니다.", Toast.LENGTH_LONG).show();
            sqldb.close();
        });
        button_search.setOnClickListener(view->{
            sqldb = userDBHelper.getReadableDatabase();  // DB 읽기
            Cursor cursor = sqldb.rawQuery("SELECT * FROM GroupTable;", null);
            String str_Names = "이름 : \\r\\n ============= \\r\\n";
            String str_Numbers = "인원 : \\r\\n ============= \\r\\n";
            while(cursor.moveToNext()){
                str_Names += cursor.getString(0)+"\\r\\n";
                str_Numbers += cursor.getString(1)+"\\r\\n";
            }
            editText_View_Name.setText(str_Names);
            editText_View_Numbers.setText(str_Numbers);
            cursor.close();
            sqldb.close();
        });
    }

    class UserDBHelper extends SQLiteOpenHelper{

        public UserDBHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version); // 기본적인 생성자 필요함
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL("CREATE TABLE GroupTable(Group_Name CHAR(20) PRIMARY KEY, Group_Number INTEGER);");
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL("DROP TABLE IF EXISTS GroupTable");
            this.onCreate(db);
        }
    }
}

    • 실로폰 앱
      public class MainActivity extends AppCompatActivity {
        
          private SoundPool soundPool;
        
          public MainActivity() {
              this.soundPool = new SoundPool(8, AudioManager.STREAM_MUSIC, 0);
        
          }
        
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              ArrayList<Pair<Integer,Integer>> sounds = new ArrayList<>();
              sounds.add(new Pair<Integer,Integer>(R.id.do1, R.raw.do1));
              sounds.add(new Pair<Integer,Integer>(R.id.do2, R.raw.do2));
              sounds.add(new Pair<Integer,Integer>(R.id.re, R.raw.re));
              sounds.add(new Pair<Integer,Integer>(R.id.mi, R.raw.mi));
              sounds.add(new Pair<Integer,Integer>(R.id.fa, R.raw.fa));
              sounds.add(new Pair<Integer,Integer>(R.id.sol, R.raw.sol));
              sounds.add(new Pair<Integer,Integer>(R.id.la, R.raw.la));
              sounds.add(new Pair<Integer,Integer>(R.id.ti, R.raw.ti));
        
              if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
                  sounds.forEach(this::tune);
              }
          }
          private void tune(Pair<Integer,Integer> pitch){
              Integer soundId = soundPool.load(this, pitch.second, 1);
              this.findViewById(pitch.first).setOnClickListener(view->{
                  soundPool.play(soundId, 1.0f, 1.0f, 0,0,1.0f);
              });
          }
        
          @Override
          protected void onDestroy() {
              super.onDestroy();
              this.soundPool.release();
          }
      }
        
    

태그: ,

카테고리:

업데이트: