마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

안드로이드 스튜디오 BroadcastReceiver에서 mainActivity의 메소드에 접근

0 추천

안드로이드 스튜디오 BroadcastReceiver에서 mainActivity의 메소드에 접근할때 메소드에 static을 추가하지 않고 접근할 수 있는 방법은 없을까요?

NotificationReciever

package com.example.dontforgetbirthdayproject;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;

import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;

import com.example.dontforgetbirthdayproject.activity.MainActivity;
import com.example.dontforgetbirthdayproject.fragment.HomeFragment;

import java.time.LocalDate;

public class NotificationReceiver extends BroadcastReceiver {

    private String TAG = this.getClass().getSimpleName();

    NotificationManager manager;
    NotificationCompat.Builder builder;

    //오레오 이상은 반드시 채널을 설정해줘야 Notification이 작동함
    private static String CHANNEL_ID = "channel1";
    private static String CHANNEL_NAME = "Channel1";

    //수신되는 인텐트 - The Intent being received.
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e(TAG, "onReceive 알람이 들어옴!!");
        String contentValue ="";
        contentValue= intent.getStringExtra("content");
        int requestCode = intent.getIntExtra("requestCode",0);
        int id = intent.getIntExtra("id",0);
        int day = intent.getIntExtra("day",0);
        int year = intent.getIntExtra("year",0);
        int month = intent.getIntExtra("month",0);
        int hour = intent.getIntExtra("hour",0);
        int minute = intent.getIntExtra("minute",0);
        int alarmStartDay = intent.getIntExtra("alarmStartDay",0);

        Log.e(TAG, "onReceive contentValue값 확인 : " + contentValue);

        builder = null;

        //푸시 알림을 보내기위해 시스템에 권한을 요청하여 생성
        manager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);

        //안드로이드 오레오 버전 대응
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
            manager.createNotificationChannel(
                    new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT)
            );
            builder = new NotificationCompat.Builder(context, CHANNEL_ID);
        } else {
            builder = new NotificationCompat.Builder(context);
        }

        //알림창 클릭 시 지정된 activity 화면으로 이동
        Intent intent2 = new Intent(context, HomeFragment.class);

        // FLAG_UPDATE_CURRENT ->
        // 설명된 PendingIntent가 이미 존재하는 경우 유지하되, 추가 데이터를 이 새 Intent에 있는 것으로 대체함을 나타내는 플래그입니다.
        // getActivity, getBroadcast 및 getService와 함께 사용
        PendingIntent pendingIntent;
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
            pendingIntent = PendingIntent.getActivity(context,requestCode,intent2,
                    PendingIntent.FLAG_UPDATE_CURRENT|PendingIntent.FLAG_MUTABLE);
        } else {
            pendingIntent = PendingIntent.getActivity(context,requestCode,intent2,
                    PendingIntent.FLAG_UPDATE_CURRENT);
        }

        LocalDate now = LocalDate.now(); //현재 날짜 가져오기
        int dday = day-alarmStartDay; //생일 날짜 - 현재날 해서 생일로부터 남은 날 계산
        //알림창 제목
        builder.setContentTitle(contentValue+dday+"일 남았습니다."); //회의명노출
        //builder.setContentText(intent.getStringExtra("content")); //회의 내용
        //알림창 아이콘
        builder.setSmallIcon(R.drawable.cake_alarm_icon);
        //알림창 터치시 자동 삭제
        builder.setAutoCancel(true);

        builder.setContentIntent(pendingIntent);

        //푸시알림 빌드
        Notification notification = builder.build();

        //NotificationManager를 이용하여 푸시 알림 보내기
        manager.notify(id,notification);
        if(day+2- now.getDayOfMonth()>=0){
            Log.d("인수 확인",String.valueOf(year)+String.valueOf(month)+String.valueOf(day)+String.valueOf(hour)+String.valueOf(minute)
                    +String.valueOf(id)+contentValue+String.valueOf(requestCode));
            MainActivity.isPushAlarmSend = true;
        }
    }
}

MainActivity의 setNotice 메소드

