ArrayIndexOutOfBoundsException
- Array 변수의 특정 번째에 데이터가 없는 경우, 즉 Array변수의 데이터가 0부터 7까지 있는데 8번재의 데이터를 찾으려고 시도 할때 발생되는 에러 입니다.
Example Source
public static void main(String[] args) {
   try{
      int value;
      int array[] = {6, 16, 26,36,46,56,66,76};
     int index = 8;
      value = array[index];   // <-- 여기서 발생
      System.out.println("Execution does not reach here if there is a invalid index.");
   }catch(ArrayIndexOutOfBoundsException e){
      System.out.println( "Valid indexes are 0, 1,2,3, 4,5,6 or 7" );
   }
 }
 
 출처 : http://doplait.springnote.com/pages/6458459

'Java' 카테고리의 다른 글

우선순위 큐(Priority Queue)와 힙(Heap)  (0) 2011.05.02
Collection  (0) 2011.05.02
출처 : http://www.androes.com/122
01-13 16:18:35.675: ERROR/AndroidRuntime(13682): java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(2131099659, class android.widget.ListView) with Adapter(class android.widget.HeaderViewListAdapter)]

위와 같은 메세지가 뜨면서 강제 종료되는 경우 아래와 같은 방법을 이용하면 됩니다.

단, ListActivity가 아닌 Activity 사용시에 적용가능한 코드이오니 착오없으시길..^^

        adapter = new NewAdapter(this, R.layout.new_list_custom, Items);
        runOnUiThread(new Runnable() { 
            public void run() { 
                adapter.notifyDataSetChanged(); 
            } 
        });        
윈도우에서 안전모드(Safe Mode)로 진입할 수 있듯이 안드로이드에서도 안전모드로 진입할 수 있습니다.
 
여기서 안전모드에 대해서 알 필요가 있습니다. 
안전 모드란 OS를 진단하기 위한 모드로, 전자 장비에 이상이 생겼을 때 주로 실행합니다.
이는 진단 모드 또는 복구 모드라고도 불리기도 합니다.
OS가 안전모드로 부팅되었을 경우 시스템을 부팅에 필요한 최소한의 파일과 드라이버만 사용되는 등 기능적으로 제약이 많으나, 오히려 이를 통해 문제점을 해결하는 데 어느 정도 도움이 되고나 하는 것입니다.
<위의 내용은 위키백과에서 참고하였습니다.>

이제 안드로이드에서 안전모드로 부팅하는 방법을 알려드리겠습니다.

안전모드로 부팅하기 위해서는 다음의 조건이 성립되면 안전모드로 부팅됩니다.

 부팅하기 전부터 다음의 버튼중 하나만 누르고 있는 상태에서 부팅을 완료하게 되면, 안전모드로 들어가게 됩니다.
1. Menu Key
2. S Key
3. Dpad에서 Center Key
4. TrackBall Button

위의 방법은 안전모드로 진입하는 방법입니다.

이 부분에 해당되는 소스 부분은 다음과 같습니다.

frameworks/base/services/java/com/android/server/SystemServer.java
 run() {
...
// Before things start rolling, be sure we have decided whether
// we are in safe mode.
final boolean safeMode = wm.detectSafeMode();
if (safeMode) {
    try {
        ActivityManagerNative.getDefault().enterSafeMode();
        // Post the safe mode state in the Zygote class
        Zygote.systemInSafeMode = true;
        // Disable the JIT for the system_server process
        VMRuntime.getRuntime().disableJitCompilation();
    } catch (RemoteException e) {
    }
} else {
    // Enable the JIT for the system_server process
    VMRuntime.getRuntime().startJitCompilation();
}
...
위의 소스를 보시면 safeMode로 진입하기 위해서는 
detectSafeMode
함수를 타야 됩니다. 이 함수를 들여다 보면 다음과 같습니다.

frameworks/policies/base/phone/com/android/internal/policy/impl/
PhoneWindowManager.java
public boolean detectSafeMode() {
    try {
        int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
        int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S);
        int dpadState = mWindowManager.getDPadKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER);
        int trackballState = mWindowManager.getTrackballScancodeState(RawInputEvent.BTN_MOUSE);
        mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0;
        performHapticFeedbackLw(null, mSafeMode
                ? HapticFeedbackConstants.SAFE_MODE_ENABLED
                : HapticFeedbackConstants.SAFE_MODE_DISABLED, true);
        if (mSafeMode) {
            Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
        } else {
            Log.i(TAG, "SAFE MODE not enabled");
        }
        return mSafeMode;
    } catch (RemoteException e) {
        // Doom! (it's also local)
        throw new RuntimeException("window manager dead");
    }
}

