AndroidManifest

 Android开发学习笔记:Intent的简介以及属性的详解
2011-08-08 17:20:48
原创作品,允许转载,转载时请务必以超链接形式标明文章  原始出处 、作者信息和本声明。否则将追究法律责任。 http://liangruijun.blog.51cto.com/3061169/634411

一.Intent的介绍

Intent的中文意思是“意图,意向”,在Android中提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。Intent不仅可用于应用程序之间,也可用于应用程序内部的Activity/Service之间的交互。因此,可以将Intent理解为不同组件之间通信的“媒介”专门提供组件互相调用的相关信息。

二.Inten启动组件的方法

Intent可以启动一个Activity,也可以启动一个Service,还可以发起一个广播Broadcasts。具体方法如下:

组件名称

方法名称

 

Activity

startActvity( )

startActivity( )

 

Service

startService( )

bindService( )

 

Broadcasts

sendBroadcasts( )

sendOrderedBroadcasts( )

sendStickyBroadcasts( )

三.Intent的属性

Intent有以下几个属性:

动作(Action),数据(Data),分类(Category),类型(Type),组件(Compent)以及扩展信(Extra)。其中最常用的是Action属性和Data属性。

1.Intent的Action属性

Action是指Intent要完成的动作,是一个字符串常量。SDK中定义了一些标准的Action常量如下表所示。

Constant

Target component

Action

ACTION_CALL

activity

Initiate a phone call.

ACTION_EDIT

activity

Display data for the user to edit.

ACTION_MAIN

activity

Start up as the initial activity of a task, with no data input and no returned output.

ACTION_SYNC

activity

Synchronize data on a server with data on the mobile device.

ACTION_BATTERY_LOW

broadcast receiver

A warning that the battery is low.

ACTION_HEADSET_PLUG

broadcast receiver

A headset has been plugged into the device, or unplugged from it.

ACTION_SCREEN_ON

broadcast receiver

The screen has been turned on.

ACTION_TIMEZONE_CHANGED

broadcast receiver

The setting for the time zone has changed.

 下面是一个测试Action常量的例子:

main.xml

    
    
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:orientation="vertical" 
  4.     android:layout_width="fill_parent" 
  5.     android:layout_height="fill_parent" 
  6.     > 
  7.     <TextView    
  8.         android:layout_width="fill_parent"   
  9.         android:layout_height="wrap_content"   
  10.         android:text="@string/hello" 
  11.         /> 
  12.     <Button   
  13.         android:text="测试Action属性" 
  14.         android:id="@+id/getBtn" 
  15.         android:layout_width="wrap_content"   
  16.         android:layout_height="wrap_content"   
  17.         /> 
  18. </LinearLayout> 

 strings.xml

    
    
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <resources> 
  3.     <string name="hello">测试Action属性</string> 
  4.     <string name="app_name">IntentActionDemo</string> 
  5. </resources> 

MainActivity.java

    
    
  1. package com.android.action.activity;  
  2.  
  3. import android.app.Activity;  
  4. import android.content.Intent;  
  5. import android.os.Bundle;  
  6. import android.view.View;  
  7. import android.view.View.OnClickListener;  
  8. import android.widget.Button;  
  9.  
  10. public class MainActivity extends Activity {  
  11.     private Button getBtn;  
  12.     @Override 
  13.     public void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.main);  
  16.           
  17.         getBtn=(Button)findViewById(R.id.getBtn);  
  18.         getBtn.setOnClickListener(new OnClickListener() {  
  19.             @Override 
  20.             public void onClick(View v) {     
  21.                 Intent intent = new Intent();                 
  22.                 intent.setAction(Intent.ACTION_GET_CONTENT);// 设置Intent Action属性                  
  23.                 intent.setType("vnd.android.cursor.item/phone");// 设置Intent Type 属性   
  24.                                                                 //主要是获取通讯录的内容  
  25.                 startActivity(intent); // 启动Activity  
  26.             }  
  27.         });          
  28.     }  

效果图:

2.Intent的Data属性

Intent的Data属性是执行动作的URI和MIME类型,不同的Action有不同的Data数据指定。比如:ACTION_EDIT Action应该和要编辑的文档URI Data匹配,ACTION_VIEW应用应该和要显示的URI匹配。

3.Intent的Category属性

Intent中的Category属性是一个执行动作Action的附加信息。比如:CATEGORY_HOME则表示放回到Home界面,ALTERNATIVE_CATEGORY表示当前的Intent是一系列的可选动作中的一个。下表是SDK文档中关于Category的信息。

Constant

Meaning

CATEGORY_BROWSABLE

The target activity can be safely invoked by the browser to display data referenced by a link — for example, an image or an e-mail message.

CATEGORY_GADGET

The activity can be embedded inside of another activity that hosts gadgets.

CATEGORY_HOME

The activity displays the home screen, the first screen the user sees when the device is turned on or when the HOME key is pressed.

