Notice
Recent Posts
Recent Comments
Link
«   2024/04   »
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
Archives
Today
Total
관리 메뉴

ParkPro's App development store

[Android] 안드로이드 알람 어플. 시간 설정과 알람 기능 예제 코드 (TimePicker, Alarm manager example code) 본문

Android

[Android] 안드로이드 알람 어플. 시간 설정과 알람 기능 예제 코드 (TimePicker, Alarm manager example code)

박프로ParkPro 2020. 5. 18. 21:16

안녕하세요, 박프로입니다.

안드로이드에서 알람 어플은 기본적으로 두 가지 기능으로 구성되어 있죠.

알람 시간 설정알람 시간이 되었을 때 정해진 '기능' 실행.

이번 페이지에서는 안드로이드 알람 어플에 필요한 이 두 가지 기본 기능 구현에 대해 알아보겠습니다.

 

구현 내용

아래 캡쳐사진을 보시면 두 개의 버튼이 있습니다. OPEN TIME PICKER 버튼을 통해 알람 시간을 설정하고 나면, 설정된 시간에 알림(Notificaion)이 동작하는 어플 예제입니다.

 

[1] 기본화면, [2] OPEN TIME PICKER 버튼 클릭 화면, [3] 알람 설정된 시간에 알림 푸쉬 (메뉴바 아이콘 생성)

 


코드 리뷰

[0] 구성

- Layout : layout_main.xml

- 알림 기능 : NotificationHelper class

- 시간 설정 기능 : TimePickerFragment class

- 알람 발생 시 동작할 기능 : AlertReceiver class (세팅된 알람 시간이 되었을 때 동작할 기능)

- 그리고 MainActivity

[1] layout

TimePicker를 이용하여 설정된 시간을 받아와 Text view를 통해서 화면에 표시하였습니다.

두 개의 버튼은 각각 알람 설정 버튼과 알람 취소 버튼입니다.

 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="No Alarm set"
        android:textSize="30sp"


        android:layout_above="@+id/button_timepicker"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="31dp"
        />

    <Button
        android:id="@+id/button_timepicker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="open time picker"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        />

    <Button
        android:id="@+id/button_cancel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="cancel alarm"
        android:layout_below="@+id/button_timepicker"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="27dp"
        />


</RelativeLayout>

 

[2] NotificationHelper

이전 글에서 설명한 코드와 유사합니다.

NotificationHelper 기능에 대한 자세한 설명은 아래 링크에서 확인해주시면 됩니다.

NotificationHelper 설명 : [Android] 안드로이드 앱 푸쉬 알림 기능 코드

public class NotificationHelper extends ContextWrapper {
    public static final String channel1ID = "channel1ID";
    public static final String channel1Name = "channel 1 ";
    public static final String channel2ID = "channel2ID";
    public static final String channel2Name = "channel 2 ";

    private NotificationManager mManager;

    public NotificationHelper(Context base) {
        super(base);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createChannels();
        }
    }

    public void createChannels(){
        NotificationChannel channel1 = new NotificationChannel(channel1ID,channel1Name, NotificationManager.IMPORTANCE_DEFAULT);
        channel1.enableLights(true);
        channel1.enableVibration(true);
        channel1.setLightColor(R.color.colorPrimary);
        channel1.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);

        getManager().createNotificationChannel(channel1);

        NotificationChannel channel2 = new NotificationChannel(channel2ID,channel2Name, NotificationManager.IMPORTANCE_DEFAULT);
        channel2.enableLights(true);
        channel2.enableVibration(true);
        channel2.setLightColor(R.color.colorPrimary);
        channel2.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);

        getManager().createNotificationChannel(channel2);

    }

    public NotificationManager getManager() {
        if (mManager == null){
            mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        }

        return mManager;
    }

    public NotificationCompat.Builder getChannel1Notification(String title, String message){
        return new NotificationCompat.Builder(getApplicationContext(), channel1ID)
                .setContentTitle(title)
                .setContentText(message)
                .setSmallIcon(R.drawable.ic_one);
    }

    public NotificationCompat.Builder getChannel2Notification(String title, String message){
        return new NotificationCompat.Builder(getApplicationContext(), channel2ID)
                .setContentTitle(title)
                .setContentText(message)
                .setSmallIcon(R.drawable.ic_two);
    }

    public NotificationCompat.Builder getChannelNotification(){
        return new NotificationCompat.Builder(getApplicationContext(), channel1ID)
                .setSmallIcon(R.drawable.ic_one);
    }
}

 

[3] TimePickerFragment

DialogFragment를 상속받아서 TimePickerFragmet class를 생성해줍니다.

TimePicker에서 사용자가 선택한 hour, min을 OnTimeSet 메소드를 통해 전달할 수 있습니다.

public class TimePickerFragment extends DialogFragment {
        @NonNull
        @Override
        public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
            Calendar c = Calendar.getInstance();
            int hour = c.get(Calendar.HOUR_OF_DAY);
            int minute = c.get(Calendar.MINUTE);