위의 소스를 보시면 알수 있듯이 
 menuState, sState, dpadState, trackballState의 값들에 의해서 SafeMode에 진입 할 수 있는 것을 확인할 수 있을 것입니다.



 
안드로이드의 UI는 단일 스레드 모델이기 때문에 UI단에서 스레드를 사용하고 싶다면 핸들러를 사용해야 합니다.

1.public void onClick(View v) {
2.new Thread(new Runnable() {
3.public void run() {
4.txtView.setText("안녕하세요?"); // 텍스트뷰의 내용변경
5.}
6.}).start();
7.}

위와 같은 코드를 실행하게 된다면 해당코드는 다른스레드에서 UI에 접근하기때문에

CalledFromWrongThreadException 예외가 발생하게 되죠

이런 문제를 해결하기 위해 쓰는것이 바로 핸들러가 되겠습니다.

핸들러를 가지고 위의 코드를 수정해 보겠습니다.

01.Handler handler = new Handler();
02. 
03.public void onClick(View v) {
04.new Thread(new Runnable() {
05.public void run() {
06. 
07.handler.post(new Runnable() {
08.public void run() {
09.txtView.setText("이제는 됩니다.");
10.}
11.});
12. 
13.}
14.}).start();
15.}

이렇게 Handler 인스턴스를 만들어놓고 post안에 Runnable을 구현하면 됩니다.

post안에 Runnable을 구현하는 방법 외에도 많은 방법이 존재합니다.


- CalledFromWrongThreadException 발생 원인 -

왜 다른스레드에서 UI를 변경하려고 하면 해당 예외가 발생하는지 안드로이드 기본소스를 통하여

알아보자면 UI변경이 있게되면 안드로이드 뷰에서는 invalidate를 호출하게 되는데

1.// View.java
2.public void invalidate() {
3....
4.final ViewParent p = mParent;
5....
6.p.invalidateChild(this, r);
7.}

여기서 보게 되면 invalidate()에서는 ViewParent의 invalidateChild()를 호출하는군요

01.// ViewRoot.java
02.public void invalidateChild(View child, Rect dirty) {
03.checkThread();
04....
05.}
06. 
07.public checkThread() {
08.if (mThread != Thread.currentThread()) {
09.throw new CalledFromWrongThreadException(
10."Only the original thread that created a view hierarchy can touch its views.");
11.}
12.}

invalidate()에서는 checkThread()를 호출합니다. checkThread()에서는 위와 같이

현재 실행중인 스레드가 ViewRoot가 가지고 있는 mThread와 참조가 같은지 비교하고

아니라면 CalledFromWrongThreadException 예외를 던지는군요

해결책 2
--------------------------------------------------------------
new Thread(new Runnable() {
    @Override
    public void run() {    
        runOnUiThread(new Runnable(){
            @Override
             public void run() {
                 // 해당 작업을 처리함
             }
        });
    }
}).start();
--------------------------------------------------------------