CATEGORY_LAUNCHER

The activity can be the initial activity of a task and is listed in the top-level application launcher.

CATEGORY_PREFERENCE

The target activity is a preference panel.

 下面是一个回到Home界面的例子:

main.xml

    
    
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:orientation="vertical" android:layout_width="fill_parent" 
  4.     android:layout_height="fill_parent" 
  5.     >     
  6.     <TextView   
  7.     android:layout_width="fill_parent" 
  8.     android:layout_height="wrap_content"   
  9.     android:text="测试Intent Category"   
  10.     /> 
  11.     <Button   
  12.     android:id="@+id/Button1"   
  13.     android:layout_width="wrap_content" 
  14.     android:layout_height="wrap_content"   
  15.     android:text="转到Home界面" 
  16.     />    
  17. </LinearLayout> 

strings.xml

    
    
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <resources> 
  3.     <string name="hello">Hello World, MainActivity!</string> 
  4.     <string name="app_name">IntentCategoryDemo</string> 
  5. </resources> 

MainActivity.java

    
    
  1. package com.android.category.activity;  
  2.  
  3. import android.app.Activity;  
  4. import android.content.Intent;  
  5. import android.os.Bundle;  
  6. import android.view.View;  
  7. import android.view.View.OnClickListener;  
  8. import android.widget.Button;  
  9.  
  10. public class MainActivity extends Activity {  
  11.     private Button btn;  
  12.     @Override 
  13.     public void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.main);  
  16.           
  17.         btn = (Button)findViewById(R.id.Button1);  
  18.         btn.setOnClickListener(new OnClickListener() {  
  19.             @Override 
  20.             public void onClick(View v) {     
  21.                 Intent intent = new Intent();                 
  22.                 intent.setAction(Intent.ACTION_MAIN);// 添加Action属性                
  23.                 intent.addCategory(Intent.CATEGORY_HOME);// 添加Category属性              
  24.                 startActivity(intent);// 启动Activity  
  25.             }  
  26.         });  
  27.     }  

 效果图:

 

4.Intent的Type属性

Intent的Type属性显式指定Intent的数据类型(MIME)。一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。
 

5.Intent的Compent属性

Intent的Compent属性指定Intent的的目标组件的类名称。通常 Android会根据Intent 中包含的其它属性的信息,比如action、data/type、category进行查找,最终找到一个与之匹配的目标组件。但是,如果 component这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。指定了这个属性以后,Intent的其它所有属性都是可选的。

 6.Intent的Extra属性

Intent的Extra属性是添加一些组件的附加信息。比如,如果我们要通过一个Activity来发送一个Email,就可以通过Extra属性来添加subject和body。

 下面的例子在第一个Activity的EditText输入用户名,该年龄保存在Intent的Extras属性中。当单击Button时,会在第二个Activity中显示用户名。

first.xml

    
    
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:orientation="vertical"   
  4.     android:layout_width="fill_parent" 
  5.     android:layout_height="fill_parent" 
  6.     >     
  7.     <TextView     
  8.         android:layout_width="wrap_content" 
  9.         android:layout_height="wrap_content"   
  10.         android:text="请输入用户名"   
  11.         />        
  12.     <EditText   
  13.         android:id="@+id/EditText1"   
  14.         android:layout_width="fill_parent" 
  15.         android:layout_height="wrap_content" 
  16.         />        
  17.     <Button   
  18.         android:id="@+id/Button1"   
  19.         android:layout_width="wrap_content" 
  20.         android:layout_height="wrap_content"   
  21.         android:text="测试Extras属性" 
  22.         />        
  23. </LinearLayout> 

second.xml

    
    
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:orientation="vertical"   
  4.     android:layout_width="fill_parent" 
  5.     android:layout_height="fill_parent" 
  6.     >         
  7.     <TextView   
  8.         android:id="@+id/TextView1"   
  9.         android:layout_width="wrap_content"   
  10.         android:layout_height="wrap_content" 
  11.         /> 
  12. </LinearLayout> 

strings.xml

    
    
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <resources> 
  3.     <string name="hello">Hello World, FirstActivity!</string> 
  4.     <string name="app_name">IntentExtrasDemo</string> 
  5. </resources> 

