zoukankan      html  css  js  c++  java
  • Android 结合AlarmManager浅谈Intent和PendingIntent

    首先简单说一下AlarmManager,AlarmManager的机制:全局定时器(又称为闹钟),在特定的时刻为我们广播一个指定的Intent,两种形式:

    1.在指定的时刻到来时执行某项操作,如你已经设定了一个闹钟时间,当该时间到来时,AlarmManager就为我们广播一个已设定的Intent,通过这个intent来执行一些操作[实际上是PendingIntent]

    2.以指定的时间间隔周期性的执行某项操作,这个就不解释了

     

    AlarmManager的闹钟类型及方法:

    Android系统提供了四种类型的闹钟:

    (1)ELAPSED_REALTIME:在指定的延时之后发送Intent,但不唤醒设备

    (2)ELAPSED_REALTIME_WAKEUP:在指定的延时之后发送Intent,同时唤醒设备

            延时是会把系统启动的时间SystemClock.elapsedRealtime()算进去!!

    (3)RTC:在指定的时刻发送Intent,但不唤醒设备

    (4)RTC_WAKEUP:在指定的时刻发送Intent,同时唤醒设备

     

    AlarmManager的方法:

    (1)、void set(int type, long triggerAtTime, PendingIntent operation)
    注册一个闹钟


    (2)、void setRepeating(int type, long triggerAtTime, long interval, PendingIntent operation)
    注册一个会重复的闹钟


    (3)、void setInexactRepeating(int type, long triggerAtTime, long interval, PendingIntent operation)
    注册一个重复闹钟的不精确版本,它相对而言更节能(power-efficient)一些,因为系统可能会将几个差不多的闹钟合并为一个来执行,减少设备的唤醒次数。

    内置的几个interval为:
    INTERVAL_FIFTEEN_MINUTES
    INTERVAL_HALF_HOUR
    INTERVAL_HOUR
    INTERVAL_HALF_DAY
    INTERVAL_DAY
    如果你将其设为DAY,那么可能这一天中的所有闹钟都会被合并掉。

    (4)、void cancel(PendingIntent operation)
    取消一个注册的闹钟


    (5)、void setTimeZone(String timeZone)
    设置系统的默认时区。需要android.permission.SET_TIME_ZONE权限

     

    (5)、voidsetTime(long millis)

    设置系统挂钟时间,需要android.permission.SET_TIME权限

     

    下面步入正题:

    Intent和PendingIntent的关系 :

       Intent是一个意图,一个描述了想要启动一个Activity、Broadcast或是Service的意图。它主要持有的信息是它想要启动的组件(Activity、Broadcast或是Service),在开发操作中,需要通过 startActivity , startService 或sendBroadcast 方法来启动这个意图执行某些操作!!

      PendingIntent可以认为是对Intent的包装,实际上就是,供当前App或之外的其他App调用,而常见的是供外部App使用,外部App执行这个 PendingIntent时,间接地调用里面的Intent,即外部App延时执行PendingIntent中描述的Intent及其最终行为,PendingIntent主要持有的信息是它所包装的Intent和当前App Context,即使当前App已经不存在了,也能通过存在于PendingIntent里的 Context来执行Intent。当你把PendingIntent递交给别的程序进行处理时,PendingIntent仍然拥有PendingIntent原程序所拥有的权限,当你从系统取得一个PendingIntent时,一定要非常小心才行,比如,通常,如果Intent目的地是你自己的component(Activity/Service/BroadcastReceiver)的话,你最好采用在Intent中显示指定目的component名字的方式,以确保Intent最终能发到目的,否则Intent最后可能不知道发到哪里了。

    可以这样理解:当你想在Aactivity中启动另一个Bactivity,那么你可以选择两种情况[立即启动或延时启动]:
    1.通过intent配置需要启动的Bactivity,然后调用startActivity()方法,让他立即执行启动操作,跳转过去
    2.另一种情况是,你虽然想启动另一个Bactivity,可是你并不想马上跳转到Bactivity页面,你想静等5分钟之后再跳转到Bactivity,那么你可以通过PendingIntent来实现[当然实现方式有很多啦,这里仅是想说明PendingIntent与intent的区别],PendingIntent可以包装第1步中的intent,然后通过AlarmManager这个定时器,定制5分钟之后启PendingIntent,实现这种延时操作,如果你还是听着似懂非懂,一头雾水,我表示很有压力了,我该怎么说你才能清楚呢,理论终究是抽象的,后见将会通过一个程序说明一下,程序中是启动一个BroadcastReceiver,其实原理都是一样的!!

    如何获得一个PendingIntent呢?其实很简单:
    1.你可以通过getActivity(Context context, int requestCode, Intent intent, int flags)系列方法从系统

    取得一个用于启动一个Activity的PendingIntent对象
    2.可以通过getService(Context context, int requestCode, Intent intent, int flags)方法从系统取得一个

    用于启动一个Service的PendingIntent对象
    3.可以通过getBroadcast(Context context, int requestCode, Intent intent, int flags)方法从系统取得一

    个用于向BroadcastReceiver的发送广播的PendingIntent对象

    PendingIntent几个常量:

    1.FLAG_CANCEL_CURRENT :如果AlarmManager管理的PendingIntent已经存在,那么将会取消当前的

    PendingIntent,从而创建一个新的PendingIntent
    2.FLAG_UPDATE_CURRENT:如果AlarmManager管理的PendingIntent已经存在,可以让新的Intent更新之前

    PendingIntent中的Intent对象数据,例如更新Intent中的Extras,另外,我们也可以在PendingIntent的原进程

    中调用PendingIntent的cancel ()把其从系统中移除掉
    3.FLAG_NO_CREATE :如果AlarmManager管理的PendingIntent已经存在,那么将不进行任何操作,直接返回已经

    存在的PendingIntent,如果PendingIntent不存在了,那么返回null

    代码贴上:

    1.MainActivity.java:

    package com.test.Alarm;
    
    import com.test.Alarm.R;
    
    import android.app.Activity;
    import android.app.AlarmManager;
    import android.app.PendingIntent;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.os.SystemClock;
    import android.util.Log;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.TextView;
    
    public class MainActivity extends Activity {
    	private Button msetButton;
    	private Button mcancelButton;
    	private TextView mTextView;
    	private final int REQUEST_CODE_0 = 0;
    	private final int REQUEST_CODE_1 = 1;
    
    	/** Called when the activity is first created. */
    	@Override
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		mTextView = (TextView) this.findViewById(R.id.mText);
    		msetButton = (Button) this.findViewById(R.id.setTimeButton);
    		mcancelButton = (Button) findViewById(R.id.cancelButton);
    
    		msetButton.setOnClickListener(new OnClickListener() {
    
    			@Override
    			public void onClick(View v) {
    				AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    				Intent intent = new Intent(getApplicationContext(),
    						AlermReceiver.class);
    				intent.putExtra("flag", true);
    				// 创建2个PendingIntent
    				PendingIntent setPendIntent0 = PendingIntent.getBroadcast(
    						getApplicationContext(), REQUEST_CODE_0, intent,
    						PendingIntent.FLAG_UPDATE_CURRENT);
    				Log.e("FLAG_UPDATE_CURRENT-->setPendIntent0:", setPendIntent0
    						+ "");
    
    				PendingIntent setPendIntent1 = PendingIntent.getBroadcast(
    						getApplicationContext(), REQUEST_CODE_1, intent,
    						PendingIntent.FLAG_UPDATE_CURRENT);
    				Log.e("FLAG_UPDATE_CURRENT-->setPendIntent1:", setPendIntent1
    						+ "");
    
    				// 5秒后发送广播,然后每隔10秒重复发广播
    				int triggerAtTime = (int) (SystemClock.elapsedRealtime() + 5 * 1000);
    				int interval = 10 * 1000;
    
    				// 注册以上创建的2个PendingIntent,每隔10秒重复发广播
    				alarmMgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
    						triggerAtTime, interval, setPendIntent0);
    				alarmMgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
    						triggerAtTime, interval, setPendIntent1);
    
    				// alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
    				// triggerAtTime, pendIntent1);
    
    			}
    		});
    		mcancelButton.setOnClickListener(new OnClickListener() {
    
    			@Override
    			public void onClick(View v) {
    
    				AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    				Intent intent = new Intent(getApplicationContext(),
    						AlermReceiver.class);
    				intent.putExtra("flag", false);
    				PendingIntent StopPendIntent0 = PendingIntent.getBroadcast(
    						getApplicationContext(), REQUEST_CODE_0, intent,
    						PendingIntent.FLAG_UPDATE_CURRENT);
    
    				/**
    				 * 如果你想更新putExtra中flag的值为false,那么你必须通过alarmMgr的setxxx()方法再注册一次,
    				 * 相当于更新已经存在的intent,如果不这样做,你就无法达到更新的目的,像这样:
    				 * 
    				 * alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 0,
    				 * StopPendIntent0);
    				 * 
    				 * 然后你再执行alarmMgr.cancel(StopPendIntent0);取消掉
    				 * 
    				 * 这个可能就是你通过flag这个标志启动了一个闹钟,并响铃了,又想通过flag来关闭闹钟却咋都不能关闭的原因,
    				 * 问题可能就在这里, 因为实际上你没有更新数据
    				 */
    				// alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 0,
    				// StopPendIntent0);
    
    				Log.e("FLAG_UPDATE_CURRENT-->StopPendIntent0:", StopPendIntent0
    						+ "");
    				alarmMgr.cancel(StopPendIntent0);
    
    				// 以下仅是为了演示PendingIntent几个常量的区别
    				PendingIntent StopPendIntent1 = PendingIntent.getBroadcast(
    						getApplicationContext(), REQUEST_CODE_1, intent,
    						PendingIntent.FLAG_UPDATE_CURRENT);
    				Log.e("FLAG_UPDATE_CURRENT-->StopPendIntent1:", StopPendIntent1
    						+ "");
    				alarmMgr.cancel(StopPendIntent1);
    
    				PendingIntent StopPendIntent11 = PendingIntent.getBroadcast(
    						getApplicationContext(), REQUEST_CODE_1, intent,
    						PendingIntent.FLAG_NO_CREATE);
    				Log.e("FLAG_NO_CREATE------->StopPendIntent11:",
    						StopPendIntent11 + "");
    				alarmMgr.cancel(StopPendIntent11);
    
    				PendingIntent StopPendIntent12 = PendingIntent.getBroadcast(
    						getApplicationContext(), REQUEST_CODE_1, intent,
    						PendingIntent.FLAG_CANCEL_CURRENT);
    				Log.e("FLAG_CANCEL_CURRENT-->StopPendIntent12:",
    						StopPendIntent12 + "");
    				alarmMgr.cancel(StopPendIntent12);
    
    				PendingIntent StopPendIntent13 = PendingIntent.getBroadcast(
    						getApplicationContext(), REQUEST_CODE_1, intent,
    						PendingIntent.FLAG_ONE_SHOT);
    				Log.e("FLAG_ONE_SHOT-------->StopPendIntent13:",
    						StopPendIntent13 + "");
    				alarmMgr.cancel(StopPendIntent13);
    			}
    		});
    	}
    }


    2.广播监听:

    package com.test.Alarm;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.util.Log;
    import android.widget.Toast;
    
    public class AlermReceiver extends BroadcastReceiver {
    
    	@Override
    	public void onReceive(Context context, Intent intent) {
    
    		Bundle bundle = intent.getExtras();
    		Toast.makeText(context, "进入闹钟BroadcastReceiver", 100).show();
    		if (bundle != null) {
    			Log.i("AlermReceiver:", String.valueOf(bundle.getBoolean("flag")));
    			if (bundle.getBoolean("flag")) {
    				// 开启闹钟操作
    				Toast.makeText(context, "开启", 100).show();
    			} else {
    				// 关闭闹钟操作
    				Toast.makeText(context, "关闭", 100).show();
    			}
    		}
    	}
    }


    3.主页面activity_main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
    
        <TextView
            android:id="@+id/mText"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello" />
    
        <Button
            android:id="@+id/setTimeButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/setTimeButton" />
    
        <Button
            android:id="@+id/cancelButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/cancelButton" />
    
    </LinearLayout>

    最后别忘了再AndroidManifest.xml中注册广播

     <receiver android:name="com.test.Alarm.AlermReceiver"/>

    运行一下:

    通过打印日志,就可以看出PendingIntent几个常量的大致区别啦!!

     

  • 相关阅读:
    codeforce842c Ilya And The Tree
    UVA11825 Hackers' Crackdown
    UVA10635 Prince and Princess
    hihocoder1327 分隔相同字符贪心
    2018 Multi-University Training Contest 3 1003 / hdu6321 Problem C. Dynamic Graph Matching 状压dp
    2018 Multi-University Training Contest 3 1001 / hdu6319 Problem A. Ascending Rating 单调队列,思维
    第十四届华中科技大学程序设计竞赛决赛同步赛
    The 15th Zhejiang Provincial Collegiate Programming Contest Sponsored by TuSimple / ZOJ4027 Sequence Swapping dp递推
    gym101485G/BZOJ4430 Guessing Camels赌骆驼 树状数组或CDQ分治
    2018 ACM-ICPC 中国大学生程序设计竞赛线上赛 Clever King 最大权闭合子图
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3113069.html
Copyright © 2011-2022 走看看