본문 바로가기

수업 정리

72일차 수업정리(Android - Timer, Animation, LandScope)

**Hierachy Event Model

    => 제공되는 메소드를 재정의 하는 방식

    => 터치나 키보드 이벤트

    => View, Activity를 상속받아 사용

    => View 클래스를 상속받아서 사용자 정의 뷰를 만들고 터치 이벤트 처리

 

**Overriding

    => 상위 클래스에 존재하는 메소드를 하위 클래스에서 재정의 하는 것

    => 목적은 기능 확장

    => 추상 메소드를 재정의하는 것은 오버라이딩이 아니고 구현

 

    => 프레임워크가 제공하는 메소드를 오버라이딩 하는 경우 상위 클래스 메소드를 호출해야 함

    => 파괴하는 메소드를 제외하고는 상위 클래스의 메소드를 호출하고 필요 기능을 추가

 

**Delegation Model

    => 이벤트 처리를 다른 객체에게 위임하는 방식

    => 상속을 받아 메소드를 재정의 하는 방식은 자주 사용하는 이벤트의 경우 효율적이나 자주 사용하지 않으면 자원 낭비

    => Delegation Model의 이벤트 처리 메소드는 첫번째 매개변수를 이용하여 이벤트가 발생한 객체를 확인 가능

1. 리스너

    - OnTouchListener

    - OnClickListener

    - OnKeyListener

    - OnLongClickListener

    - OnFocusChangeListener

  => 리스너들은 뷰의 내부 인터페이스로 만들어져 있음

  => 대부분 메소드를 1개만 소유하고 있어 람다로 작성 가능

 

2. 이벤트 처리 방법

    => 이벤트를 처리할 객체에서 .set리스너(리스너 객체)를 호출해서 이벤트 처리를 위임

 

3. 리스너 객체 생성

  1) 외부에 인터페이스를 구현한 클래스 생성

    => 이벤트처리하는 클래스를 외부에 별도로 생성하는 것이 권장되지만, 데이터 교환이 어려움

  2) 내부에 인터페이스를 구현한 클래스 생성

    => 내부에 클래스를 만드므로 데이터 교환이 쉬움

    => 별도의 클래스를 만들기 때문에 anonymous나 람다보다 무거워질 가능성이 높음

  3) anonymous나 람다를 이용하여 생성

    => 코드는 간결해지나 이벤트 처리를 많이 하게 되면 가독성이 떨어짐

 

4.View.OnClickListener

    => 클릭했을 때 이벤트 처리를 위한 리스너 인터페이스

    => 처리해야 할 메소드는 public void onClick(View view)

  1) 실행가능한 Activity추가

  2) 레이아웃 파일에 화면 디자인

    => 2개의 버튼 배치

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".EventActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn1"
        android:text="버튼 1"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn2"
        android:text="버튼 2"/>
</LinearLayout>

 

  3) Activity에서 클릭 이벤트 처리

public class EventActivity extends AppCompatActivity {
    String msg = "메시지";

    class EventHandler implements View.OnClickListener{
        public void onClick(View view){
            Toast.makeText(
                    EventActivity.this,
                    msg,
                    Toast.LENGTH_SHORT)
                    .show();
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_event);

        Button btn1 = (Button)findViewById(R.id.btn1);

        btn1.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                Toast.makeText(
                        EventActivity.this,
                        msg,
                        Toast.LENGTH_SHORT)
                        .show();
            }
        });

    }
}

 

**이벤트 라우팅

    => 2개 이상의 객체로 부터 발생한 이벤트를 하나의 이벤트 핸들러를 이용하여 처리

    => 이벤트 라우팅을 하려면 이벤트 발생 객체를 구분할 수 있어야 함

        - 안드로이드의 이벤트 처리 메소드들은 첫번째 매개변수가 이벤트가 발생한 객체

        - 이 매개변수를 이용하여 구분하면 됨

 

**주기적인 화면 갱신

    => GUI 시스템에서는 화면 갱신을 Main Thread에서만 처리 가능

    => 화면 갱신 작업은 모아서 한꺼번에 처리하고 가장 나중에 수행

    => 주기적인 화면 갱신은 Handler를 이용하거나 Timer를 이용해야 함

1. 실행가능한 Activity 1개 추가

 

2. 화면 디자인

    => 텍스트를 출력할 수 있는 TextView 1개와 Button 1개를 세로방향으로 배치

 

3. 버튼을 누르면 1초다마 0~9까지 TextView에 출력하는 코드를 작성

    => Timer에 작성

  1) 인스턴스 변수 선언

    //클래스 안의 여러 메소드에서 사용하기 위해서 인스턴스 변수를 생성
    //이벤트 처리를 할 때 anonymous 나 람다를 이용하면
    //지역변수를 사용할 수 없기 때문에 인스턴스 변수로 선언하기도 합니다.
    Button btn;
    TextView disp; 

  2) onCreate 메소드에 뷰를 찾아오고 이벤트를 처리하는 코드를 추가

