안드로이드 개발 시 유용한 툴 소개(ChromeADB, Vysor)

안녕하세요. 오늘은 안드로이드 개발 시 유용한 툴 두가지를 소개드리려고 합니다. 기술적인 내용이 아니니 가볍게 봐주시면 좋겠습니다.

ChromeADB

첫번째로 소개드릴 툴은 ChromeADB입니다. 이 툴은 ADB 주요 기능들에 GUI를 입혀서 만든 크롬앱입니다. 사용해보시면 굳이 설명이 필요없을 정도로 UI도 단순하고 직관적인데요.
그래도 간단히 소개해 드리도록 하겠습니다. 먼저 아래 화면은 패키지 관리 화면입니다. 앱 삭제 및 설치, 데이터 삭제, 강제 종료를 쉽게 할 수 있습니다. 보통은 단말의 설정 -> 앱관리에 들어가 원하는 앱을 찾고 위의 작업들을 하는데요. 제조사나 안드로이드 버전에 따라 메뉴 구성이 달라서 은근히 많은 시간이 들고 자주하게 되면 매우 귀찮은 작업입니다. 하지만 ChromeADB를 사용하면 매우 쉽고 빠르게 이런 작업들을 할 수 있습니다.

chromeadb_look.png

두번째로는 컨트롤러 화면입니다. 텍스트 입력, 전원, 볼륨 등의 사용자 입력을 이용한 테스트를 할 수 있습니다. 저는 글쓰기 에디터를 만들때 유용하게 사용했던 기능입니다.

chromeadb_controller.png

마지막으로 보여드릴 기능은 메모리 관리 기능인데요. 그래프를 통해서 실시간으로 메모리 사용량을 볼 수 있습니다. 사실 이 기능은 안드로이드 스튜디오에서 이제 메모리 사용량을 예쁘게 보여주기 때문에 별로 의미가 없어지긴 했는데요. 예전에 이클립스를 사용할때는 정말 유용했던 기능입니다. 프로세스 탭에 들어간 후 메모리 사용량을 보고 싶은 앱을 선택하면 됩니다.

chromeadb_memory.png

Vysor

두번째로 소개드릴 앱은 바로 Vysor라는 앱으로 ChromeADB와 마찬가지로 크롬앱입니다. 실제 안드로이드 단말의 화면을 컴퓨터 화면으로 미러링해주는 앱으로 정말 강력하게 추천하는 앱입니다. 그 이유는 다음과 같습니다. 일반적으로 테스트를 하다보면 에물레이터를 쓰거나 단말을 직접 연결해서 단말을 통해 테스트를 하는데요. 이 두가지 방법은 모두 장단점이 있습니다. 에뮬레이터를 쓰는 경우엔 보통 네트워크나 카메라, GPS 등의 테스트가 제한적이고 각종 앱들의 계정 관련 설정을 하기가 까다롭습니다. 가령 카카오톡 공유하기 기능 같은 걸 테스트하기 위해서는 카카오톡 계정을 연동하는 등의 작업을 해야하는데 이런 부분이 어렵죠. 실제 단말을 사용하는 경우엔 위의 단점들을 극복할 수 있지만 매번 모니터를 보고 코드를 작성하다가 다시 단말을 확인하는 작업이 여간 불편한게 아닙니다. 하지만 이 앱을 쓰면 이런 단점들은 커버하고 장점만 취할 수가 있습니다. 회의때 프리젠테이션 용도로 사용해도 아주 좋구요. 사용법도 너무 간단합니다. Vysor를 실행하고 PC와 안드로이드 단말을 연결하면 Vysor에 연결된 단말이 나오고 Connect 버튼을 누르면 바로 미러링이 시작됩니다.

vysor_look.png

아래 화면은 미러링이 시작된 화면입니다.

vysor_mirror1.png
vysor_mirror2.png

아래 이미지는 실제 단말에서 카메라를 켠 화면인데요. 미러링된 화면에서도 잘 보이는걸 알 수 있습니다.
vysor_mirror3.png

개발을 하다보면 키보드에서 마우스로 손 한번 가는것도 귀찮게 느껴질때가 있는데요. 코드를 짜고 빌드 버튼을 누르고 키보드에서 손을 떼고 단말을 손에 쥐고 테스트하는 작업은 말할것도 없죠.
이런것들이 상당히 많이 해소되기 때문에 정말 좋습니다. (살짝 화면상에 딜레이가 있거나 화질이 떨어지기도 하는데요 크게 불편한 정도는 아닌거 같습니다.)

