월별 글 목록: 2013년 11월월

PreferenceFragment에서 스크롤바 제어하기..

PreferenceFragment 클래스는 안드로이드 API 11에서 처음 소개되었고, 기존의 PreferenceActivity(보통 설정화면을 처리하기 위해서 사용한다)를 허니콤 이상의 버전에서 Fragment로 대체하기 위해서 추가되었다.

대부분 안드로이드 앱의 설정 부분을 살펴보면, 설정의 항목이 많은 경우 기본 스크롤바를 보게 된다. 이 스크롤바에 스타일을 주거나, 없애는 등의 작업을 할 수 있는 방법을 살펴보자. PreferenceFragment 클래스에서 화면에 설정항목들을 보여주기 위한 뷰로 ListView를 사용하고 있다. 그리고 기본 API에서는 ListView에 접근하는 메서드나 ListView의 메서드를 지원하지 않는다.

그래서 PreferenceFragment를 상속한 클래스에서 Reflection을 이용해서  ListView객체를 사용해서, 간단하게 PreferenceFragment의 스크롤바를 제거해보자.

아래의 AbstractPreferenceFragment는 여러 설정화면을 구현하는 클래스가 상속해서 사용하도록 만든 부모 클래스이다. 각 설정화면을 구현하는 클래스에서는 이 AbstractPreferenceFragment 클래스를 상속해서, disableScrollBar()만 호출하면 스크롤바를 제거할 수 있다.

public class AbstractPreferenceFragment extends PreferenceFragment {
	protected void disableScrollBar() {
		Field field = null;
		try {
			field = PreferenceFragment.class.getDeclaredField("mList");
			// 소스를 확인해 보니, 아이스크림 이후(허니콤은 소스를 공개하고 있지 않아서 모르겠지만 동일하지 않을까 예측) 부터
			// 계속 mList라는 변수명을 사용하고 있음
			field.setAccessible(true);
			((ListView) field.get(this)).setVerticalScrollBarEnabled(false);
		} catch (Exception e) {
		}
	}
}

이제, 위의 코드를 활용해서 ListView에 스크롤바를 트윅해서 스타일이나, 여러가지 변경을 할 수 있겠다.

우분투(Ubuntu)에서 Webdav 마운트하기..

개인적으로 클라우드 서비스를 많이 사용하는 사용자로, 일부 서비스들은 싱크 어플리케이션이 리눅스 용으로 출시를 하고 있지 않아서 아쉬웠는데, Webdav을 마운트 해서, 싱크 클라이언트의 대안으로 사용할 수 있다. 아래는 우분투(Ubuntu)에서 root 계정으로, webdav을 마운트하는 방법이다.

1. davfs2(http://savannah.nongnu.org/projects/davfs2) 설치
$ sudo apt-get install davfs2

2. 폴더 생성
// 루트로 생성한다.
$ sudo mkdir /media/webdav

3. webdav 서비스 마운트..
$ sudo mount -t davfs https://ip_address:port /media/webdav

4. 마운트 해제
$ sudo umount /media/webdav

간단하게, box.net과 4shared의 webdav 서비스들을 마운트 해 보면..
* http://www.box.com
$ sudo mkdir /media/box
$ sudo mount -t davfs https://dav.box.com/dav /media/box

* http://www.4shared.com
$ sudo mkdir /media/4shared
$ sudo mount -t davfs https://webdav.4shared.com /media/4shared

아래 처럼, 위 명령으로 마운트한 webdav 서비스들을 볼 수 있다.

참고로, webdav 서비스를 제공하고 있는 클라우드 서비스들은 http://www.sjava.net/?p=469을 참고하면 된다.

* Reference
http://www.handybackup.net/webdav-client-for-web-folder.shtml

android.app.FragmentManagerImpl.execPendingActions에서 NPE가 떨어지는 경우..

android.app.FragmentManagerImpl.execPendingActions에서 java.lang.NullPointerException(NPE)가 떨어지는 제 경우를 살펴보니, Activity에서 많은 Fragment가 replace되고 있는 상황이다. 이 문제에 대해서, 아래를 확인해 보면 도움을 받을 수 있다.
– http://stackoverflow.com/questions/14810183/fragmentmanager-nullpointerexception-when-trying-to-commitallowingstateloss
– http://stackoverflow.com/questions/10456077/nullpointerexception-in-fragmentmanager

아래는 android.app.Activity를 상속받은 Activity 클래스에서 앱이 종료되면서, 프레임웍에서 발생시키는 크래시이다. 이것만으로는 디버깅하기 졸라 어렵다.

11-06 14:24:55.582: E/AndroidRuntime(6925): FATAL EXCEPTION: main
11-06 14:24:55.582: E/AndroidRuntime(6925): java.lang.NullPointerException
11-06 14:24:55.582: E/AndroidRuntime(6925): at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1357)
11-06 14:24:55.582: E/AndroidRuntime(6925): at android.app.FragmentManagerImpl$1.run(FragmentManager.java:426)
11-06 14:24:55.582: E/AndroidRuntime(6925): at android.os.Handler.handleCallback(Handler.java:605)
11-06 14:24:55.582: E/AndroidRuntime(6925): at android.os.Handler.dispatchMessage(Handler.java:92)
11-06 14:24:55.582: E/AndroidRuntime(6925): at android.os.Looper.loop(Looper.java:137)
11-06 14:24:55.582: E/AndroidRuntime(6925): at android.app.ActivityThread.main(ActivityThread.java:4424)
11-06 14:24:55.582: E/AndroidRuntime(6925): at java.lang.reflect.Method.invokeNative(Native Method)
11-06 14:24:55.582: E/AndroidRuntime(6925): at java.lang.reflect.Method.invoke(Method.java:511)
11-06 14:24:55.582: E/AndroidRuntime(6925): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
11-06 14:24:55.582: E/AndroidRuntime(6925): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
11-06 14:24:55.582: E/AndroidRuntime(6925): at dalvik.system.NativeStart.main(Native Method)

그래서, Activity를 최신버전(4.4)의 support 라이브러리에 있는 FragmentActivity로 바꿔서 돌려보니, 디버깅할 수 있는 콜 스택을 보여준다.. 헐.. 그래서, 내 경우에는 Fragment 클래스에서 replace하는 메서드에 아래의 코드를 추가해서 해결했다.

if(activity() == null || activity().isFinishing())
return;