我想在我的项目中实现一个时间表功能。所以我在谷歌上搜索了一个警报管理程序,但我找不到任何例子。

谁能帮我一个基本的警报管理程序?


当前回答

我尝试了XXX的解决方案,虽然它最初确实有效,但在某种程度上它停止了工作。onReceive再也没有被调用。我花了好几个小时想知道那是什么。我开始意识到,出于某种神秘的原因,意图不再被召唤。为了解决这个问题,我发现确实需要在清单中为接收者指定一个操作。例子:

<receiver android:name=".Alarm" android:exported="true">
    <intent-filter>
        <action android:name="mypackage.START_ALARM" >
        </action>
    </intent-filter>
</receiver> 

请注意,名称是“。“Alarm”和周期。在XXX的setAlarm方法中,创建Intent,如下所示:

Intent i = new Intent("mypackage.START_ALARM");

START_ALARM消息可以是您想要的任何消息。我这样命名只是为了演示。

I have not seen receivers defined in the manifest without an intent filter that specifies the action. Creating them the way XXX has specified it seems kind of bogus. By specifying the action name, Android will be forced to create an instance of the BroadcastReceiver using the class that corresponds to the action. If you rely upon context, be aware that Android has several different objects that are ALL called context and may not result in getting your BroadcastReceiver created. Forcing Android to create an instance of your class using only the action message is far better than relying upon some iffy context that may never work.

其他回答

•AlarmManager与IntentService结合使用

我认为使用AlarmManager的最佳模式是它与IntentService的协作。IntentService由AlarmManager触发,它通过接收意图处理所需的操作。这种结构不像使用BroadcastReceiver那样对性能有影响。我在kotlin中为这个想法开发了一个示例代码,可以在这里获得:

MyAlarmManager.kt

import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent

object MyAlarmManager {

    private var pendingIntent: PendingIntent? = null

    fun setAlarm(context: Context, alarmTime: Long, message: String) {
        val alarmManager: AlarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager

        val intent = Intent(context, MyIntentService::class.java)
        intent.action = MyIntentService.ACTION_SEND_TEST_MESSAGE
        intent.putExtra(MyIntentService.EXTRA_MESSAGE, message)

        pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        alarmManager.set(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent)
    }

    fun cancelAlarm(context: Context) {
        pendingIntent?.let {
            val alarmManager: AlarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
            alarmManager.cancel(it)
        }
    }

}

MyIntentService.kt

import android.app.IntentService
import android.content.Intent

class MyIntentService : IntentService("MyIntentService") {

    override fun onHandleIntent(intent: Intent?) {
        intent?.apply {
            when (intent.action) {
                ACTION_SEND_TEST_MESSAGE -> {
                    val message = getStringExtra(EXTRA_MESSAGE)
                    println(message)
                }
            }
        }
    }

    companion object {
        const val ACTION_SEND_TEST_MESSAGE = "ACTION_SEND_TEST_MESSAGE"
        const val EXTRA_MESSAGE = "EXTRA_MESSAGE"
    }

}

manifest.xml

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

    <application
        ... >

    <service
        android:name="path.to.MyIntentService"
        android:enabled="true"
        android:stopWithTask="false" />

    </application>

</manifest>

用法:

val calendar = Calendar.getInstance()
calendar.add(Calendar.SECOND, 10)
MyAlarmManager.setAlarm(applicationContext, calendar.timeInMillis, "Test Message!")

如果你想取消预定的闹钟,试试这个:

MyAlarmManager.cancelAlarm(applicationContext)

报警经理:

添加到XML布局(*初始化这些视图在创建在主活动)

  <TimePicker
    android:id="@+id/timepicker"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="2"></TimePicker>

  <Button
    android:id="@+id/btn_start"
    android:text="start Alarm"
    android:onClick="start_alarm_event"
    android:layout_width="match_parent"
    android:layout_height="52dp" />