출처 :  
http://www.androidpub.com/android_dev_info/57470 
원문.
Add a new resource or modify existing ICU resource definition:
   Note: This is a rare case. You should talk to ICU team first if it is a bug
   in ICU resource or a feature enhancement before making such changes.
   If you would like to add existing ICU resource to Android, please check #2.
   a. Create or change the text format resource files under external/icu4c/data.
   b. Make a temporary directory for ICU build.
      i.e. mkdir external/icu4c/icuBuild
   c. cd to ICU build directory.
      i.e. cd external/icu4c/icuBuild
   d. Run external/icu4c/runConfigureICU with "Linux" option to generate the
      makefile.
      i.e. $ANDROID_BUILD_TOP/external/icu4c/runConfigureICU Linux
   e. make -j2
   f. The new icudtxxl.dat is under data/out/tmp and the individual resources are
      under data/out/build/icudtxxl
      For example, you can find data/out/tmp/icudt44l.dat and data/out/build/icudt44l/*.res.
   g. Copy the new icudtxxl.dat over $ANDROID_BUILD_TOP/external/icu4c/stubdata/icudtxxl-all.dat.
      i.e. cp data/out/tmp/icudt44l.dat $ANDROID_BUILD_TOP/external/icu4c/stubdata/icudt44l-all.dat.
   h. Check #1 or #2 to replace or add resource to ICU.
   i. Clean up ICU build directory.
   j. Discuss with icu-team how to include the change to public ICU.

위와 같은 형식으로 처리 하면됩니다.

1. 한국어로 간단하게 정리하자면, ICU4C폴더로 진입 후 icuBuild란 폴더를 생성합니다.

2. 그리고 icuBuild 폴더로 진입 한 후 icu4c 폴더[즉 이전폴더]에 존재하는 runconfigureICU 명령어를 이용하여, 빌드 환경을 생성합니다.
    예를 들면,  icuBuild$ ../
runconfigureICU  Linux 와 같이 명령어를 쳐서 빌드환경을 생성 합니다.
3.  make -j2란 명령어를 이용하여 icu4c를 빌드합니다.
4.  cp 명령어를 이용하여 stubdata폴더 안으로 복사합니다.
    예를 들면, icuBuild$ cp ./data/out /tmp/icudt44l.dat ../stubdata/icudt44l-all.dat 와같이 명령어를 칩니다.
5. 복사가 끝난 후 이전 폴더[icu4c폴더] 로 진입 후 rm 명령어를 이용하여 icuBuild 폴더를 삭제 합니다.
   예를 들면, $  rm -rf ./icuBuild 와 같이 명령어를 치면, 폴더가 삭제 됩니다.

위의 컴파일 환경은 리눅스 빌드 환경에서 하셔야지 됩니다.
이점 참고하시길 바래요~ ^^
 
1. 기본적으로 Settings에서 TimeZone의 GMT값을 Android\bionic\libc\zoneinfo\
zoneinfo.dat 파일에서 불러와 처리를 합니다.

그래서 만약 Timezone의 GMT값을 수정하고 싶을 경우에는  zoneinfo.dat, 및 idx 를 재생성 해주어야 합니다.

기존 폴더에서 생성 했다면, 다시  Android\bionic\libc\zoneinfo\ 폴더안에 복사해 주면 됩니다.

2. 기타 추가 사항에 대해서 정리 예정입니다. 좋은 정보 가지고 있으시다면, 글 부탁드려요 ^^
 

Settings -> Date and Time -> Use 24-hour format 을 Default로 설정하는 방법에 대해서 정리해 보았습니다.

일단 Use 24-hour format 기능은 onResume에서 아래와 같이 동작을 합니다.

@Override
protected void onResume() {
 super.onResume();

   ...

 ((CheckBoxPreference)mTime24Pref).setChecked(is24Hour());

   ...

}

 

private boolean is24Hour() {
  return DateFormat.is24HourFormat(this);
}

 

위의 소스를 보시면 is24HourFormat 함수를 통해서 24시간인지 아닌지를 Return해줍니다.

여기서 is24HourFormat 함수를 보면 다음과 같은데 여기서 Settings.System.TIME_12_24란 Key값을 가진 Systemproperty의 값을 받아오는 것을 확인 하실수 있습니다.

하지만 최초 부팅시 또는 초기화후 부팅시에는 value값이 존재하지 않음으로 null이 됩니다.

/**
* Returns true if user preference is set to 24-hour format.
* @param context the context to use for the content resolver
* @return true if 24 hour time format is selected, false otherwise.
*/
public static boolean is24HourFormat(Context context) {
String value = Settings.System.getString(context.getContentResolver(),
Settings.System.TIME_12_24);

if (value == null) {
Locale locale = context.getResources().getConfiguration().locale;

synchronized (sLocaleLock) {
if (sIs24HourLocale != null && sIs24HourLocale.equals(locale)) {
return sIs24Hour;
}
}

java.text.DateFormat natural =
java.text.DateFormat.getTimeInstance(
java.text.DateFormat.LONG, locale);


if (natural instanceof SimpleDateFormat) {
SimpleDateFormat sdf = (SimpleDateFormat) natural;
String pattern = sdf.toPattern();

if (pattern.indexOf('H') >= 0) {
value = "24";
} else {
value = "12";
}

} else {
value = "12";
}

synchronized (sLocaleLock) {
sIs24HourLocale = locale;
sIs24Hour = !value.equals("12");
}
}


boolean b24 = !(value == null || value.equals("12"));
return b24;
}