마지막으로 위에 소개드린 두 앱은 모두 크롬앱으로 만들어졌기 때문에 맥이든 윈도우든 리눅스든 다 사용이 가능하고 설치고 크롬 앱스토어에서 쉽게 설치가 가능하구요. 일반 앱처럼 런처를 통해서도 바로 실행 시킬 수 있는것도 큰 장점인것 같습니다. 장인은 연장을 가리지 않는다고 하지만 좋은 툴들을 사용하면 개발이나 테스트 시간을 많이 줄여주기 때문에 이런 툴들을 적절히 잘 사용하면 좋을 것 같습니다!

뷰페이저(ViewPager)

ViewPager는 좌우 스와이핑 제스처를 통해 뷰를 전환하는 레이아웃관리자로 볼 수 있다. 뷰페이저의 페이지는 전환될 레이아웃을 말하기 때문에 당연히 뷰도 될 수 있고 뷰그룹도 될 수 있다. 보통 가장많이 쓰이는건 프래그먼트와 함께 많이 쓰이게 된다.

특징

뷰페이저는 항상 현재 위치의 좌우 아이템을 미리 로드한다. 즉 현재 3번 페이지를 보여주고 있다면 이미 2, 4번 페이지에 대한 getItem이 호출된다. 0번에 있다면 우측의 1번 페이지까지 해서 2개가 로드된다. 그리고 현재 위치를 기준으로 좌우에 있는 페이지까지만 유지하고 그 밖에 있는 것들은 버린다.

뷰페이저의 현재 아이템 가져오기

뷰페이저는 페이지들의 전환을 쉽게 해준다. 당연히 뷰페이저를 통해 UX를 구성할때는 현재 페이지를 가져와서 원하는 작업을 하고 싶은 경우가 많다. 그래서 당연히 뷰페이저나 뷰페이저어댑터를 통해 현재 페이지를 가져올 수 있는 API가 있을 것 같다. 그…그런데…없다..그런거..-_-; 만들어야한다.

참고자료 stackOverFlow..

어떻게 할까 한 10초 고민하다가 바로 android viewpager get current fragment로 구글링을 해보니 바로 어떤 똘똘한 아저씨가 친절하게 해결책을 올려주셨다. 요새는 검색하면 어지간한 문제는 다 해결이 되는데 그만큼 내 머리를 쓸일은 적어지는 것 같다. 쩝..

아이디어는 간단하다.

  1. 프래그먼트가 생성되면 리스트에 담는다
  2. 프래그먼트가 소멸되면 리스트에서 버린다
  3. 필요할때마다 리스트에서 꺼낸다

주의점은 아까 특징에서 언급했듯이 뷰페이저는 현재 위치를 기준으로 좌우의 페이지까지만 가지고 있는다. 즉 현재 위치나 내 좌우 페이지가 아닌 위치의 페이지를 가져오려고 하면 오류가 발생한다.

이정도 개념을 머리에 두고 아래 코드를 보면 바로 이해가 갈 것 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class MyPagerAdapter extends FragmentStatePagerAdapter {
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();

public MyPagerAdapter(FragmentManager fm) {
super(fm);
}

@Override
public int getCount() {
return ...;
}

@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(...);
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}

public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}

위 코드는 아까 위에서 링크를 걸어뒀던 스택오버플로우에 있는 코드이다. 코드를 보면 아래와 같다.

  1. 프래그먼트가 생성되면 리스트에 담는다
    • instantiateItem()

  2. 프래그먼트가 소멸되면 리스트에서 버린다
    • destroyItem()
  3. 필요할때마다 리스트에서 꺼낸다
    • getRegisteredFragment()

실제 사용할때는 아래와 같이 사용하게 될 것 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class Example {
int mCurrentPosition;
ViewPager mViewPager;
MyPagerAdapter mAdapter;

......

private void initViewPager() {
mViewPager = ...;
mAdapter = new MyPagerAdapter(......);

mViewPager.setAdapter(mAdapter);
mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }

@Override
public void onPageSelected(int position) {
mCurrentPosition = position;
}

@Override
public void onPageScrollStateChanged(int state) {

}
});
}

private void doSomethingWithCurrentFragment() {
Fragment fragment = mAdapter.getRegisteredFragment(mCurrentPosition);
if (fragment == null) {
return;
}

// do something with current fragment..
}
}

먼저 뷰페이저의 현재 위치를 알기 위해 onPageChangeListener를 뷰페이저에 달아준다. 이 리스너의 onPageSelected는 뷰페이저의 페이지가 바뀔때마다 호출된다. 이걸 통해 현재 뷰패이저의 위치를 가지고 있다가 필요할 때 뷰페이저어댑터를 통해 현재 프래그먼트를 가져온다. 끝!!!