添加到清单(内部应用程序标签&&外部活动)

 <receiver android:name=".AlarmBroadcastManager"
        android:enabled="true"
        android:exported="true"/>

创建AlarmBroadcastManager类(从BroadcastReceiver继承)

 public class AlarmBroadcastManager extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
      MediaPlayer mediaPlayer=MediaPlayer.create(context,Settings.System.DEFAULT_RINGTONE_URI);
      mediaPlayer.start();
    }
 }

在Main Activity中(添加这些功能):

 @RequiresApi(api = Build.VERSION_CODES.M)
 public  void start_alarm_event(View view){
    Calendar calendar=Calendar.getInstance();
    calendar.set(
    calendar.get(Calendar.YEAR),
    calendar.get(Calendar.MONTH),
    calendar.get(Calendar.DAY_OF_MONTH),
    timePicker.getHour(),
    timePicker.getMinute(),
    0
    );
    setAlarm(calendar.getTimeInMillis());
 }

 public void setAlarm(long timeInMillis){
    AlarmManager alarmManager=(AlarmManager) getSystemService(Context.ALARM_SERVICE);
    Intent intent=new Intent(this,AlarmBroadcastManager.class);
    PendingIntent pendingIntent=PendingIntent.getBroadcast(this,0,intent,0);
     alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,timeInMillis,AlarmManager.INTERVAL_DAY,pendingIntent);
    Toast.makeText(getApplicationContext(),"Alarm is Set",Toast.LENGTH_SHORT).show();


 }

这段代码将帮助您制作重复警报。重复时间可由您设置。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
     <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical" 
     android:background="#000000"
     android:paddingTop="100dp">

    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center" >

    <EditText
        android:id="@+id/ethr"
    android:layout_width="50dp"
    android:layout_height="wrap_content"
    android:ems="10"
    android:hint="Hr"
    android:singleLine="true" >


        <requestFocus />
    </EditText>

    <EditText
        android:id="@+id/etmin"
    android:layout_width="55dp"
    android:layout_height="wrap_content"

    android:ems="10"
    android:hint="Min"
    android:singleLine="true" />

    <EditText
        android:id="@+id/etsec"
    android:layout_width="50dp"
    android:layout_height="wrap_content"

    android:ems="10"
    android:hint="Sec"
    android:singleLine="true" />

    </LinearLayout>

   <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content" 
    android:gravity="center"
    android:paddingTop="10dp">


    <Button
        android:id="@+id/setAlarm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClickSetAlarm"
        android:text="Set Alarm" />

</LinearLayout>

</LinearLayout>

MainActivity.java

public class MainActivity extends Activity {
    int hr = 0;
    int min = 0;
    int sec = 0;
    int result = 1;

    AlarmManager alarmManager;
    PendingIntent pendingIntent;
    BroadcastReceiver mReceiver;

    EditText ethr;
    EditText etmin;
    EditText etsec;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ethr = (EditText) findViewById(R.id.ethr);
        etmin = (EditText) findViewById(R.id.etmin);
        etsec = (EditText) findViewById(R.id.etsec);
        RegisterAlarmBroadcast();
    } 

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    protected void onDestroy() {
        unregisterReceiver(mReceiver);
        super.onDestroy();
    }

    public void onClickSetAlarm(View v) {
        String shr = ethr.getText().toString();
        String smin = etmin.getText().toString();
        String ssec = etsec.getText().toString();

        if(shr.equals("")) 
            hr = 0;
        else {
            hr = Integer.parseInt(ethr.getText().toString());
            hr=hr*60*60*1000;
        }

        if(smin.equals(""))
            min = 0;
        else {
            min = Integer.parseInt(etmin.getText().toString());
            min = min*60*1000;
        }

        if(ssec.equals(""))
            sec = 0;
        else {
             sec = Integer.parseInt(etsec.getText().toString());
             sec = sec * 1000;
        }
        result = hr+min+sec;
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), result , pendingIntent); 
    }

    private void RegisterAlarmBroadcast() {
        mReceiver = new BroadcastReceiver() {
            // private static final String TAG = "Alarm Example Receiver";
            @Override
            public void onReceive(Context context, Intent intent) {
                Toast.makeText(context, "Alarm time has been reached", Toast.LENGTH_LONG).show();
            }
        };

        registerReceiver(mReceiver, new IntentFilter("sample"));
        pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent("sample"), 0);
        alarmManager = (AlarmManager)(this.getSystemService(Context.ALARM_SERVICE));
    }

    private void UnregisterAlarmBroadcast() {
        alarmManager.cancel(pendingIntent); 
        getBaseContext().unregisterReceiver(mReceiver);
    }
}