value 값이 null이므로 시스템으로 부터 Locale의 값을 가지고 와서 Time format을 확인한 후 value값이 12인지 24인지에 따라서 True or False를 리턴하게 됩니다.

Format의 확인 형식은 다음과 같습니다.

yyyy MM dd HH:mm             :  24시간을 표시

yyyy MM dd hh:mm a           : 12시간을 표시

여기서 "h"란 pattern을 확인 한 후 시간을 구분하게 됩니다.

하지만 여기서 한가지 의문이 생기게 됩니다.

왜 Locale을 불러오는지 말입니다.

그래서 확인한 결과 각각의 나라별 시간 표시 형식이 구분되어 있기 때문에 Locale을 사용하는 것을 확인하였습니다.

예를 들면 en_US같은 경우는 12시간을 표시하고, de_DE 같은 경우는 24시간을 표시하게 됩니다.

그래서 Locale을 사용하게 되는 것입니다.

그리고 시간의 패턴을 표시하기 위해서는 is24HourFormat 란 함수를 사용하여 확인한 후 12시간을 표시할 것인지 24시간을 표시할 것인지를 소스상에서

구분하는 것을 확인 하실수 있을것입니다.

여기까지가 24시간인지 아닌지를 체크하는 프로세스입니다.

그러면 이제 Locale을 변경을 해야되는데 이 값의 변경은 보통 SetupWizard에서 처리를 해줍니다.

하지만 SetupWizard가 없을 경우에는 Default Locale로 설정을 해주는데, 이 값은 다음과 같은 경로의 MakeFile에서 설정을 해줍니다.

Android\device\samsung\YP-GS1\Product.mk

Android\device\samsung\YP-GS1\full_YP-GS1.mk

이 파일을 열어보면, 여러 설정들이 존재하는데 그 중에서 다음과 같은 부분을 확인 할 수 있습니다.

# Overrides

PRODUCT_MANUFACTURER:=samsung

PRODUCT_BRAND:=samsung

PRODUCT_NAME:=YP-GS1

PRODUCT_DEVICE:=YP-GS1

PRODUCT_LOCALES := en_GB \

en_US en_AU en_IE en_NZ en_ZA \

   de_AT de_CH de_DE \

   fr_FR fr_CH \

   it_IT \

   es_ES \

   es_US \

   nl_NL \

   pt_PT \

   pl_PL \

   tr_TR \

   ko_KR \

   ru_RU \

   bg_BG hr_HR cs_CZ da_DK nl_BE et_EE fi_FI el_GR \

   hu_HU is_IS ga_IE kk_KZ lv_LV lt_LT mk_MK no_NO \

   pt_PT ro_RO sr_RS sk_SK sl_SI sv_SE uk_UA

