우선, 시계를 출력하려면 당연히 Timer가 필요하다.

java.util.Timer Class 를 이용해서 일정한 주기로 Task를 실행할 수 있다.

Task는 Method를 넘겨주는게 아니라, 역시 TimerTask의 SubClassing 해서 구현한 다음 해당 Class의 Object를 넘겨줘야한다.

    @Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

mCurTimeTextView = (TextView) findViewById(R.id.CurrentTimeTextView);

MainTimerTask timerTask = new MainTimerTask();

mTimer = new Timer();

mTimer.schedule(timerTask, 500, 1000);

}


Activity 가 생성될때, 불러지는 onCreate를 Override하여, TimerTask Object와 Timer Object를 만들고, timer의 schedule method를 통하여,
일정 주기로 Task가 호출 될 수 있게 한다.

2번째 Argument가 최초 실행 timing이고, 3번째 Argument가 실행 주기이다. 초단위로 시계를 보여줄것이기 때문에,
1초마다 호출되도록 프로그래밍 하였다.

private Handler mHandler = new Handler();

private Runnable mUpdateTimeTask = new Runnable() {

public void run() {

......

}

};

class MainTimerTask extends TimerTask {

public void run() {

mHandler.post(mUpdateTimeTask);

}

}


MainTimerTask Class구현부가, InnerClass 로 TimerTask를 SubClassing한 형태인데, 
Android에서는 MainThread이외에서는 UI Object를 제어 할 수 없기 때문에,
Handler를 통해서 MainThread에 Task를 넘겨 준다.

즉 시간을 Update하는 부분은 Runnable Object의 Run() Method이다.
Run() Method는 아래와 같이 구현한다.

Date rightNow = new Date();

SimpleDateFormat formatter = new SimpleDateFormat(

"hh:mm:ss dd.MM.yyyy");

String dateString = formatter.format(rightNow);

mCurTimeTextView.setText(dateString);


현재 시간을 가져오기 위해 java.util.Date Class를 사용했으며,
Date를 String으로 변환하기위해 java.text.SimpleDateFormat Class를 사용하였다.
SimpleDateFormat Class에 대한 자세한 사용법은 http://developer.android.com/reference/java/text/SimpleDateFormat.html 를 참고 하길 바란다.
formatter를 통해서 Date String을 만들고 해당 String을 TextView에 setTest로 setting함으로써 시간을 세팅할 수 있다.

이외에 유의 해야 할점은 Activity Life Cycle에 따른 Timer stop/start 이다.

onDestory/onPause 에서 Timer 를 정지 시키고, onResume에서 재 시작해주도록 아래와 같이 프로그래밍 한다.

@Override

protected void onDestroy() {

mTimer.cancel();

super.onDestroy();

}


@Override

protected void onPause() {

mTimer.cancel();

super.onPause();

}


@Override

protected void onResume() {

MainTimerTask timerTask = new MainTimerTask();

mTimer.schedule(timerTask, 500, 3000);

super.onResume();

}


간단한 프로그래밍이지만, Android Life Cycle/ MultiThread에서의 UI 제어등 알아두어야 할것이 꽤 있다.





오늘은 DeskClock App에서 Alram  Event를 발생시키는 부분과 Alram BroadCast 처리하는 부분을 살펴 보려고 한다.

최초에 생각은 Process를 띄워서 Alaram BroadCast를 Generating 시킬것이라고 생각했었는데,
소스를 보고나선 역시나... 그따위로 할리가 없었다ㅋㅋㅋ

Android Package 중에 AlaramManager(android.app.AlarmManager)라는 녀석이 있어서, 그 서비스를 이용하는것이다. 