//알람매니저에 알람등록 처리
    @RequiresApi(api = Build.VERSION_CODES.O)
    public void setNotice(int year, int month, int alarmStartDay,int day, int hour, int minute, int id, String content, int requestCode) {

        //알람을 수신할 수 있도록 하는 리시버로 인텐트 요청
        Intent receiverIntent = new Intent(this, NotificationReceiver.class);
        receiverIntent.putExtra("content", content);
        receiverIntent.putExtra("requestCode", requestCode);
        receiverIntent.putExtra("id",id);
        receiverIntent.putExtra("year",year);
        receiverIntent.putExtra("month",month);
        receiverIntent.putExtra("day",day);
        receiverIntent.putExtra("alarmStartDay",alarmStartDay);
        receiverIntent.putExtra("hour",hour);
        receiverIntent.putExtra("minute",minute);

        /**
         * PendingIntent란?
         * - Notification으로 작업을 수행할 때 인텐트가 실행되도록 합니다.
         * Notification은 안드로이드 시스템의 NotificationManager가 Intent를 실행합니다.
         * 즉 다른 프로세스에서 수행하기 때문에 Notification으로 Intent수행시 PendingIntent의 사용이 필수 입니다.
         */

        /**
         * 브로드캐스트로 실행될 pendingIntent선언 한다.
         * Intent가 새로 생성될때마다(알람을 등록할 때마다) intent값을 업데이트 시키기 위해, FLAG_UPDATE_CURRENT 플래그를 준다
         * 이전 알람을 취소시키지 않으려면 requestCode를 다르게 줘야 한다.
         * */

        PendingIntent pendingIntent;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            pendingIntent = PendingIntent.getBroadcast(this, requestCode, receiverIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
        } else {
            pendingIntent = PendingIntent.getBroadcast(this, requestCode, receiverIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        }

        //date타입으로 변경된 알람시간을 캘린더 타임에 등록
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1);
        calendar.set(Calendar.DATE, alarmStartDay);
        calendar.set(Calendar.HOUR_OF_DAY,hour);
        calendar.set(Calendar.MINUTE,minute);


        //알람시간 설정
        //param 1)알람의 타입
        //param 2)알람이 울려야 하는 시간(밀리초)을 나타낸다.
        //param 3)알람이 울릴 때 수행할 작업을 나타냄
        LocalDate now = LocalDate.now();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
        } else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
            alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
        } else {
            alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);

        }
       
    }

이것저것 하다보니 접근을 하려면 setNotice 부분에 static을 붙여야 하던데 그러면 PendingIntent 안에 있는 this에 빨간줄이 쳐져서 어떻게 해야할지 모르겠습니다.. 

notificationReceiver에서 푸시알림을 보내고 나면 다시 setNotice에 다음날짜를 넣어서 호출하고 싶은데..

아무리 검색해봐도 자료가 적기도 하고 해답을 찾지 못해서 질문드립니다!

류승민 (270 포인트) 님이 2023년 2월 13일 질문

1개의 답변

+1 추천
 
채택된 답변

BroadcastReceiver라면 Intent를 활용해서 처리하시면 될 것 같아 보입니다.

Intent에 전달하는 날찌시간은 클래스를 하나 만들거나 Calendar를 넘기시면 코드관리가 편해집니다.

public class MyAlarm implements Serializable {
     private int id = 0;
     private int year = 0;
     private int month = 0;
     private int date = 0;
     private int hour = 0;
     private int minute = 0;
     private int alarmStartDay = 0;
     private int requestCode = 0;

     private String content = "";

     // 생성자(들), Getter, Setter 생략

    public Celenar toCalendar() {
         ...
    }
}

public class NotificationReceiver extends BroadcastReceiver {
 
    ...
 
    private NotificationManager manager;
    private NotificationCompat.Builder builder;
 
    ...
 
    //수신되는 인텐트 - The Intent being received.
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e(TAG, "onReceive 알람이 들어옴!!");
        MyAlarm myAlarm = intent.getSerializableExtra("date", MyAlarm::class.java)
 
        Log.e(TAG, "onReceive myAlarm : " + myAlarm);
 
       
        Intent homeIntent = createHomeIntent(myAlarm, 2);

        builder = createNoficiationBuilder(myAlarm, homeIntent);
 
        //푸시알림 빌드
        Notification notification = builder.build();
        //NotificationManager를 이용하여 푸시 알림 보내기
        manager.notify(id,notification);
        
    }

    private NotificationCompat.Builder createNoficiationBuilder(MyAlaram: myAlaram) {
       ...
    }


    private Intent createHomeIntent(MyAlaram: myAlaram, int thresholdDay) {
         Intent intent = new Intent(context, HomeActivity.class);
         
         ...       

         boolean isExtraAlaram = day + thresholdDay - now.getDayOfMonth() >= 0;
         if(isExtraAlaram){
            Log.d("인수 확인",String.valueOf(year)+String.valueOf(month)+String.valueOf(day)+String.valueOf(hour)+String.valueOf(minute)
                    +String.valueOf(id)+contentValue+String.valueOf(requestCode));
             // TODO : 추가알람에 대한 설정
        } else {
             // TODO : 최초알람에 대한 설정
        }
        return intent;
    }

        
    private PendingIntent createPendingIntent(MyAlaram: myAlaram) {
       ...
    }
}

코드는 발향성을 제시하는 용도이므로. 참고하셔서 필요한 부분을 수정해서 사용하세요.

위처럼, 액티비티에 넘기는 Intent를 만들 때, 최초알람과 추가알람에 대한 Intent의 내용을 구분해서 작성하시면 액티비티에서는 단순히 받아서 처리만하면 될 것 같아보입니다. Alaramanager를 설정하는 부분이 BroadcastReceiver 에 위치하는게 적절하지 않을 수 있는데, 이 경우는 이 부분만 떼어서 액티비티에서 처리해도 될 듯합니다.

 

spark (226,720 포인트) 님이 2023년 2월 13일 답변
류승민님이 2023년 2월 21일 채택됨
...