이것저것
06 이벤트 처리 본문
안드로이드에는 많은 이벤트가 있습니다. 화면을 터치하면 터치 이벤트가, 키패드를 누르면 키 이벤트가 발생합니다. 터치 이벤트는 복잡하기 때문에 쉽게 처리할 수 있도록 클릭 이벤트가 별도로 존재합니다.
버튼 태그에서 onClick 속성을 추가하면 클릭 이벤트를 처리할 수 있고, xml 파일이 아닌 자바 소스에서 setOnClickLister를 호출하여 리스너를 설정할 수도 있습니다.
이와 같은 이벤트 처리 방식은 화면에서 발생하는 이벤트를 버튼과 같은 위젯 객체에 전달한 후, 그 이후의 처리 과정을 버튼에 위임한다는 뜻이서 Delegation Model 이라고 합니다.
터치 이벤트를 처리해보도록 하겠습니다.
package org.techtown.prac3;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
View view = findViewById(R.id.view);
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
float curX = event.getX();
float curY = event.getY();
if(action==MotionEvent.ACTION_DOWN){
println("Action Down" + curX + ", " + curY);
}
else if(action==MotionEvent.ACTION_MOVE){
println("Action Move" + curX+", "+curY);
}
else if(action == MotionEvent.ACTION_UP){
println("Action Up" + curX + ", " + curY);
}
return true;
}
});
}
public void println(String data){
textView.append(data + "\n");
}
}
위 코드는 다음과 같습니다. 우선 findViewById 메서드를 통해 view를 참조한 후, setOnTouchListener메서드를 호출하여 리스너를 등록합니다. 호출할 때 리스너 객체를 전달하는데 new 키워드를 통해 객체를 생성과 동시에 인자로 전달합니다. 뷰가 터치가 되면 리스너 객체의 onTouch 메서드가 자동으로 호출됩니다.
onTouch 메서드에는 MotionEvent 객체가 파라미터로 전달됩니다. 이 객체에는 액션 정보나 터치한 위치의 좌표 등에 대한 정보가 담겨있습니다.
위 코드를 실행하면 다음과 같은 결과가 나옵니다.

제스처 이벤트는 터치 이벤트 중 스크롤 등을 구별한 후 알려주는 이벤트입니다. 체스처 이벤트를 처리해주는 클래스는 GestureDetector입니다.
위 코드에 제스처 이벤트를 처리하는 코드를 추가하면 다음과 같습니다.
package org.techtown.prac3;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
TextView textView;
GestureDetector detector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
View view = findViewById(R.id.view);
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
float curX = event.getX();
float curY = event.getY();
if(action==MotionEvent.ACTION_DOWN){
println("Action Down" + curX + ", " + curY);
}
else if(action==MotionEvent.ACTION_MOVE){
println("Action Move" + curX+", "+curY);
}
else if(action == MotionEvent.ACTION_UP){
println("Action Up" + curX + ", " + curY);
}
return true;
}
});
detector = new GestureDetector(this, new GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
println("onDown()");
return true;
}
@Override
public void onShowPress(MotionEvent e) {
println("onShowPress()");
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
println("onSingleTapUp()");
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
println("onScroll()");
return true;
}
@Override
public void onLongPress(MotionEvent e) {
println("onLongPress()");
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
println("onFling()");
return false;
}
});
View view2 = findViewById(R.id.view2);
view2.setOnTouchListener(new View.OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event) {
detector.onTouchEvent(event);
return true;
}
});
}
public void println(String data){
textView.append(data + "\n");
}
}
위 코드는 다음과 같습니다.
두번째 뷰 객체를 터치하면 자동으로 onTouch 메서드가 호출됩니다. 이 메서드에서는 detector 객체의 onTouchEvent메스드를 호출하여 GestureDector 객체에 정의된 메서드를 호출하게됩니다.

키 입력은 onKeyDown()메서드를 재정의하여 처리할 수 있습니다.
onKey()메서드는 뷰의 OnKeyListener 인터페이스를 구현할 때 사용됩니다.
위 코드에서 back 버튼을 눌렸을때 화면에 toast 되도록 코드를 작성하면 다음과 같습니다.
public boolean onKeyDown(int keyCode, KeyEvent event){
if(keyCode ==KeyEvent.KEYCODE_BACK){
Toast.makeText(this, "back button pressed", Toast.LENGTH_LONG).show();
return true;
}
return false;
}

안드로이드 프로젝트를 생성하면 res 폴더 안에 layout폴더 하나만 존재하는데 가로, 세로로 화면을 전환할 때마다 다른 화면을 보여주기 위해서는 layout-land라는 폴더를 만들어야 합니다. layout 폴더에 만들어진 xml 파일은 세로 방향을, layout-land 폴더 안에 만들어진 xml 파일은 가로 방향을 나타내는 디스플레이가 됩니다.
디스플레이를 세로에서 가로로 바꾸면, 기존의 액티비티를 메모리에서 없앴다가 다시 만듭니다. 이때 메모리에서 없어지면 기존 액티비티 안에서 선언한 변수 값들이 사라지므로 다시 복원하기 위해서 onSaveInstanceState 콜백 메서드르 사용합니다. 이 메서드는 액티비티가 종료되기 전 상태를 저장합니다.
package org.techtown.sampleorientation;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
String name;
EditText editText;
@Override
protected void onStart() {
super.onStart();
showToast("onStart()");
}
@Override
protected void onStop() {
super.onStop();
showToast("OnStop()");
}
@Override
protected void onDestroy() {
super.onDestroy();
showToast("onDestory()");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showToast("onCreate()");
editText = findViewById(R.id.editText);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
public void onClick(View view){
name = editText.getText().toString();
showToast("saved name");
}
});
if(savedInstanceState!=null){
name = savedInstanceState.getString("name");
showToast("restore name");
}
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("name", name);
}
public void showToast(String data){
Toast.makeText(this, data, Toast.LENGTH_LONG).show();
}
}
위 코드를 설명하면 다음과 같습니다.
name 변수를 선언한 후, editText를 통해 글자를 입력하여 이 변수에 할당합니다. 단말 방향을 바꾸어 액티비티가 소멸되었다가 다시 만들어질때 onSaveinstanceState()메서드 안에서 name 변수의 값을 파라미터로 전달받은 Bundle 객체에 넣어줍니다. 이 객체는 onCreate 메서드가 호출될 때 파라미터로 전달됩니다. 그 이름은 위 코드에서 savedInstanceState라고 되어있으며 여기서 name 변수를 가져오면 데이터가 복구됩니다.


'앱 > 안드로이드' 카테고리의 다른 글
| 08 여러 화면간 전환하기 (2) | 2021.01.17 |
|---|---|
| 07 토스트, 스낵바, 대화상자, 프로그레스바 (0) | 2021.01.13 |
| 05 기본 위젯과 드로어블 (0) | 2021.01.11 |
| 04 상대 레이아웃, 테이블 레이아웃, 프레임 레이아웃, 스크롤 뷰 (1) | 2021.01.08 |
| 03 Linear layout (0) | 2021.01.07 |