FirstActivity.java

    
    
  1. package com.android.extras.activity;  
  2.  
  3. import android.app.Activity;  
  4. import android.content.Intent;  
  5. import android.os.Bundle;  
  6. import android.view.View;  
  7. import android.view.View.OnClickListener;  
  8. import android.widget.Button;  
  9. import android.widget.EditText;  
  10.  
  11. public class FirstActivity extends Activity {  
  12.     private Button btn;  
  13.     private EditText etx;  
  14.       
  15.     @Override  
  16.     public void onCreate(Bundle savedInstanceState) {  
  17.         super.onCreate(savedInstanceState);  
  18.         setContentView(R.layout.first);  
  19.           
  20.         btn = (Button)findViewById(R.id.Button1);  
  21.         etx = (EditText)findViewById(R.id.EditText1);  
  22.           
  23.         btn.setOnClickListener(new OnClickListener() {  
  24.             @Override  
  25.             public void onClick(View v) {  
  26.                 Intent intent = new Intent();  
  27.                 //设置Intent的class属性,跳转到SecondActivity  
  28.                 intent.setClass(FirstActivity.this, SecondActivity.class);  
  29.                 //为intent添加额外的信息  
  30.                 intent.putExtra("useName", etx.getText().toString());  
  31.                 //启动Activity  
  32.                 startActivity(intent);  
  33.             }  
  34.         });         
  35.     }  

SecondActivity.java

    
    
  1. package com.android.extras.activity;  
  2.  
  3. import android.app.Activity;  
  4. import android.content.Intent;  
  5. import android.os.Bundle;  
  6. import android.widget.TextView;  
  7.  
  8. public class SecondActivity extends Activity {  
  9.     private TextView tv;  
  10.       
  11.     @Override 
  12.     public void onCreate(Bundle savedInstanceState) {  
  13.         super.onCreate(savedInstanceState);  
  14.         //设置当前的Activity的界面布局  
  15.         setContentView(R.layout.second);  
  16.         //获得Intent  
  17.         Intent intent = this.getIntent();         
  18.         tv = (TextView)findViewById(R.id.TextView1);  
  19.         //从Intent获得额外信息,设置为TextView的文本  
  20.         tv.setText(intent.getStringExtra("useName"));  
  21.     }  

注意:在添加第二个Activity SecondActivity的时候,要在AndroidManifest.xml里面添加上SecondActivity,具体如下,即是在15行</activity>的后面添加上16~18行的代码。如果不这样做,就会在模拟器上出现错误。

    
    
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" 
  3.       package="com.android.extras.activity" 
  4.       android:versionCode="1" 
  5.       android:versionName="1.0"> 
  6.     <uses-sdk android:minSdkVersion="10" /> 
  7.  
  8.     <application android:icon="@drawable/icon" android:label="@string/app_name"> 
  9.         <activity android:name=".FirstActivity" 
  10.                   android:label="@string/app_name"> 
  11.             <intent-filter> 
  12.                 <action android:name="android.intent.action.MAIN" /> 
  13.                 <category android:name="android.intent.category.LAUNCHER" /> 
  14.             </intent-filter> 
  15.         </activity> 
  16.         <activity android:name=".SecondActivity" 
  17.                   android:label="@string/app_name"> 
  18.         </activity> 
  19.     </application> 
  20. </manifest> 

效果图:

本文出自 “IT的点点滴滴” 博客,请务必保留此出处http://liangruijun.blog.51cto.com/3061169/634411


1111111111111111111111111111111111111111111111111111111

111111111111111111111111111111111111111111111111111111111

1111111111111111111111111111111111111111111111111111111111111

http://blog.csdn.net/think_soft/article/details/7559560

2222222222222222222222222222222222222222222222222222222

222222222222222222222222222222222222222222222222222222222

2222222222222222222222222222222222222222222222222222222222222

Intent中的四个重要属性——Action、Data、Category、Extras
标签: actionapplicationandroid电话google浏览器
  21481人阅读  评论(2)  收藏  举报

Intent中的四个重要属性——Action、Data、Category、Extras  

Intent作为联系各Activity之间的纽带,其作用并不仅仅只限于简单的数据传递。通过其自带的属性,其实可以方便的完成很多较为复杂的操作。例如直接调用拨号功能、直接自动调用合适的程序打开不同类型的文件等等。诸如此类,都可以通过设置Intent属性来完成。

  Intent主要有以下四个重要属性,它们分别为:

    Action:Action属性的值为一个字符串,它代表了系统中已经定义了一系列常用的动作。通过setAction()方法或在清单文件AndroidManifest.xml中设置。默认为:DEFAULT。

    Data:Data通常是URI格式定义的操作数据。例如:tel:// 。通过setData()方法设置。

    Category:Category属性用于指定当前动作(Action)被执行的环境。通过addCategory()方法或在清单文件AndroidManifest.xml中设置。默认为:CATEGORY_DEFAULT。

    Extras:Extras属性主要用于传递目标组件所需要的额外的数据。通过putExtras()方法设置。

  四个属性各自的常用值如下所示:

  Action:

     ACTION_MAIN:Android Application的入口,每个Android应用必须且只能包含一个此类型的Action声明。 

    ACTION_VIEW:系统根据不同的Data类型,通过已注册的对应Application显示数据。

    ACTION_EDIT:系统根据不同的Data类型,通过已注册的对应Application编辑示数据 

    ACTION_DIAL打开系统默认的拨号程序,如果Data中设置了电话号码,则自动在拨号程序中输入此号码 

    ACTION_CALL:直接呼叫Data中所带的号码 

    ACTION_ANSWER:接听来电 

    ACTION_SEND:由用户指定发送方式进行数据发送操作

    ACTION_SENDTO:系统根据不同的Data类型,通过已注册的对应Application进行数据发送操作 

    ACTION_BOOT_COMPLETED:Android系统在启动完毕后发出带有此Action的广播(Broadcast) 

    ACTION_TIME_CHANGEDAndroid系统的时间发生改变后发出带有此Action的广播(Broadcast) 

    ACTION_PACKAGE_ADDEDAndroid系统安装了新的Application之后发出带有此Action的广播(Broadcast) 

    ACTION_PACKAGE_CHANGEDAndroid系统中已存在的Application发生改变之后(如应用更新操作)发出带有此Action的广播(Broadcast) 

    ACTION_PACKAGE_REMOVED:卸载了Android系统已存在的Application之后发出带有此Action的广播(Broadcast)  

  Category:

     CATEGORY_DEFAULTAndroid系统中默认的执行方式,按照普通Activity的执行方式执行 

    CATEGORY_HOME:设置该组件为Home Activity

    CATEGORY_PREFERENCE:设置该组件为Preference 

    CATEGORY_LAUNCHER:设置该组件为在当前应用程序启动器中优先级最高的Activity,通常为入口ACTION_MAIN配合使用 

    CATEGORY_BROWSABLE设置该组件可以使用浏览器启动 

    CATEGORY_GADGET设置该组件可以内嵌到另外的Activity

  Extras:

     EXTRA_BCC:存放邮件密送人地址的字符串数组。 

    EXTRA_CC:存放邮件抄送人地址的字符串数组

    EXTRA_EMAIL:存放邮件地址的字符串数组 

    EXTRA_SUBJECT:存放邮件主题字符串 

    EXTRA_TEXT存放邮件内容 

    EXTRA_KEY_EVENTKeyEvent对象方式存放触发Intent的按键  

    EXTRA_PHONE_NUMBER存放调用ACTION_CALL时的电话号码   

   Data:

     tel://:号码数据格式,后跟电话号码。 

    mailto://:邮件数据格式,后跟邮件收件人地址

    smsto://:短息数据格式,后跟短信接收号码

    content://:内容数据格式,后跟需要读取的内容。 

    file://:文件数据格式,后跟文件路径

    market://search?q=pname:pkgname:市场数据格式,在Google Market里搜索包名为pkgname的应用

            geo://latitude,longitude:经纬数据格式,在地图上显示经纬度指定的位置

在intent-filter中指定data属性的实际目的是:要求接收的Intent中的data必须符合intent-filter中指定的data属性,这样达到反向限定Intent的作用。

例如:在AndroidManifest.xml 中进行如下设置:

[html]  view plain  copy
  1. <activity android:name=".TestActivity">  
  2.     <intent-filter>  
  3.          <action android:name="com.jony.test"/>  
  4.          <data android:scheme="file"/>  
  5.     </intent-filter>  
  6. </activity>  
那么启动该Activity的Intent必须进行如下设置:

[java]  view plain  copy
  1. Intent intent = new Intent();  
  2. Uri uri =  Uri.parse("file://com.android.test:520/mnt/sdcard");  
  3. intent.setData(uri);  

data属性解析:android:scheme、android:host、android:port、android:path、android:mimeType

data的前四个属性构成了URI的组成部分,mimeType设置了数据的类型

data元素组成的URI模型如下:

scheme://host:port/path

举例说明:

URI   file://com.android.jony.test:520/mnt/sdcard

scheme-->file:

host-->com.android.jony.test

port-->520

path-->mnt/sdcard

其中host和port为URI的authority,如果没有指定host,port将被忽略

data的各属性并不是独立的,data的各属性构成了URI的整个组成部分。要使authority(host和port)有意义,必须指定scheme;要使path有意义,必须使scheme和authority(host和port)有意义。

URI和intent-filter匹配:

Intent中URI和intent-filter进行比较的时候只会进行部分的比较:

(1)当intent-filter中只设置了scheme,只会比较URI的scheme部分;

(2)当intent-filter中只设置了scheme和authority,那么只会匹配URI中的scheme和authority;

(3)当intent-filter中设置了scheme、authority和path,那么只会匹配URI中的scheme、authority、path;(path可以使用通配符进行匹配)

(4)当intent-filter中设置了mimeType,还会进行数据类型的匹配。


总结:

(1)在AndroidMainfest.xml 中对每一个Activity都做了说明——intent-filter,intent-filter声明了需要接收怎样的Intent,当发送的Intent和intent-filter中定义的相符合,就会启动相应的Activity;

(2)当有多个Activity符合发送的Intent时,Android系统会列出所有满足Intent的Activity,用户可以通过选择进行相关的操作;

(3)在一个Activity的intent-filter中可以有多个action、多个category、多个data,这样可以有多种组合与Intent进行匹配。注意:如果在一个Activity中有多个Intent进行匹配的时候,建议使用多个intent-filter与Intent进行匹配。猜测:这样应该可以提高Intent的匹配速度。

(4)data属性,这是一个进行反向限制Intent的操作,要求Intent的data必须是intent-filter中声明的数据之一(应为在一个intent-filter中可以设置多个data)。注意:如果要启动目标Activity,但是指定的data数据类型与Activity中data数据类型不匹配,将会造成ActivityNotFoundException异常。



备注:再次感谢原文作者的辛勤劳动

原文链接地址——Intent中的四个重要属性详解
44444444444444444444444444444444444444444444444444444444
444444444444444444444444444444444444444444444444444444444444444444
444444444444444444444444444444444444444444444444444444444444444444444444444444
 

如何在service中获取按键监听事件呢

  1023人阅读  评论(0)  收藏  举报
  分类:

思路一:

你的service 启一个大小为1*1的窗口 放到角落
这个窗口 可以监听on key的

思路二:

开机时创建一个新的进程,实际上就是Linux里面的进程操作。可以使用NDK开发用C或者C++新建一个进程来运行自己的服务,并提高进程优先级,避免被清理掉(我猜测QQ和微信的推送服务,或许是这么实现的)。

思路三:

这个需求必须修改底层才可实现,我现在的做法是修改底层,在按键按下时发送广播,这样在service或者activity都可捕获到按键信息

app中对于HOME键广播事件的接收

      首先,自定义一个BroadcastReceiver:

[java] view plaincopy
class HomeKeyEventBroadCastReceiver extends BroadcastReceiver {  
  
    static final String SYSTEM_REASON = "reason";  
    static final String SYSTEM_HOME_KEY = "homekey";//home key  
    static final String SYSTEM_RECENT_APPS = "recentapps";//long home key  
      
    @Override  
    public void onReceive(Context context, Intent intent) {  
        String action = intent.getAction();  
        if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {  
            String reason = intent.getStringExtra(SYSTEM_REASON);  
            if (reason != null) {  
                if (reason.equals(SYSTEM_HOME_KEY)) {  
                    // home key处理点  
                      
                } else if (reason.equals(SYSTEM_RECENT_APPS)) {  
                    // long home key处理点  
                }  
            }  
        }  
    }  
}  
       其次,生成且注册之
[java] view plaincopy
receiver = new HomeKeyEventBroadCastReceiver();  
registerReceiver(receiver, new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));  
这样,我们就可以在app中进行HOME键的处理了!


=====================================================================================

将到Android中Home键的监听,很多人第一反应时重写相应Activity的onKeyDown()方法,监听当按下的键的keyCode为KEYCODE_HOME时,进行自己的相应的处理。如:

[java]  view plain copy
  1. @Override  
  2. public boolean onKeyDown(int keyCode, KeyEvent event) {  
  3.     if (keyCode == KeyEvent.KEYCODE_HOME) {  
  4.         stopService(mIntentService);  
  5.         return true;  
  6.     }  
  7.     return super.onKeyDown(keyCode, event);  
  8. }  
但是这样的监听是不能监听到HOME键的。这样的方法只能监听到BACK,MENU键。那么怎么监听Home键了?


1.新建一个监听Home键的Listener


[java]  view plain copy
  1. public class HomeListener {  
  2.     static final String TAG = "HomeListener";   
  3.     private Context mContext;   
  4.     private IntentFilter mFilter;   
  5.     private OnHomePressedListener mListener;   
  6.     private InnerRecevier mRecevier;   
  7.    
  8.     // 回调接口    
  9.     public interface OnHomePressedListener {   
  10.         public void onHomePressed();   
  11.    
  12.         public void onHomeLongPressed();   
  13.     }   
  14.    
  15.     public HomeListener(Context context) {   
  16.         mContext = context;   
  17.         mFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);   
  18.     }   
  19.    
  20.     /** 
  21.      * 设置监听 
  22.      *  
  23.      * @param listener 
  24.      */   
  25.     public void setOnHomePressedListener(OnHomePressedListener listener) {   
  26.         mListener = listener;   
  27.         mRecevier = new InnerRecevier();   
  28.     }   
  29.    
  30.     /** 
  31.      * 开始监听,注册广播 
  32.      */   
  33.     public void startWatch() {   
  34.         if (mRecevier != null) {   
  35.             mContext.registerReceiver(mRecevier, mFilter);   
  36.         }   
  37.     }   
  38.    
  39.     /** 
  40.      * 停止监听,注销广播 
  41.      */   
  42.     public void stopWatch() {   
  43.         if (mRecevier != null) {   
  44.             mContext.unregisterReceiver(mRecevier);   
  45.         }   
  46.     }  
  47.       
  48.     class InnerRecevier extends BroadcastReceiver{  
  49.         final String SYSTEM_DIALOG_REASON_KEY = "reason";   
  50.         final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";   
  51.         final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";   
  52.         final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";   
  53.   
  54.         @Override   
  55.         public void onReceive(Context context, Intent intent) {   
  56.             String action = intent.getAction();   
  57.             if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {   
  58.                 String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);   
  59.                 if (reason != null) {   
  60. //                    Log.e(TAG, "action:" + action + ",reason:" + reason);   
  61.                     if (mListener != null) {   
  62.                         if (reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) {   
  63.                             // 短按home键    
  64.                             mListener.onHomePressed();   
  65.                         } else if (reason   
  66.                                 .equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {   
  67.                             // 长按home键    
  68.                             mListener.onHomeLongPressed();   
  69.                         }   
  70.                     }   
  71.                 }   
  72.             }   
  73.         }   
  74.     }   
  75. }  