여기서 Product_locales부분을 확인 할 수 있는데 여기의 첫번째 값이 en_GB이냐 ko_KR이냐에 따라 최초 부팅시 Locale의 값이 바뀌게 됩니다.

그래서 만약 영국식 영어로 설정하고 싶을 경우에는 위와 같이 en_GB를 첫번째로 넣으시면 됩니다.

Locale Default 24 hour을 설정하는 방법은 다음과 같습니다.

Android/external/ICU4C/data/locales/en_GB.txt를 열어보면 다음과 같습니다.

 // ***************************************************************************

// *
// * Copyright (C) 2007 International Business Machines
// * Corporation and others.  All Rights Reserved.
// * Tool: com.ibm.icu.dev.tool.cldr.LDML2ICUConverter.java
// * Source File:<path>/common/main/en_GB.xml
// *
// ***************************************************************************
en_GB{
    NumberPatterns{
        "#,##0.###",
        "¤#,##0.00",
        "#,##0%",
        "#E0",
    }
    Version{"1.54"}
    calendar{
        gregorian{
            DateTimePatterns{
                "HH:mm:ss v",
                "HH:mm:ss z",
                "HH:mm:ss",
                "HH:mm",
                "EEEE, d MMMM yyyy",
                "d MMMM yyyy",
                "d MMM yyyy",
                "dd/MM/yyyy",
                "{1} {0}",
            }
        }
    }
    delimiters{
        alternateQuotationEnd{"”"}
        alternateQuotationStart{"“"}
        quotationEnd{"’"}
        quotationStart{"‘"}
    }
    zoneStrings{
        "meta:Europe_Central"{
            cu:int{1}
        }
        "meta:Europe_Eastern"{
            cu:int{1}
        }
        "meta:Europe_Western"{
            cu:int{1}
        }
    }
}

여기서 gregorian영역안에서 Format에 해당하는 부분들을 추가해야 합니다.
예를 들면, 
dayNames, monthNames, quarters 등을 추가하여야 하며, 이를 적용한 부분의 예는 다음과 같습니다.

 
 // ***************************************************************************
// *
// * Copyright (C) 2007 International Business Machines
// * Corporation and others.  All Rights Reserved.
// * Tool: com.ibm.icu.dev.tool.cldr.LDML2ICUConverter.java
// * Source File:<path>/common/main/en_GB.xml
// *
// ***************************************************************************
en_GB{
    NumberPatterns{
        "#,##0.###",
        "¤#,##0.00",
        "#,##0%",
        "#E0",
    }
    Version{"1.54"}
    calendar{
        gregorian{
            DateTimePatterns{
                "HH:mm:ss v",
                "HH:mm:ss z",
                "HH:mm:ss",
                "HH:mm",
                "EEEE, d MMMM yyyy",
                "d MMMM yyyy",
                "d MMM yyyy",
                "dd/MM/yyyy",
                "{1} {0}",
            }
dayNames{ format{ abbreviated{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", } wide{ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", } } stand-alone{ narrow{ "S", "M", "T", "W", "T", "F", "S", } } }
monthNames{ format{ abbreviated{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", } wide{ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", } } stand-alone{ narrow{ "J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D", } } } quarters{ format{ abbreviated{ "Q1", "Q2", "Q3", "Q4", } wide{ "1st quarter", "2nd quarter", "3rd quarter", "4th quarter", } } stand-alone{ narrow{ "1", "2", "3", "4", } } }
} } delimiters{ alternateQuotationEnd{"”"} alternateQuotationStart{"“"} quotationEnd{"’"} quotationStart{"‘"} } zoneStrings{ "meta:Europe_Central"{ cu:int{1} } "meta:Europe_Eastern"{ cu:int{1} } "meta:Europe_Western"{ cu:int{1} } } }

gregorian
 영역안에 Format 영역을 추가 한 후 icudt44l.dat 파일을 생성한 후 stubdata 폴더에 복사하면 됩니다.

'안드로이드' 카테고리의 다른 글

