118일차(1)/Android App(75) : Wearable App 예제(2), 기기 페어링
- 가상기기 삭제하고 새로 만들기
- 가상기기 삭제하기 (옵션-delete)
- Phone에서 새 가상기기를 생성하려고 보면 플레이스토어 표시가 있는데, 가상기기에 구글 플레이스토어가 포함되어있는지 여부를 말한다.
- 가상기기에서도 구글 계정으로 로그인해서 플레이스토어 앱을 받을 수 있다!
- 이 표시가 있어야 웨어러블 앱을 가상기기에서도 연동하여 테스트해볼 수 있다.
- Phone 가상기기 생성. R 선택해서 다운로드 받고 next-next-finish
- 다음은 wear OS- small round로 생성
- China ver.이 아닌 R 버전으로 생성. next-finish
- 이렇게 가상기기 두개를 만들어둔다.(Wearable 앱을 페어링해서 활용하기 위한 것)
- 구동이 오래 걸리므로 앱을 만들기 전에 미리 가상기기를 Run 시켜서 시작해두기
- Phone 가상기기의 구글 플레이스토어에 구글계정으로 로그인하기
- 구글계정으로 로그인하면 실제 기기를 사용하는 것처럼 플레이스토어를 사용할 수 있다.
- 이 Phone 기기 안에 wear os 앱을 설치해야 한다.
- 구글 플레이스토어에서 wear os 검색!
- Wear OS by Google 앱을 install 해두기
- 위 아이콘의 1,2번은 시계의 물리 버튼을 말한다.
- 각각 물리버튼 1,2 / 손바닥으로 화면을 덮을 때 / 시계를 기울이는 동작 을 가리킨다.
- 현재 1번 물리버튼은 최근에 사용했던 앱 목록이다.
- 2번 물리버튼은 설치된 어플리케이션 보기
- 손으로 덮으면 화면이 꺼지게 되어있다.
- 추가 컨트롤을 하고 싶다면 Emulator 창의 Extended control 버튼 클릭
- 새 창이 뜨고, 센서값 등을 조정할 수 있다.
- 설치되어 있는 앱을 띄워놓고 테스트할 수 있다.
- Rotary Input (회전) 탭에서 시계 옆에 있는 파란 원을 돌려서 회전시킬 수 있다.(시계 화면에서 스크롤하는 효과)
- 설정에 있는 기능 살펴보기
- 설정-디스플레이-Change watch face
- 기본화면 배치 레이아웃을 수정할 수 있다. 우측으로 넘겨서 Add new 하면 새로 만들 수도 있다.
* Wear OS와 Phone 기기 페어링하기
- 디바이스 매니저의 메뉴에서 Pair Wearable 클릭
- 페어링이 가능한 Phone 기기가 나타난다.
- 이런 오류창이떴는데 Phone 기기의 구글 플레이스토어가 업데이트되지 않아서였다.
- 업데이트를 완료하고 Restart pairing 하니 정상적으로 구동됨!
- 우상단 pair with emulater를 클릭해서 연결할 수도 있다.
- 페어링이 완료된 창!
- 시계에서 사용할 구글계정을 선택하고 로그인해주면 된다.
- 가상기기를 실기기와 페어링할 수도 있다.
- 페어링이 진행되고 있는 모습
- 싱크(동기화)가 되었다면 전화번호 목록도 볼 수 있다.
- 완료된 화면!
- 이런 창이 나타난다.
- 이전 예제 코드 리뷰
- 데이터를 아답타에 넣어주고, 아답타에 View를 연결한 구조이다.
- 이 프로젝트를 wear os에넣고 run 시켜보려고 한다!
- 오버라이드한 3개의 메소드
- ViewHolder에서 뷰를 최소한의 갯수만 만들어서 리턴한다.
- 목록이 아무리 많아도 최대 3개만 만들어서 돌려가면서 쓰는 것이다(재활용한다)
- 그래서 recyclerView이다!!
- 내용을 바꾸어주는 부분. 뷰는 그대로 두고, 내용을 바꾸는 메소드
- 포지션 값을 전달하면 텍스트뷰의 내용만 바꾸어준다.
- 레이아웃을 전개해서 ViewHolder 의 생성자에 넣어주기
- ViewHolder 안에서는 뷰 안에 있는 텍스트뷰를 필드로 가지고있고
가져가고 싶으면 getTextView로 가져가면 된다.
- getTextView로 모델의 데이터를 출력하는 구조이다.
- 클릭하면 어떤 동작을 하도록 만들고 싶다면?
- 크기를 확인하기 위해 cell의 리니어레이아웃 안에서 색상을 부여했다.
- 리니어 레이아웃의 크기가 이렇게 잡히는 것을 볼 수 있다!
- 각각의 레이아웃이 하나의 View가 되어 회전할 때마다 교체되는 것이다.
- LinearLayout 안에 텍스트뷰가 있는 구조
- gravity로 가운데정렬 시키기
- 아이템을 클릭했을때 어떤 동작을 하고 싶다면?
- 클릭리스너를 TextView에 달아야 한다.
- 이런 사각형 형태의 View가 리스트로 되어있는 것
- textView에 onclickListener를 추가한다.
- 클릭하면 이 안으로 실행순서가 들어오고, position값이 들어온다. 어떤 포지션(몇번째 목록)을 클릭했는지를 알 수 있다.
Log.d("Clicked!!", "position"+position);
- 이렇게 로그를 넣어두고 run 해보면 클릭한 position 값이 로그로 출력된다.
- 이런 작업들, 리스너에서 읽어온 것은 모두 아답타 안에서 일어나는 일이다.
=> 이것을 MainActivity로 전달하고 싶다면?
- 새 모듈 생성
step26listview2
MemberDto 클래스 생성
package com.example.step26listview2;
public class MemberDto {
private int num;
private String name;
private String addr;
public MemberDto(){}
public MemberDto(int num, String name, String addr) {
this.num = num;
this.name = name;
this.addr = addr;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
}
MemberAdapter
package com.example.step26listview2;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class MemberAdapter extends RecyclerView.Adapter<MemberAdapter.ViewHolder> {
private List<MemberDto> members;
private ItemClickListener listener;
//아답타 안에서 일어나는 특정 이벤트를 전달받을 객체 type을 미리 정의하기
public interface ItemClickListener{
public void clicked(int index);
}
//생성자
public MemberAdapter(List<MemberDto> members){
this.members=members;
}
public void setOnItemClickListener(ItemClickListener listener){
this.listener=listener;
};
@NonNull
@Override
public MemberAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//cell.xml 문서를 전개해서 View 객체를 얻어낸다.
View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.cell, parent, false);
//ViewHolder 객체를 생성해서 리턴해준다.
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MemberAdapter.ViewHolder holder, int position) {
//position에 해당하는 TextView의 참조값
TextView textView=holder.getTextView();
//TextView에 회원의 이름 출력하기
textView.setText(members.get(position).getName());
//TextView 에 클릭 리스너 등록
textView.setOnClickListener(v -> {
//ItemClickListener (여기에서는 MainActivity가 된다.) 에 정보를 전달한다.
if(listener != null) {
listener.clicked(position);
}
});
}
@Override
public int getItemCount() {
return members.size();
}
//ViewHolder를 내부 클래스로 정의한다.
public static class ViewHolder extends RecyclerView.ViewHolder{
//필드
private TextView textView;
//생성자
public ViewHolder(@NonNull View itemView) {
super(itemView);
//TextView의 참조값을 얻어내서 필드에 저장
textView=itemView.findViewById(R.id.textView);
}
//TextView getter 메소드
public TextView getTextView(){
return textView;
}
}
}
- RecyclerView.Adapter 를 상속받아서 만들기. 추상메소드도 오버라이드
- ViewHolder를 내부클래스로 정의했다.
- 필드 선언, 생성자 만들어주기
- 목록을 생성자의 인자로 전달받아서 필드에 저장
- 인터페이스 ItemClickListener 정의하기
- 이벤트를 전달받을 때 이 객체를 사용하면 된다.
- ItemClickListener 타입을 커스텀으로 정의했다.
- 리스너 인터페이스의 참조값을 여기에 넣어주려고 한다.
- MainActivity 에서 사용하려면 일단 인터페이스 구현
- 이 안에서 아답타의 참조값에 점찍어서 setOnItemClickListener 로 사용
- 그 값을 필드에 넣어놓고 필요할때 사용하겠다는 뜻
- 새 레이아웃 리소스 파일 생성
cell.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textView"
android:textAlignment="center"
android:textSize="20sp"/>
</LinearLayout>
- TextView를 하나 만들어준다.
- onCreateViewHolder 메소드에서 객체를 얻어내고,
view객체로 viewholder 객체를 생성해서 리턴해준다. 아래에서 사용할 수 있도록!
- 여기서 생성한 참조값이 위 메소드에 전달되고, index도 함께 전달된다.
- 상속받은 Adapter에 제너릭<> 을 설정해야 한다.
- 우리가 직접 만든 ViewHolder를 사용할것
MemberAdapter.ViewHolder
- 메소드에 타입을 이렇게 적어주어야 한다.
- 위 clicked 메소드는 인덱스만 전달하는 것으로 수정...
- 클릭했을 때 null일 경우를 방지해야 한다.(position값이 들어오지 않는 경우)
- 이 position값으로 이벤트를 처리해준다.
- 이제 이 MemberAdapter.ItemClickListener를 Activity에서 구현하면 가져다가 사용할 수 있다.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.wear.widget.BoxInsetLayout 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:padding="@dimen/box_inset_layout_padding"
tools:context=".MainActivity"
tools:deviceIds="wear">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/inner_frame_layout_padding"
app:layout_boxedEdges="all">
<androidx.wear.widget.WearableRecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recyView"
android:scrollbars="vertical"/>
</FrameLayout>
</androidx.wear.widget.BoxInsetLayout>
- WearableRecycleView 를 FrameLayout 안에 추가해주기
MainActivity
package com.example.step26listview2;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import androidx.wear.widget.WearableLinearLayoutManager;
import androidx.wear.widget.WearableRecyclerView;
import com.example.step26listview2.databinding.ActivityMainBinding;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends Activity implements MemberAdapter.ItemClickListener{
private TextView mTextView;
private ActivityMainBinding binding;
MemberAdapter adapter;
List<MemberDto> members;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
//Sample Model
members=new ArrayList<>();
members.add(new MemberDto(1, "바나나", "서울"));
members.add(new MemberDto(2, "딸기", "부산"));
members.add(new MemberDto(3, "복숭아", "대전"));
members.add(new MemberDto(4, "사과", "서울"));
members.add(new MemberDto(5, "오렌지", "서울"));
WearableRecyclerView recyclerView=binding.recyView;
recyclerView.setHasFixedSize(true);
recyclerView.setEdgeItemsCenteringEnabled(true);
recyclerView.setLayoutManager(new WearableLinearLayoutManager(this));
//아답타 연결
adapter=new MemberAdapter(members);
//RecyclerView에 연결
recyclerView.setAdapter(adapter);
adapter.setOnItemClickListener(this);
}
@Override
public void clicked(int index) {
//Model을 변경하고
members.get(index).setName(index+" clicked!");
//Adapter에 Model이 변경되었다고 알린다.
adapter.notifyDataSetChanged();
}
}
- 샘플 모델을 추가하고, 아답타를 연결해준다.
- 우리가 아답타에서 정의한 인터페이스를 직접 구현한다.
- 메소드가 오버라이드된다. index 값이 전달된다.
- adapter, members 2개의 값을 필드로 만들어준다.
adapter.notifyDataSetChanged()
- clicked 메소드 안에서 아답타 출력 작업을 해주면 완료...!
- 특정 아이템을 클릭하면 index 번호+clicked! 로 바뀐다.
- Wear OS 기기에서 확인해보면, 우리가 만든 앱도 이렇게 앱 목록에 들어가 있는 것을 볼 수 있다.
'국비교육(22-23)' 카테고리의 다른 글
119일차(1)/Android App(76) : apk 파일 생성, 수동으로 구동시키기 (0) | 2023.03.31 |
---|---|
117일차(2)/Android App(74) : Wearable App 예제(1) (0) | 2023.03.29 |
117일차(1)/CSS(16) : CSS3 Flex 활용(4) (0) | 2023.03.28 |
116일차(1)/CSS(15) : CSS3 Flex 활용(3) (0) | 2023.03.27 |
115일차(1)/CSS(14) : CSS3 Flex 활용(2) (0) | 2023.03.26 |