            return new TimePickerDialog(getActivity(), (TimePickerDialog.OnTimeSetListener) getActivity(), hour, minute, DateFormat.is24HourFormat(getActivity()));

        }
    }

 

DateFormat을 통해 24시간/12시간 모드를 선택이 가능합니다. 또 원형 모양의 시계가 마음에 안들면, 시계의 모드도 변경할 수 있습니다. 아래 사진과 같은 형태가 좀 더 친숙하죠?

 

아래 코드처럼 TimePickerDialag의 인자 중 Style을 변경해서 시계 모양 변경이 가능합니다.

return new TimePickerDialog(getActivity(), android.R.style.Theme_Holo_Light_Dialog_NoActionBar,(TimePickerDialog.OnTimeSetListener) getActivity(), hour, minute, DateFormat.is24HourFormat(getActivity()));

 

[4] AlertReceiver

알람 시간이 되었을 때 동작할 기능으로 AlertReceiver class를 생성했습니다.

AlertReceiver class에서는 알림 기능을 동작하도록 코드를 구현했습니다.

만약 알람 시간이 되었을 때의 다른 기능을 구현하고 싶으면 다른 기능의 class를 만들면 됩니다.

public class AlertReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        NotificationHelper notificationHelper = new NotificationHelper(context);
        NotificationCompat.Builder nb = notificationHelper.getChannelNotification();
        notificationHelper.getManager().notify(1,nb.build());
    }
}

+ AndroidManifest.xml

안드로이드에서 receiver를 동작시키기 위해서 intent filter와 receiver를 추가해줍니다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.parkpro.timepickerexample">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name=".AlertReceiver"/>
    </application>

</manifest>

 

[5] MainActivity

Button을 누르면 TimePikcer DialgFragment가 생성되면서 시간을 선택하게끔 되고, TimePicker에서 받아온 시간을 onTimeSet 메소드에서 받아와 시간 업데이트 및 알람 세팅이 시작됩니다.

 

여기서 주목할 부분은, startAlarm method에서

(1) Receiver class를 intent로 생성한 후에

(2) intent를 이용해서 pending intent를 만들고

(3) alarmManager가 pending intent를 입력값으로 받아 실행시킨다는 점입니다.

 

alarmManager를 이용해서 실행할 '특정 행동'은 이렇게 pending intent를 사용해서 구성됩니다.

펜딩인텐트(Pending intent)는 인텐트(intent)의 일종인데, pending이란 단어의 의미를 가져와 해석해보면 '어떤 일이 있을 때 까지 기다리는 인텐트'라고 해석할 수 있는데요. 말 그대로 '지금' 실행하는 인텐트가 아니라 '특정 시점'에 실행하는 인텐트입니다. 안드로이드의 AlarmManager가 미래의 특정 시점에 실행할 인텐트로 펜딩인텐트가 사용되는 것이 대표적인 펜딩인텐트의 사용 사례입니다.

(pending intent에 대한 설명 : https://techlog.gurucat.net/80)

 

알람설정 구현을 했으니 알람을 취소하는 메소드도 추가해줍니다. (cancelAlarm)

public class MainActivity extends AppCompatActivity implements TimePickerDialog.OnTimeSetListener{
    private TextView mTextView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);



        setContentView(R.layout.activity_main);


        mTextView =  findViewById(R.id.textView);

        Button button = (Button) findViewById(R.id.button_timepicker);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                DialogFragment timePicker = new TimePickerFragment();
                timePicker.show(getSupportFragmentManager(), "time picker");
            }

        });

        Button buttonCancelAlarm = findViewById(R.id.button_cancel);
        buttonCancelAlarm.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick (View v) {
                cancelAlarm();
            }
        });
    }

    @Override
    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
        Calendar c = Calendar.getInstance();
        c.set(Calendar.HOUR_OF_DAY, hourOfDay);
        c.set(Calendar.MINUTE, minute);
        c.set(Calendar.SECOND, 0);

        updateTimeText(c);
        startAlarm(c);
    }

    private void updateTimeText(Calendar c){
        String timeText = "Alarm set for : ";
        timeText += DateFormat.getTimeInstance(DateFormat.SHORT).format(c.getTime());

        mTextView.setText(timeText);
    }

    private void startAlarm(Calendar c){
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(this, AlertReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1, intent, 0);

        if(c.before((Calendar.getInstance()))){
            c.add(Calendar.DATE, 1);
        }
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pendingIntent);
        //alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), 1*60*1000 ,  pendingIntent);

    }

    private void cancelAlarm(){
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(this, AlertReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1, intent, 0);

        alarmManager.cancel(pendingIntent);
        mTextView.setText("Alarm canceled");
    }

}

 

간단하게 알람 어플 예제를 구현해봤습니다.

저도 강의 들으면서 공부한 것을 정리하는 중인데요, 공부하시는 분들에게 도움이 되었으면 좋겠습니다.

 

좋은 하루 보내시길 바랍니다.