DeskClock 소스내에
com.android.deskclock.Alarams 가 실제로 AlaramManager를 이용하여, Alaram서비스를 등록한다.

    public static long addAlarm(Context context, Alarm alarm) {

        ContentValues values = createContentValues(alarm);

        Uri uri = context.getContentResolver().insert(

                Alarm.Columns.CONTENT_URI, values);

        alarm.id = (int) ContentUris.parseId(uri);


        long timeInMillis = calculateAlarm(alarm);

        if (alarm.enabled) {

            clearSnoozeIfNeeded(context, timeInMillis);

        }

        setNextAlert(context);

        return timeInMillis;

    


addAlaram() Method가 실제로 알람을 추가 하는데,
여기선 직접적으로 AlramManager도 사용하지 않고, Data Handling도 하지 않는다.
단순히, ContentResolver를 통해서 Data를 삽입하고, setNextAlert()을 통해서 다음 알람을 세팅한다.

setNextAlram()는 alram이 있냐 없냐를 봐서 없으면 Disable , 있으면 Enable시키는데, 
일단 관심은 AlaramManager를 사용하는 파트 임으로, 제끼고 
enableAlert() Method를 보도록 하자.

 private static void enableAlert(Context context, final Alarm alarm,

            final long atTimeInMillis) {

        AlarmManager am = (AlarmManager)

                context.getSystemService(Context.ALARM_SERVICE);


        if (Log.LOGV) {

            Log.v("** setAlert id " + alarm.id + " atTime " + atTimeInMillis);

        }


        Intent intent = new Intent(ALARM_ALERT_ACTION);


        Parcel out = Parcel.obtain();

        alarm.writeToParcel(out, 0);

        out.setDataPosition(0);

        intent.putExtra(ALARM_RAW_DATA, out.marshall());


        PendingIntent sender = PendingIntent.getBroadcast(

                context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);


        am.set(AlarmManager.RTC_WAKEUP, atTimeInMillis, sender);


        setStatusBarIcon(context, true);


        Calendar c = Calendar.getInstance();

        c.setTimeInMillis(atTimeInMillis);

        String timeString = formatDayAndTime(context, c);

        saveNextAlarm(context, timeString);

    }


보면 사실 별것은 없고,  AlramManager Object를 얻어오고, Intent를 만들고,
Alram에서 넘어온 시간 값 함꼐 am.set으로 넘겨 주는 이정도 이다.

실제로 사용하는건 참 간단하다고 볼 수 있다.

다음번에는 AlramManager가 trig 하는 BroadCast를 어떻게 받아서 처리 하는지 보면
기본적으로 Alaram Service 사용을 알 수 있다.

내 생각에 추가로 ContentResoulver() 쪽만 스터디 하고 나면, 
Alram App 하나정도는 금방 만들수 있지 않을까 생각한다.


Android Manifest.xml은 Android 앱의 "시작과 끝"이다.
Android Manifest를 잘 들여 다 보면, 이 앱이 어떤 하드웨어를 사용하고, 어떤 기능등을 제공하는지 대략적으로 알 수 있다.

AndroidManifest.xml을 볼때 가장 먼저 보는것이 android-permission 부분이다.

DeskClock에서 사용하고 있는 Permission List는 아래와 같다 

    <uses-permissionandroid:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    <uses-permissionandroid:name="android.permission.WAKE_LOCK"/>

    <uses-permissionandroid:name="android.permission.VIBRATE"/>

    <uses-permissionandroid:name="android.permission.WRITE_SETTINGS"/>

    <uses-permissionandroid:name="android.permission.DISABLE_KEYGUARD"/>

    <uses-permissionandroid:name="android.permission.READ_PHONE_STATE"/>

    <uses-permissionandroid:name="android.permission.DEVICE_POWER"/>


해당 설정들은 http://developer.android.com/reference/android/Manifest.permission.html 에서 상세 정보를 볼수 있따.

특히한것만 한번 살펴 보면,

WRITE_SETTING - Android Device의 System Setting을 Read/Write할 수 있는 권한  
DISABLE_KEYGUARD - KEYGUARD를 Disable시키는 건데, KeyGuard란 화면 Lock됐을때의 화면이다.
READ_PHONE_STATE - Phone 번호 정보등 폰에 관련된 정보를 얻기 위한 권한 

Activity 들은 UI 단의 Activity 이기 때문에, 제처두고, 

등록되어 있는 Service, Provider, Receiver쪽을 잠깐 살펴보자..

<provider android:name="AlarmProvider" android:authorities="com.android.deskclock" />


이부분은 해당 App.을 "Content Provider"로 사용하겠다는 선언이다.
android:authorities는 Content Provider의 identification 이라고 생각하면 된다.
자세한 정보는 에서 http://developer.android.com/guide/topics/manifest/provider-element.html 확인할 수 있다.


 <receiver android:name="AlarmReceiver">

            <intent-filter>

               <action android:name="com.android.deskclock.ALARM_ALERT" />

               <action android:name="alarm_killed" />

               <action android:name="cancel_snooze" />

            </intent-filter>

 </receiver>

 <service android:name="AlarmKlaxon">

            <intent-filter>

                <action android:name="com.android.deskclock.ALARM_ALERT" />

            </intent-filter>

 </service>


위와 같이 service/receiver 선언 부분이 몇가지 있는데, 
service 는 Android에서 얘기하는 "BroadCast" 를 발생시키는 녀석이고,
receiver는 "BroadCast"를 받아서 처리 하는 녀석이다.

위의 코드를 보면, DeskClock에서는 Alram을 발생시키고, 그리고 자기가 직접 처리 할수 있게 설정되어 있다.
그외에도 몇가지 Receiver들이 선언 되어 있는데,
BOOTING/TIME_SET/TIMEZONE_CHANGED/등등의 BROADCAST를 처리 할 수 있게 
Receiver들이 선언 되어 있다. 

단순한 것이지만, service를 등록하여 alram을 broadcast하고, receiver를 등록하여 alram을 사용자에게 알려주는 기능을 한다는 것을 
AndroidManifest.XML을 보면서 파악할 수 있었다.

이 Manifest 설정을 보면서 소스 코드를 파악해보도록 하자.


DeskClock ? Google사에서 오픈 소스로 여는 시계 어플리케이션이다.


Android 공부도 할겸해서, 분석해보기로 한 어플리케이션! 

Project URL  : http://android.git.kernel.org/?p=platform/packages/apps/DeskClock.git 

이 소스 분석을 통해 기대 하고 있는 부분은, Alaram Service를 위한 Service Provider 구현.
Alaram을 울리기 위한, 진동/사운드 등등 이다.

Project Page 에서 볼 수 있듯이, 소스 코드는 git 를 통해서 다운로드 받는다.

> git clone git://android.git.kernel.org/platform/packages/apps/DeskClock.git



위와 같이 다운로드 받아 진다.

Google에서 공개 하는 Source Code 는 Android Sample역시, Eclipse 에서 import 하도록 되어 있지 않고,
Eclipse의 "Create Project from exising Source"를 통해서 Eclipse에서 Project를 열도록 되어 있다.


적당한 이름을 써주고, Buid Target을 각자의 환경에 맞게 설정하고, 

Run as "Android Applicaton" 으로 실행하면,

프로젝트 실행이 완료 된것이다.


+ Recent posts