如果你只需要报警一次,那么更换

alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), result , pendingIntent);

with

 alarmManager.set( AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + result , pendingIntent );

这是工作代码。它每10分钟唤醒一次CPU,直到手机关机。

添加到Manifest.xml:

...
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
...
<receiver android:process=":remote" android:name=".Alarm"></receiver>
...

类中的代码:

package yourPackage;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.widget.Toast;

public class Alarm extends BroadcastReceiver 
{    
    @Override
    public void onReceive(Context context, Intent intent) 
    {   
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
        wl.acquire();

        // Put here YOUR code.
        Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); // For example

        wl.release();
    }

    public void setAlarm(Context context)
    {
        AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        Intent i = new Intent(context, Alarm.class);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
        am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 10, pi); // Millisec * Second * Minute
    }

    public void cancelAlarm(Context context)
    {
        Intent intent = new Intent(context, Alarm.class);
        PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(sender);
    }
}

设置来自服务的告警:

package yourPackage;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;

public class YourService extends Service
{
    Alarm alarm = new Alarm();
    public void onCreate()
    {
        super.onCreate();       
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 
    {
        alarm.setAlarm(this);
        return START_STICKY;
    }

   @Override        
   public void onStart(Intent intent, int startId)
    {
        alarm.setAlarm(this);
    }

    @Override
    public IBinder onBind(Intent intent) 
    {
        return null;
    }
}

如果您想设置开机时重复闹铃:

将权限和服务添加到Manifest.xml:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>
...
<receiver android:name=".AutoStart">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"></action>
    </intent-filter>
</receiver>
...
<service
        android:name=".YourService"
        android:enabled="true"
        android:process=":your_service" >
</service>

并创建一个新类:

package yourPackage;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class AutoStart extends BroadcastReceiver
{   
    Alarm alarm = new Alarm();
    @Override
    public void onReceive(Context context, Intent intent)
    {   
        if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED))
        {
            alarm.setAlarm(context);
        }
    }
}

这里有一个相当独立的例子。5秒后按钮变为红色。

    public void SetAlarm()
    {
        final Button button = buttons[2]; // replace with a button from your own UI
        BroadcastReceiver receiver = new BroadcastReceiver() {
            @Override public void onReceive( Context context, Intent _ )
            {
                button.setBackgroundColor( Color.RED );
                context.unregisterReceiver( this ); // this == BroadcastReceiver, not Activity
            }
        };

        this.registerReceiver( receiver, new IntentFilter("com.blah.blah.somemessage") );

        PendingIntent pintent = PendingIntent.getBroadcast( this, 0, new Intent("com.blah.blah.somemessage"), 0 );
        AlarmManager manager = (AlarmManager)(this.getSystemService( Context.ALARM_SERVICE ));

        // set alarm to fire 5 sec (1000*5) from now (SystemClock.elapsedRealtime())
        manager.set( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 1000*5, pintent );
    }

请记住,即使在应用程序未运行时,AlarmManager也会触发。如果你调用这个函数并点击Home键,等待5秒,然后回到你的应用程序,按钮将变成红色。

我不知道如果你的应用程序根本不在内存中,你会得到什么样的行为,所以要小心你试图保存什么样的状态。