দৈনিক রিমাইন্ডার নোটিফিকেশন বাস্তবায়ন
এই গাইডটি দেখাবে কীভাবে একটি নির্দিষ্ট সময়ে প্রতিদিন নোটিফিকেশন দেখাতে হয়। আমরা AlarmManager এবং Service ব্যবহার করে একটি রিমাইন্ডার সিস্টেম তৈরি করব যা ডিভাইস রিবুট হওয়ার পরেও কাজ করবে।
ফিচার সমূহ
- প্রতিদিন নির্দিষ্ট সময়ে নোটিফিকেশন
- ডিভাইস রিবুট টলérant (BootCompleteReceiver দিয়ে)
- নোটিফিকেশন চ্যানেল সাপোর্ট (Android 8.0+)
- ব্যবহারকারী তাকিয়ে দিতে পারবে কাস্টম সময়
ধাপ ১: প্রজেক্ট তৈরি
Package: com.example.remindernotification
ধাপ ২: লেআউট (activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="রিমাইন্ডার সময় নির্বাচন করুন:"
android:textSize="18sp"
android:layout_marginBottom="16dp"/>
<Button
android:id="@+id/btnTimePicker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="সময় বেছে নিন"
android:onClick="showTimePicker"/>
<Button
android:id="@+id/btnEnable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="রিমাইন্ডার চালু করুন"
android:onClick="enableReminder"/>
<TextView
android:id="@+id/tvSelectedTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="নির্বাচিত সময়: কোনো সময় নির্বাচিত নেই"
android:textSize="16sp"/>
</LinearLayout>
ধাপ ৩: TimePickerFragment.java
package com.example.remindernotification;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import java.util.Calendar;
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(requireActivity(),
(TimePickerDialog.OnTimeSetListener) requireActivity(),
hour, minute, true);
}
}
ধাপ ৪: MainActivity.java
package com.example.remindernotification;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Calendar;
public class MainActivity extends AppCompatActivity
implements TimePickerDialog.OnTimeSetListener {
private static final String PREFS_NAME = "ReminderPrefs";
private static final String KEY_HOUR = "reminder_hour";
private static final String KEY_MINUTE = "reminder_minute";
private static final String KEY_ENABLED = "reminder_enabled";
private TextView tvSelectedTime;
private int selectedHour = 9, selectedMinute = 0;
private AlarmManager alarmManager;
private PendingIntent pendingIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvSelectedTime = findViewById(R.id.tvSelectedTime);
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
// সেভ করা সময় লোড করুন
loadSavedTime();
updateTimeDisplay();
}
public void showTimePicker(View view) {
new TimePickerFragment().show(getSupportFragmentManager(), "timePicker");
}
@Override
public void onTimeSet(android.widget.TimePicker view, int hourOfDay, int minute) {
selectedHour = hourOfDay;
selectedMinute = minute;
saveTime();
updateTimeDisplay();
}
public void enableReminder(View view) {
scheduleDailyReminder();
saveEnabledState(true);
findViewById(R.id.btnEnable).setEnabled(false);
findViewById(R.id.btnTimePicker).setEnabled(false);
}
private void scheduleDailyReminder() {
Intent intent = new Intent(this, ReminderService.class);
pendingIntent = PendingIntent.getService(
this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, selectedHour);
calendar.set(Calendar.MINUTE, selectedMinute);
calendar.set(Calendar.SECOND, 0);
// যদি সময় পাস হয়ে গেছে, পরের দিনের জন্য সেট করুন
if (calendar.getTimeInMillis() <= System.currentTimeMillis()) {
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
long interval = 1000L * 60 * 60 * 24; // ২৪ ঘণ্টা
if (alarmManager != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
interval,
pendingIntent
);
} else {
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
interval,
pendingIntent
);
}
}
}
private void loadSavedTime() {
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
selectedHour = prefs.getInt(KEY_HOUR, 9);
selectedMinute = prefs.getInt(KEY_MINUTE, 0);
}
private void saveTime() {
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
prefs.edit()
.putInt(KEY_HOUR, selectedHour)
.putInt(KEY_MINUTE, selectedMinute)
.apply();
}
private void saveEnabledState(boolean enabled) {
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
prefs.edit().putBoolean(KEY_ENABLED, enabled).apply();
}
private void updateTimeDisplay() {
String time = String.format("%02d:%02d", selectedHour, selectedMinute);
tvSelectedTime.setText("নির্বাচিত সময়: " + time);
}
}
ধাপ ৫: ReminderService.java
package com.example.remindernotification;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import androidx.core.app.NotificationCompat;
public class ReminderService extends Service {
private static final String CHANNEL_ID = "reminder_channel";
private static final String DEFAULT_CHANNEL = "default";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
showReminderNotification();
stopSelf();
return START_NOT_STICKY;
}
private void showReminderNotification() {
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, DEFAULT_CHANNEL)
.setContentTitle("রিমাইন্ডার")
.setContentText("আপনার নিশ্চিত কাজের সময় হয়েছে!")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_REMINDER);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID, "রিমাইন্ডার নোটিফিকেশন",
NotificationManager.IMPORTANCE_HIGH);
channel.setDescription("দৈনিক রিমাইন্ডার নোটিফিকেশন");
manager.createNotificationChannel(channel);
builder.setChannelId(CHANNEL_ID);
}
manager.notify(1001, builder.build());
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
ধাপ ৬: BootCompleteReceiver.java (রিবুট Efter রিস্টার্ট)
package com.example.remindernotification;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import java.util.Calendar;
public class BootCompleteReceiver extends BroadcastReceiver {
private static final String PREFS_NAME = "ReminderPrefs";
private static final String KEY_HOUR = "reminder_hour";
private static final String KEY_MINUTE = "reminder_minute";
private static final String KEY_ENABLED = "reminder_enabled";
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
boolean enabled = prefs.getBoolean(KEY_ENABLED, false);
if (enabled) {
int hour = prefs.getInt(KEY_HOUR, 9);
int minute = prefs.getInt(KEY_MINUTE, 0);
scheduleReminder(context, hour, minute);
}
}
}
private void scheduleReminder(Context context, int hour, int minute) {
Intent serviceIntent = new Intent(context, ReminderService.class);
PendingIntent pendingIntent = PendingIntent.getService(
context, 0, serviceIntent, PendingIntent.FLAG_IMMUTABLE);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, 0);
if (calendar.getTimeInMillis() <= System.currentTimeMillis()) {
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
long interval = 1000L * 60 * 60 * 24;
if (alarmManager != null) {
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
interval,
pendingIntent
);
}
}
}
ধাপ ৭: AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.remindernotification">
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<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/Theme.ReminderNotification">
<service
android:name=".ReminderService"
android:enabled="true"
android:exported="false" />
<receiver
android:name=".BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
আধুনিক বিকল্প: WorkManager + Exact Alarm (সুপারিশ করা)
আধুনিক Android-এ (API 23+) WorkManager সহ setExactAndAllowWhileIdle বা setAlarmClock ব্যবহার করা ভালো। এটি ব্যাটারি অপ্টিমাইজেশন, ডজ মোড, এবং সিস্টেম হেলথের সাথে কম্প্যাটিবল।
পরীক্ষা চেকলিস্ট
- অ্যাপ খুলুন → সময় বেছে নিন → "রিমাইন্ডার চালু করুন" চাপুন
- ডিভাইস রিবুট করুন → নির্দিষ্ট সময়ে নোটিফিকেশন আসছে কিনা চেক করুন
- নোটিফিকেশন ট্যাপ করলে MainActivity খুলছে কিনা
- ব্যাটারি সেভার অন থাকলে ও কাজ করছে কিনা (SCHEDULE_EXACT_ALARM permission দরকার)