ICU4C 빌드 방법.  (0) 2011.06.22
Time Zone 수정 방법.  (0) 2011.06.22
안드로이드 OS의 기본언어(locale) 설정하기  (0) 2011.06.15
Locale에 따른 시간 포멧 설정.  (0) 2011.06.15
PowerManager 사용시 유의점.  (0) 2011.06.13
안드로이드의  현재 설정  언어/국가/timezone 등은 

/data/property 디렉토리에  

persist.sys.timezone
persist.sys.language
persist.sys.country

이런 파일명으로  저장되어 있습니다. 

설정에서  언어들 바꾸고,  위 위치에 가서  cat 등으로 보시면 저장된 값이 바뀌어 있는 것을 보실 수 있습니다. 


즉,  부팅시에  이 파일이 있으면  해당 언어로  안드로이드 OS가 구동이 된다는 것입니다. 



그럼,  위 파일을  저장해 주는  방법이  OS 빌드 중에 어딘가에 있겠지요. 

이것은  init.rc 파일에 적어주면 되더군요. 

OS의 소스 디렉토리 중에서  

vender/업체/프로젝트/  로 된 디렉토리에 가시면,  init.rc 파일이 있는데요. 

01.# killed by the kernel.  These are used in ActivityManagerService.
02.setprop ro.FOREGROUND_APP_ADJ 0
03.setprop ro.VISIBLE_APP_ADJ 1
04.setprop ro.SECONDARY_SERVER_ADJ 2
05.setprop ro.BACKUP_APP_ADJ 2
06.setprop ro.HOME_APP_ADJ 4
07.setprop ro.HIDDEN_APP_MIN_ADJ 7
08.setprop ro.CONTENT_PROVIDER_ADJ 14
09.setprop ro.EMPTY_APP_ADJ 15
10. 
11.# for  default langudage
12.setprop persist.sys.language ko
13.setprop persist.sys.country KR
14.setprop persist.sys.timezone Asia/Seoul


위의  아래쪽 3줄 처럼 넣어 줍니다. 

setprop 의  위치가 중요하지는 않을 수도 있는데요. 
전 저 위치에 넣었습니다. 

이렇게 해서 OS를 빌드하면, 

최초 실행시에도 한글로  나온답니다. 

출처 : http://www.androidpub.com/203240 

build\target\product\sdk.mk or core.mk 등에서 사용되기도 함.
 

설정의 언어 목록을 수정하는 방법은 바이너리 빌드시에 Product.mk 파일을 수정해 주면 된다.

기본적으로 Product.mk 파일은 device/[company]/[Project]/Product.mk 또는 [Project Name].mk로 존재 합니다. 

PRODUCT_LOCALES := en_US ko_KR 이렇게 작성하면 목록에는 영어와 한국어 두개만 나타나게 된다.
 
그리고 Locale Default로는 en_US로 사용됩니다.

getDateInstance

public static final DateFormat  getDateInstance(int style,
                                               Locale  aLocale)
지정된 로케일에 대해, 지정된 포맷 스타일을 가지는 일자 포매터를 가져옵니다.

파라미터:
style - 지정하는 포맷 스타일. 다음에 예를 나타냅니다. US 로케일에서의 M/d/yy 에 대한 SHORT
aLocale - 지정된 로케일
반환값:
일자 포매터

boolean isScreenOn ()

void goToSleep (long time)

void reboot (String reason)

void userActivity (long when, boolean noChangeLights)

 

화면의 켜짐을 조사하거나 즉시 화면을 끄거나 재부팅하는 등의 기능을 제공한다. 화면을 강제로 끄는 goToSleep 메서드는 전원 버튼을 누르지 않아도 프로그램이 소프트웨어적으로 슬립 모드로 들어갈 수 있어 실용성이 있다. 그러나 아무나 사용할 수 있는 메서드는 아니므로 엄격한 제한이 따른다. 이 메서드를 사용하려면 DEVICE_POWER 퍼미션이 필요하며 또 시스템 앱으로 서명을 해야 한다.

+ Recent posts