2.在使用的类的onCreate方法中注册Home键的监听


[java]  view plain copy
  1. /** 
  2.      * 注册Home键的监听 
  3.      */  
  4.     private void registerHomeListener() {  
  5.         mHomeWatcher = new HomeListener(this);   
  6.         mHomeWatcher.setOnHomePressedListener(new OnHomePressedListener() {  
  7.               
  8.             @Override  
  9.             public void onHomePressed() {  
  10.                 //TODO 进行点击Home键的处理  
  11.                 Log.i("xsl""0000000000000");  
  12.                 stopService(mIntentService);  
  13.             }  
  14.               
  15.             @Override  
  16.             public void onHomeLongPressed() {  
  17.                 //TODO 进行长按Home键的处理  
  18.                 Log.i("xsl""0000000000000");  
  19.             }  
  20.         });  
  21.         mHomeWatcher.startWatch();  
  22.     }  

3. 在使用的类的onPause方法中停止监听

[java]  view plain copy
  1. mHomeWatcher.stopWatch();  

====================================================================================

Android开机启动Activity或者Service方法

【原理】

    当Android系统完成BOOT阶段之后,就会发送一条名为 ACTION_BOOT_COMPLETED 的广播,我们便可在一个BroadcastReceiver中捕获这条广播,然后启动我们的Activity或者Service,当然要注意的是,我们的application必须具有捕获该广播的权限,下面请看具体步骤:

