[Android(Java)] 안드로이드 java 기초
카테고리: Android(Java)
1. 매칭하기
자바 코드에서 View를 제어하기 위해서는 해당 뷰와 변수(객체)와의 매칭이 필요하다.
다양한 방법이 있지만 대표적으로 뷰의 id속성 값을 이용하여 매칭을 하는
findViewById() 방식이 있다.
TextView tv_1 = (TextView) findViewById(R.id.tv_1);
Button btn_1 = (Button) findViewById(R.id.btn_1);
해당 방식의 순서는 이러하다.
- Activity의 onCreate() 함수 실행
- setContentView() 함수를 통해 클래스와 레이아웃을 매칭
- findViewById()함수를 통해 매칭된 레이아웃 내에서 해당 id를 가지는 View를 매칭
onCreate()함수는 Activity의 생명 주기에 대하여 설명이 필요하므로 후에 설명하겠음
2. 제어하기
2.1. 텍스트 변경
2.1.1. void setText()
TextView 클래스에 속하는 함수로 TextView를 상속받는 모든 클래스(ex : Button, EditText 등)에서 사용이 가능하다. 문자열을 입력받아 해당 View의 텍스트를 변경할 수 있으며 String 리소스 값을 전달 받아 텍스트 변경이 가능하며 문자 배열 (char [ ]) 과 시작점의 인덱스와 길이를 함께 입력하여 변경하는 방법도있다.
tv_1.setText("안녕하세요"); //TextView의 텍스트가 "안녕하세요"로 변경된다.
tv_1.setText(R.string.hello);
// TextView의 텍스트가 hello라는 이름을 가진 String 리소스 값으로 변경된다.
char[] hello = new char[]{'안','녕','하','세','요','!'};
tv_1.setText(hello,0,2);
// TextView의 텍스트가 "안녕"으로 변경된다.
2.1.2. void append()
TextView 클래스에 속하는 함수로 TextView를 상속받는 모든 클래스(ex : Button, EditText 등)에서 사용이 가능하다. 인자로 입력받은 문자열을 기존의 텍스트에 추가하는 함수이며 문자열과 함께 시작지점과 끝지점의 인덱스를 함께 입력하여 부분 문자열을 부분문자열을 추가하는 것도 가능하다.
tv_1.setText(""); //TextView의 텍스트가 빈칸으로 변경된다.
tv_1.append("안녕하세요");//TextView의 텍스트가 "안녕하세요"가 된다
tv_1.append("반가워요",0,3);//TextView의 텍스트가 "안녕하세요반가워"가 된다.
2.1.3. CharSequence getText()
TextView 클래스에 속하는 함수로 TextView를 상속받는 모든 클래스(ex : Button, EditText 등)에서 사용이 가능하다. 해당 View의 텍스트를 CharSequence 형식으로 반환하기 때문에 String으로 사용할 경우 toString()함수를 이용해 형식을 변형해주어야 한다. 주로 EditText로 입력받은 문자열을 불러올때 사용된다.
String text = tv_1.getText().toString(); //text에 "안녕하세요반가워"가 저장된다.
2.2. 이벤트 처리
2.2.1. 클릭 이벤트
버튼을 클릭했을때 특정한 액션을 취하는 가장 단순하면서도 많이 쓰이는 이벤트처리이며
클릭 이벤트를 처리하는 방법은 매우 많으나 크게 3가지 정도의 방법을 알려주고자 한다.
- onClick 속성 지정
우선 첫 번째 방법은 public 함수를 만들어 View의 onClick 속성으로 지정하는 방법이다.
이러한 public 함수를 만든다.
public void onClick_test(View view){
// action
}
그리고 나서 layout파일에서 이벤트를 원하는 View의 onClick속성으로 해당함수를 지정한다.
<Button
android:id="@+id/btn_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
android:onClick="onClick_test"/>
이러한 방법은 간단하고 적용하기도 쉽지만 코드가 길어지거나 layout에 View가 많아지면 일일이 지정하기도 힘들고 코드가 복잡해지면 어떤 View에 적용한 이벤트인지 알아보기 힘들기 때문에
추천하지는 않는다.
- OnClickListener 사용
OnClickListener라는 이벤트 리스너를 사용하는 방법으로 가장 많이 사용되는 방법이라 할 수 있다. 해당 리스너를 사용하는 방법도 다양하며 해당 리스너를 implements한 내부 클래스를 만들어 사용하거나. 익명 클래스를 만들어 사용 또는 Activity 자체에 해당 리스너를 implements하여 사용할 수 있다.
예시1)
class MyOnClickListener implements View.OnClickListener {
@Override
public void onClick(View view) {
//action
}
}
위와 같은 내부 클래스(inner class)를 생성하여 버튼에 지정한다.
Button btn_2 = (Button) findViewById(R.id.btn_2);
btn_2.setOnClickListener(new MyOnClickListener());
예시2)
또는 다음과 같은 익명클래스(anonymous class)를 이용한다.
btn_3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//action
}
});
이 방법의 경우 버튼마다 다른 이벤트를 적용하기도 좋고 가독성도 뛰어나 많이 사용되는 방법이다. 하지만 이 방법 역시 버튼의 개수가 엄청나게 많을 경우 일일이 익명 클래스를 만들어주어야 하는 단점이 있다.
이 경우 익명클래스를 미리 만들어두고 해당 클래스를 적용시키는 방법이 있다.
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View view) {
switch(view.getId()){
case R.id.btn_1:
// btn_1 action
break;
case R.id.btn_2:
// btn_2 action
break;
case R.id.btn_3:
// btn_3 action
break;
case R.id.btn_4:
// btn_4 action
break;
}
}
};
btn_1.setOnClickListener(listener);
btn_2.setOnClickListener(listener);
btn_3.setOnClickListener(listener);
btn_4.setOnClickListener(listener);
예시3)
해당 Activity에 OnClickListener를 바로 implements하는 방법으로 Activity가 하나의 OnClickListener가 되었으므로 this를 이용해 지정할 수 있다. 내부클래스 또는 익명클래스를 만들기 귀찮을 때 추천하는 방법이다.
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn_1 = (Button) findViewById(R.id.btn_1);
Button btn_2 = (Button) findViewById(R.id.btn_2);
Button btn_3 = (Button) findViewById(R.id.btn_3);
Button btn_4 = (Button) findViewById(R.id.btn_4);
btn_1.setOnClickListener(this);
btn_2.setOnClickListener(this);
btn_3.setOnClickListener(this);
btn_4.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch(view.getId()){
case R.id.btn_1:
// btn_1 action
break;
case R.id.btn_2:
// btn_2 action
break;
case R.id.btn_3:
// btn_3 action
break;
case R.id.btn_4:
// btn_4 action
break;
}
}
}
}
build.gradle을 이용해 자바버전을 업그레이드 하면 lambda를 이용하여 좀더 간단한 형태로 바꿀 수 있다.(최신 버전의 Android studio 에서는 프로젝트 생성시 자동으로 업그레이드가 된다.)
btn_4.setOnClickListener(view -> {
//action
});
2.2.2. 터치 이벤트
View를 터치 했을때 일어나는 이벤트로 클릭이벤트와 별반 다를거 없어 보이지만 클릭이벤트보다 좀더 섬세한 이벤트 처리를 가능하게 한다. 클릭이벤트의 이벤트 인식은 클릭을 했다가 손을 떼었을때 한 순간만을 인식하지만 터치 이벤트는 사용자가 손가락을 화면에 대거나, 화면에서 떼거나, 화면에 닿은채로 움직일때 모두를 처리할 수 있다.
터치 이벤트의 처리는 크게 두가지 방법이 있다. 그 방법은 다음과 같다.
- View의 OnTouchEvent() 오버라이딩
- OnTouchListener 사용
이에 대한 설명은 다음에 지금은 잠온다.
3. 화면 전환
다양한 기능을 가진 어플을 만들다 보면 하나의 화면으로는 부족한 경우가 대부분이다.
그래서 다른 화면으로 전환을 해줄 필요가 있다. 다른 화면으로 전환을 하는 방법은 크게 Activity를 전환하는 방법과 fragment를 이용하는 방법이 있다.
3.1. Activity 전환
Activity 전환을 잘 활용하기 위해서는 Activity 생명주기를 이해할 필요가 있는데 그것에 대한 내용은 다음 포스트를 참고하길 바란다.
Activity를 전환하는 대표적인 방법은 Intent를 통한 Activity 전환방법이 있다.
Intent란 Activity간에 서로를 호출하기 위한 통신장치로 다른 Activity를 부르는 호출기를 생성하여 호출기를 누르는 것으로 다른 Activity를 불러낸다고 생각을 하면 쉬울 것이다.
코드를 통해 확인해 보자
//다른 액티비티를 불러낼 호출기를 생성한다.
Intent intent = new Intent(MainActivity.this, NextActivity.class);
//호출기를 눌러 액티비티를 불러낸다.
startActivity(intent);
//기존 액티비티를 종료한다.(선택)
//finish();
3.2. Fragment 전환
Fragment의 생명주기에 대한 내용 역시 다음 포스트에서 다루도록 하겠다.
Fragment를 전환하는 가장 간단한 방법으로는 Fragment Transaction을 사용하는 방법이 있다.
3.2.1. Fragment Transaction
우선 다음과 같은 Fragment의 view가 들어갈 layout을 만들어 준다.
<FrameLayout
android:id="@+id/fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
File > new > Fragment 를 이용해 사용할 Fragment를 만든다.
본 예제에서는 총 3개의 Fragment를 만들어 보았다.
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_1, container, false);
return view;
}
}
우선 Activity에서 Fragment Manager을 생성한다.
FragmentManager fm = getSupportFragmentManager();
생성한 Fragment Manager을 이용해 Fragment Transaction을 생성한다.
FragmentTransaction ft = fm.beginTransaction();
replace() 메서드를 호출하여 원하는 프레그먼트로 View를 전환한다.
ft.replace(R.id.fragment,new Fragment1());
//(fragment가 들어갈 layout의 id, 들어갈 프레그먼트)
/*
Fragment1 frag_1 = new Fragment1();
ft.replace(R.id.fragment,frag_1);
*/
원하는 작업이 완료되었다면 commit() 메서드를 호출하여 적용시킨다.
replace() 메서드는 commit을 해야 적용이되므로 마지막에 꼭 commit을 한다. 한번 commit한 Fragment Transaction은 다른 작업을 더이상 할 수 없으므로 다시 사용할 경우 새로 생성해주어야 한다.
ft.commit();
응용
public class FragmentActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.btn_1:
setFragment(1);
break;
case R.id.btn_2:
setFragment(2);
break;
case R.id.btn_3:
setFragment(3);
break;
}
}
};
Button btn_1 = findViewById(R.id.btn_1);
Button btn_2 = findViewById(R.id.btn_2);
Button btn_3 = findViewById(R.id.btn_3);
btn_1.setOnClickListener(clickListener);
btn_2.setOnClickListener(clickListener);
btn_3.setOnClickListener(clickListener);
setFragment(1);
}
private void setFragment(int num){
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
switch (num){
case 1:
ft.replace(R.id.fragment,new Fragment1());
break;
case 2:
ft.replace(R.id.fragment,new Fragment2());
break;
case 3:
ft.replace(R.id.fragment,new Fragment3());
break;
}
ft.commit();
}
}
3.2.2. add() vs replace()
4. ListView 구현
4.1. 기본 구현
안드로이드에서 기본적으로 제공하는 문자열을 출력하는 ListView를 구현해보자.
ListView를 구현하기 위해서는 다음의 세 가지가 필요하다.
- 출력할 데이터들이 담겨있는 Data set
- 데이터를 출력할 ListView
- ListView에게 적절한 레이아웃과 데이터를 매칭시켜줄 Adapter
4.1.1. Data set 준비하기
출력해주고 싶은 데이터가 담겨질 Data set을 만들어야 한다.
형식은 배열로도 만들 수 있지만 동적으로 ListView를 활용하기 위해서는
List 또는 ArrayList를 사용할 것을 권장한다.
List<String> list = new ArrayList<>();
//ArrayList<String> list = new ArrayList<>();
//String[] list = new String[list_size];
list.add("hello");
4.1.2. Adapter 만들기
Adapter는 Data set의 데이터를 적절한 레이아웃의 View와 매칭시켜 ListView에게 전달해주는 역할을하는 객체로 안드로이드에서 문자열 출력을 도와주는 기본적인 ArrayAdapter가 존재한다.
ArrayAdapter는 해당 액티비티의 Context, 레이아웃, Data set을 받아 생성한다.
기본 제공 레이아웃인 simple_list_item_1을 사용해보자
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1,list);
4.1.3. ListView 생성 및 Adapter 적용
ListView를 선언하고 View를 매칭한뒤 Adapter를 적용하는 것으로 기본적인 문자열을 아이템으로 출력하는 ListView의 구현을 완성할 수 있다.
ListView lv_1 = findViewById(R.id.lv_1);
lv_1.setAdapter(adapter);
4.1.4. 업데이트
동적으로 ListView를 활용하기 위해서는 Data set이 변경되었을 경우 ListView가 업데이트가 되도록해야한다. 그러기 위해서는 Adapter에게 데이터 변화를 알려 Adapter가 ListView를 새로 그리도록하는 작업이 필요하다.
//리스트 ["hello"]
list.add("example");//리스트 ["hello","example"]
list.add("JJSH"); //리스트 ["hello","example","JJSH"]
list.remove(0); //리스트 ["example","JJSH"]
adapter.notifyDataSetChanged(); //Adapter에게 Data set이 변경됨을 알림
4.2. Custom
문자열만 출력되는 ListView로는 원하는 것을 다 표현하기는 힘들다. 이러한 문제를 해결하고 ListView의 아이템들의 디자인을 변경하기 위해서는 Adapter와 레이아웃을 직접 만들어 주어야 하는데 이런식으로 구현되는 ListView를 Custom ListView라고 한다.
4.2.1. Data set 준비하기
우선은 원하는 데이터의 형식을 정의한 클래스를 생성한다. 예시로 제목과 본문 그리고 정수형 숫자를 하나 가지고 있는 List_Item 이라는 클래스를 생성하고 생성자와 각 필드를 불러올 get메서드를 작성해 보았다.
public class List_Item {
private String title;
private String body;
private int num;
public List_Item(String title, String body, int num) {
this.title = title;
this.body = body;
this.num = num;
}
public String getTitle() {
return title;
}
public String getBody() {
return body;
}
public int getNum() {
return num;
}
}
앞서 만든 List_Item으로 List를 만들고 반복문을 이용하여 샘플 Data set을 만든다.
List<List_Item> list =new ArrayList<>();
for(inti = 0; i < 20; i++){
list.add(new List_Item("title"+i,"body"+i,i));
}
4.2.2. Layout 만들기
Custom ListView를 구현하기 위해서는 Custom 디자인의 Layout이 필요하다.
res > layout 폴더에 새로운 Layout 리소스 파일을 생성한다.
List_Item의 속성 값들을 출력할 수 있는 구조로 Layout을 구성해보자
(사진 생략)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="title"/>
<TextView
android:id="@+id/body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_weight="1"
android:text="body"/>
<TextView
android:id="@+id/num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="30dp"
android:text="0"/>
</LinearLayout>
4.2.3. Adapter 만들기
이제 Custom ListView의 핵심이라고 할 수 있는 Custom Adapter를 만들어보자
BaseAdapter를 상속받아 해당 클래스의 추상 함수를 오버라이딩한다.
Activity의 Context와 List를 받는 생성자를 만들고 각 함수의 반환값을 알맞은 값으로 설정한다.
가장 핵심이 되는 함수는 getView 함수로 inflate()
함수를 이용해 앞서 만들었던 Layout을 불러오고 각 View를 매칭시켜 값을 넣어준다.
public class MyListAdapter extends BaseAdapter {
private Context context;
private List<List_Item> list;
public MyListAdapter(Context context, List<List_Item> list){
this.context = context;
this.list = list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int index) {
return list.get(index);
}
@Override
public long getItemId(int index) {
return index;
}
@Override
public View getView(int index, View view, ViewGroup viewGroup) {
View v = View.inflate(context, R.layout.list_item, null);
TextView title = v.findViewById(R.id.title);
TextView body = v.findViewById(R.id.body);
TextView num = v.findViewById(R.id.num);
title.setText(list.get(index).getTitle());
body.setText(list.get(index).getBody());
num.setText(String.valueOf(list.get(index).getNum()));
return v;
}
}
이제 모든 준비가 다 되었으므로 Activity로 돌아가 ListView를 구현해보자
4.2.4. ListView 구현
해당 과정은 ArrayAdapter를 이용한 ListView 구현과 거의 동일하다.
Custom Adapter를 생성하여 ListView에 적용시킨다.
MyListAdapter adapter = new MyListAdapter(this,list);
ListView lv_1 = findViewById(R.id.lv_1);
lv_1.setAdapter(adapter);
**실행 화면**
(생략)
Reference
none