//버튼을 클릭했을 때 동작을 정의
btn.setOnClickListener(new Button.OnClickListener(){
    @Override
    public void onClick(View view) {
        try{
            for(int i=0; i<10; i+=1){
                Thread.sleep(1000);
                String msg = String.format("i : %d", i);
                //로그 출력
                Log.e("작업내역 : ", msg);
                disp.setText(msg);
             }
        }catch (Exception e){ }
    }
});

    => 코드는 아무런 문제가 없고 정상적으로 수행되나 화면 갱신만 안됨

        - GUI 시스템 에서는 주기적인 화면 갱신을 일반코드로는 불가능

        - 화면 출력은 모아서 한꺼번에 가장 나중에 수행하기 때문

 

**Timer

    => 일정한 주기를 가지고 작업을 수행하는 클래스 - 스레드로 구현

    => 클래스는 CountDownTimer

    => onTick이라는 메소드에 주기적으로 수행할 내용을 작성

    => 인스턴스를 생성할 때는 2개의 매개변수를 대입하여 생성, 첫번째 매개변수는 전체 수행시간, 두번째 매개변수는 주기

    => 타이머 시작은 start()를 호출하면 되고 중지는 cancel()

    => 클릭 메소드 수정

@Override
public void onClick(View view) {
	CountDownTimer timer = new CountDownTimer(100000, 1000) {
    	int value = 0;
    	@Override
    	public void onTick(long l) {
    		String msg = String.format("value : %d", value++);
    	    disp.setText(msg);
   		}

    	@Override
    	public void onFinish() {

    	}
    };
timer.start();

**Timer를 이용해 이미지 변경

1. 필요한 이미지를 drawable 디렉토리에 복사

    => image1.jpg, image2.jpg

 

**안드로이드의 리소스

    => 안드로이드는 자원을 res 디렉토리에 저장

    => 실행시 자원을 전부 메모리에 로드하여 사용

    => raw 디렉토리에 저장된 데이터는 로드하지 않고 사용할 때 로드

    => 리소스 중에서도 크기가 큰 리소스는 res 디렉토리에 저장하지 않고 assets디렉토리에서 관리

1. drawable : 이미지, 이미지와 관련된 XML, 그림을 표현한 XML

2. layout : 화면 UI를 정의한 레이아웃 XML

3. values : 문자열, 색상, 크기, 배열 및 스타일등의 XML

4. menu : 메뉴

5. xml

6. anim : 애니메이션 XML

7. mipmap : 앱의 아이콘

8. raw : 이진파일 - html이나 사운드 파일

 

    => 안드로이드는 리소스를 res 디렉토리에 저장하면 R.java 파일에 static final int 형태로 확장자 없이 정수로 생성

        - 종류가 다르더라도 이름이 같으면 문제가 발생할 소지가 있음

        - 자원별로 클래스를 제작, 저장하므로 종류가 다르면 상관없으나 raw의 경우 한 클래스를 사용하므로,  확장자만 다를경우 에러 발생

    => 리소스명은 소문자와 숫자만으로 생성하는 것을 권장

 

**Animation

1. Twin Animation

    => 시작값과 종료값을 가지고 상태를 지정하여 수학적 계산의 의해 애니메이션을 만들어 내는 것

    => TranslateAnimation, ScaleAnimation, RotateAnimation, AlphaAnimation, AnimationSet을 이용하여 작성

    => 애니메이션 작성은 xml을 이용하는 경우가 많음

    => xml을 애니메이션으로 만들기

        - Animation 변수명 = AnimationUtils.loadAnimation(Context context, int resId);

          뷰 객체.startAnimation(변수명)

    => 애니메이션 관련 속성

        - duration, fillAfter(애니메이션 종료후 마지막 상태 유지 여부 - 기본은 false)

        - fillBefore(애니메이션 시작시 상태 - 기본은 true)

        - repeatCount(0은 반복X, 1 -> 2, INFINITY -> 무한대)

        - repeatMode(반복시의 동작으로 REVERSE를 설정시 반대되는 애니메이션 재생)

        - startOffset(시작전에 대기시간)

        - interpolator(애니메이션 진행 속도 변환)

        - detachWallpaper : 배경은 애니메이션 되지 않도록 설정

        - zAdjustment : 뷰가 겹쳤을 때 Z-index

  1) 출력할 이미지를 drawable 디렉토리에 복사

 

  2) res 디렉토리에 애니메이션을 위한 anim 디렉토리를 생성

 

  3) anim 디렉토리에 rotate.xml 파일을 생성하고 회전 애니메이션 작성