【步骤一】首先要有一个用于开机启动的Activity或者Service,这里以系统自己创建的最简单的Activity为例进行讲解。

   
   
  1. package com.billhoo.study; 
  2.  
  3. import android.app.Activity; 
  4. import android.os.Bundle; 
  5.  
  6. public class BootTestActivity extends Activity { 
  7.     /** Called when the activity is first created. */ 
  8.     @Override 
  9.     public void onCreate(Bundle savedInstanceState) { 
  10.         super.onCreate(savedInstanceState); 
  11.         setContentView(R.layout.main); 
  12.     } 

 

【步骤二】我们要编写一个BroadcastReceiver用以捕获ACTION_BOOT_COMPLETED这条广播,并在捕获之后启动我们要启动的Activity。

注意:必须在intent中添加Intent.FLAG_ACTIVITY_NEW_TASK标记,这就是我之前老是启动失败的原因。至于为什么,我还在研究SDK doc,明白了之后就回来补上。

   
   
  1. package com.billhoo.study; 
  2.  
  3. import android.content.BroadcastReceiver; 
  4. import android.content.Context; 
  5. import android.content.Intent; 
  6.  
  7. public class BootCompletedReceiver extends BroadcastReceiver { 
  8.   @Override 
  9.   public void onReceive(Context context, Intent intent) { 
  10.     if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) 
  11.     { 
  12.       Intent newIntent = new Intent(context, BootTestActivity.class); 
  13.       newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  //注意,必须添加这个标记,否则启动会失败 
  14.       context.startActivity(newIntent);       
  15.     }       
  16.   } 

【步骤三】在AndroidManifest.xml配置文件中注册我们的BroadcastReceiver

   
   
  1. <receiver android:name=".BootCompletedReceiver"> 
  2.     <intent-filter> 
  3.         <action android:name="android.intent.action.BOOT_COMPLETED" /> 
  4.     </intent-filter> 
  5. </receiver> 

 

【步骤四】在AndroidManifest.xml配置文件中添加允许我们捕获该广播的权限

   
   
  1. <!-- permissions --> 
  2. <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> 

 

重启虚拟机,大功告成。

下面附上完成的AndroidManifest.xml,以便大家理解参考

   
   
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     package="com.billhoo.study" android:versionCode="1" 
  4.     android:versionName="1.0"> 
  5.     <uses-sdk android:minSdkVersion="4" /> 
  6.  
  7.     <!-- permissions --> 
  8.     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> 
  9.  
  10.     <application android:icon="@drawable/icon" android:label="@string/app_name"> 
  11.         <!-- activities --> 
  12.         <activity android:name=".BootTestActivity" android:label="@string/app_name"> 
  13.             <intent-filter> 
  14.                 <action android:name="android.intent.action.MAIN" /> 
  15.                 <category android:name="android.intent.category.LAUNCHER" /> 
  16.             </intent-filter> 
  17.         </activity> 
  18.  
  19.         <!-- receivers --> 
  20.         <receiver android:name=".BootCompletedReceiver"> 
  21.             <intent-filter> 
  22.                 <action android:name="android.intent.action.BOOT_COMPLETED" /> 
  23.             </intent-filter> 
  24.         </receiver> 
  25.  
  26.     </application> 
  27. </manifest> 
5555555555555555555555555555555555555555555555555555555555
5555555555555555555555555555555555555555555555555555555555555555
55555555555555555555555555555555555555555555555555555555555555555555555555
C++中实现回调机制的几种方式 一文中,我们提到了实现回调的三种方式(C风格的回调函数, Sink方式和Delegate方式)。在面向对象开发中,delegate的方式是最灵活和方便的,因此很早就有人用复杂的模板去模拟(有兴趣的话可以看这里这里),总之是实现起来很复杂。但是现在借助C++11的 function bind , 我们可以很方便的去实现。下面是我自己的一种实现方式:
   namespace Common
{
    typedef  void* cookie_type;

    template<typename TR, typename T1, typename T2>
     class CEvent
    {
     public:
        typedef TR return_type;
        typedef T1 first_type;
        typedef T2 second_type;

        typedef std::function<return_type (first_type, second_type)> handler_type;

        ~CEvent()
        {
            Clear();
        }

        return_type  operator()(first_type p1, second_type p2)
        {
            return_type ret = return_type();
            size_t size = _handlers.size();
             for(size_t i=0; i<size; ++i)
            {
                ret = _handlers[i]-> operator()(p1, p2);
            }
             return ret;
        }

        cookie_type AddHandler(std::function<return_type (first_type, second_type)> h)
        {
            CEventHandler*p =  new(nothrow)  CEventHandler(h);
             if(p != nullptr) _handlers.push_back(p);
             return (cookie_type)p;
        }

        template<typename class_type, typename class_fun>
        cookie_type AddHandler(class_type* pThis, class_fun f)
        {
            CEventHandler* p =  new(nothrow) CEventHandler(pThis, f);
             if(p != nullptr) _handlers.push_back(p);
             return (cookie_type)p;
        }

         void RemoveHandler(cookie_type cookie)
        {
            CEventHandler* p = (CEventHandler*)cookie;

            auto itr = std::find(_handlers.begin(), _handlers.end(), p);
             if(itr != _handlers.end())
            {
                _handlers.erase(itr);
                delete p;
            }
             else
            {
                assert( false);
            }
        }

         void Clear()
        {
             if(!_handlers.empty())
            {
                 int n = _handlers.size();
                std::for_each(_handlers.begin(), _handlers.end(), [](CEventHandler* p)
                { 
                    assert(p != nullptr);
                    delete p;
                });
                _handlers.clear();        
            }
        }

     private:
         class CEventHandler 
        {
         public:
            CEventHandler(handler_type h)
            {
                _handler = h;
                assert(_handler != nullptr);
            }

            template<typename class_type, typename class_fun>
            CEventHandler(class_type* pThis, class_fun object_function)
            {
                 using  namespace std::placeholders;
                _handler = std::bind(object_function, pThis, _1, _2);
                assert(_handler != nullptr);
            }

            return_type  operator()(first_type p1, second_type p2)
            {
                return_type ret = return_type();
                assert(_handler != nullptr);
                 if(_handler != nullptr) ret = _handler(p1, p2);
                 return ret;
            }

            handler_type _handler;
        };


     private:
        std::vector<CEventHandler*> _handlers;
    };
}

大概实现思想是我们通过一个内置的 CEventHandler 类来封装处理函数,我们可以通过AddHandler来添加事件处理函数,添加时会返回一个Cookie,我们可以通过该Cookie来RemoveHandler, 下面是测试代码:
#include "stdafx.h"
#include <iostream>
#include "event1.h"

using  namespace std;

class CObjectX 
{

};

class CClickEventArgs:  public CObjectX
{

};


class CButton:  public CObjectX
{
public:
     void FireClick()
    {
        CClickEventArgs args;
        OnClicked( this, args);
    }

    Common::CEvent< int, CObjectX*, CClickEventArgs&> OnClicked;
};


class CMyClass 
{
public:
     int OnBtuttonClicked(CObjectX* pButton, CClickEventArgs& args)
    {
        cout << "CMyClass: Receive button clicked event" << endl;
         return 1;
    }
};

int OnBtuttonClicked_C_fun(CObjectX* pButton, CClickEventArgs& args)
{
    cout << "C Style Function: Receive button clicked event" << endl;
     return 1;
}


class CMyFunObj
{
public:
     int  operator()(CObjectX* pButton, CClickEventArgs& args)
    {
        cout << "Functor: Receive button clicked event" << endl;
         return 1;
    }
};

int _tmain( int argc, _TCHAR* argv[])
{
     using  namespace std::placeholders;

    CButton btn;

    CMyClass obj;
    Common::cookie_type c1 = btn.OnClicked.AddHandler(&obj, &CMyClass::OnBtuttonClicked);

    Common::cookie_type c2 = btn.OnClicked.AddHandler(OnBtuttonClicked_C_fun);

    CMyFunObj functor;
    Common::cookie_type c3 = btn.OnClicked.AddHandler(functor);

    btn.FireClick();


    btn.OnClicked.RemoveHandler(c2);

    std::cout << endl;


    btn.FireClick();

    system("pause");

     return 0;
}

以下是测试结果:


 可以看到, 我们在普通C函数, 类成员函数和仿函数(functor)中都测试通过。

另外对于事件函数返回值为void的情况,会编译出错,我们需要偏特化一下:
    template< typename T1, typename T2>
     class CEvent< void, T1, T2>
    {
     public:
        typedef  void return_type;
        typedef T1 first_type;
        typedef T2 second_type;

        typedef std::function<return_type (first_type, second_type)> handler_type;

        ~CEvent()
        {
            Clear();
        }

        return_type  operator()(first_type p1, second_type p2)
        {
            size_t size = _handlers.size();
             for(size_t i=0; i<size; ++i)
            {
                _handlers[i]-> operator()(p1, p2);
            }
        }

        cookie_type AddHandler(std::function<return_type (first_type, second_type)> h)
        {
            CEventHandler*p =  new(nothrow)  CEventHandler(h);
             if(p != nullptr) _handlers.push_back(p);
             return (cookie_type)p;
        }

        template<typename class_type, typename class_fun>
        cookie_type AddHandler(class_type* pThis, class_fun f)
        {
            CEventHandler* p =  new(nothrow) CEventHandler(pThis, f);
             if(p != nullptr) _handlers.push_back(p);
             return (cookie_type)p;
        }

         void RemoveHandler(cookie_type cookie)
        {
            CEventHandler* p = (CEventHandler*)cookie;

            auto itr = std::find(_handlers.begin(), _handlers.end(), p);
             if(itr != _handlers.end())
            {
                _handlers.erase(itr);
                delete p;
            }
             else
            {
                assert( false);
            }
        }

         void Clear()
        {
             if(!_handlers.empty())
            {
                 int n = _handlers.size();
                std::for_each(_handlers.begin(), _handlers.end(), [](CEventHandler* p)
                { 
                    assert(p != nullptr);
                    delete p;
                });
                _handlers.clear();        
            }
        }

     private:
         class CEventHandler 
        {
         public:
            CEventHandler(handler_type h)
            {
                _handler = h;
                assert(_handler != nullptr);
            }

            template<typename class_type, typename class_fun>
            CEventHandler(class_type* pThis, class_fun object_function)
            {
                 using  namespace std::placeholders;
                _handler = std::bind(object_function, pThis, _1, _2);
                assert(_handler != nullptr);
            }

            return_type  operator()(first_type p1, second_type p2)
            {
                assert(_handler != nullptr);
                 if(_handler != nullptr) _handler(p1, p2);
            }

            handler_type _handler;
        };


     private:
        std::vector<CEventHandler*> _handlers;
    };

最后谈一下在写这个代码中遇到的问题:
(1)不知道你能不能发现下面代码的问题, 我在写代码时就栽在这里了:
       vector < int *>   v;
     int *  p1  =  new  int ( 1 );
     v.push_back(p1);
     int *  p2  =  new  int ( 2 );
     v.push_back(p2);
 
     // 尝试删除所有值为p1的项
    //由该代码想到=>v.erase(std::remove(v.begin(), v.end(), p1), v.end());
    //错误代码:
     auto itr  =  remove(v.begin(), v.end(), p1);
     for_each(itr, v.end(), []( int *  p){delete p;});
     v.erase(itr, v.end());

    //正确代码:
   v.erase(remove_if(v.begin(), v.end(), [](int*p)->bool {if(p==p1) {delete p; return true;} else return false}), v.end());

(2)我们想把cookei_type放到类里面去, 类似这样:
1      template < typename TR, typename T1, typename T2 >
2      class  CEvent
3      {
4      public :
5          typedef TR return_type;
6          typedef T1 first_type;
7          typedef T2 second_type;
8          typedef  void *  cookie_type;

可发现要这样使用:
Common::CEvent < int , CObjectX * , CClickEventArgs &> ::cookie_type c1  =  btn.OnClicked.AddHandler( & obj,  & CMyClass::OnBtuttonClicked);
太不方便了, 不知道大家有没有好的方法。

注:上面的代码还没有经过真正商业使用,如果有问题欢迎指出。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值