<?xml version="1.0" encoding="utf-8"?>
<rotate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%"
    android:duration="5000"/>

 

  4) 실행가능한 Activity 생성(AnimationActivity)

 

  5) 레이아웃 수정

    => 버튼 1개, 이미지뷰 1개 작성

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".AnimationActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="애니메이션 시작"
        android:id="@+id/animationbtn"/>

    <ImageView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:src="@drawable/image1"
        android:id="@+id/imageview"/>
</LinearLayout>

 

  6) Activity.java 파일의 onCreate에 작성

public class AnimationActivity extends AppCompatActivity {

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

        final ImageView imageView = (ImageView)findViewById(R.id.imageview);
        Button button = (Button)findViewById(R.id.animationbtn);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Animation rotate = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.rotate);
                imageView.startAnimation(rotate);
            }
        });
    }
}

 

2. AnimationListener

    => Animation도 화면 변경하는 작업이므로 애니메이션 종료후, 어떤 동작 을 수행시키려면 리스너의 콜백 메소드를 이용해야 함

    => 애니메이션 시작 전, 종료 후, 반복될 때 호출 되는 메소드를 소유

    => 애니메이션 객체.setAnimationListener(AnimationListener listener);

 

3. 기타 리소스

    => values 디렉토리에 만드는 리소스

  1) strings.xml : 문자열 리소스

  2) colors.xml

  3) style.xml : 스타일 리소스 - 글자모양 등

  4) arrays.xml : 문자열 배열

  5) dimens.xml : 크기

 

**스마트폰 크기 호환성

    => 아이콘이나 이미지는 스마트 폰의 해상도에 따라 적절한 파일을 제공해주는 것이 필요

    => minmap이나 drawable 디렉토리를 만들 때 -mdpi, -hdpi, -xdpi, -xxdpi, -xxxdpi등을 추가하여 만들면 됨

    => 지역 코드를 붙일 수 있음

        - en(영어), en_US(미국에서 사용하는 영어)..

    => 방향을 지정할 수 있음

        - port(수직), land(수평)

    => 스마트폰 크기 가져오기

        - DisplayMetrics ? = new DisplayMetrics();

        - getWindowManager().getDefaultDisplay().getMetrics(?);

        - ?에 크기가 저장됨

    => 단위

        - 절대 단위 : 크기가 고정 - pt, px, mm, in

        - 상대 단위 : 크기가 가변 - dp(dip), sp(sip)

        - 인쇄시에는 절대단위를 사용하는 것이 좋고, 화면 출력시는 상대 단위가 좋음

   1)Strings.xml 파일에 문자열을 정의

<string name="btndisplay">Animation Start</string>

 

  2) res 디렉토리에 values-ko 디렉토리를 생성

 

  3) values-ko 디렉토리에 strings.xml파일을 만들고 작성

<string name="btndisplay">애니메이션 시작</string>

 

  4) 레이아웃 파일에서 버튼의 텍스트를 수정

android:text="@string/btndisplay"

 

**회전 처리

   => 스마트 폰은 가로보기와 세로보기 모드가 존재

    => 안드로이드는 단말의 방향이 변경되면 Activity를 메모리에서 제거후 새로 제작

    => Activity에서 회전을 지원하고자하면 androidmanifest.xml파일에서 Activity를 등록 시 옵션 추가

       (android:configChanges = "orientationkeyboardHidden|screenSize" 추가)

        - Android:screenOrientation="portrait 나 landscape"를 설정하면 고정

    => 발향 전환이 발생하면 호출되는 메소드

        - Activity 클래스의 onConfigurationChanged(Configuration newConfig) 호출후 매개변수의 orientation 속성 확인

         (기기 방향을 알수 있음)

    => 방향에 따라 다른 레이아웃을 출력하고자 하면 layout-land 디렉토리를 만들고 layout을 생성하면 됨

        - 위처럼 제작하면 회전 발생시 setContentView 메소드를 호출해 주어야 함

    => 이전 상태를 보관하고 차후 실행시 이전의 상태를 보존하고자하면, onSaveInstanceState 메소드를 재정의 하여 상태를 저장

        - onCreate에서 이전 상태를 복원 해줌

1. 회전이 발생시 토스트 출력

  1) androidmanifest.xml 파일 수정

<activity android:name=".AnimationActivity"
    android:configChanges="orientation|keyboardHidden|screenSize">
    <intent-filter>
         <action android:name="android.intent.action.MAIN" />

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

 

2. AnimationActivity.java 파일에 회전이 발생하면 호출되는 메소드를 재정의