Android O Android P 自定义开机广播

背景

一般来说,我们都是用的监听android.intent.action.BOOT_COMPLETED

但凡稍有些经验的开发者都知道,这个广播很慢,非常慢。因为它是一个有序广播,根据优先级来的,而且监听这个广播的apk又非常多。打个log感受一下,这个广播开始到结束在我司的机器上持续了30s!

关键是你把优先级调高了,即便你是前几个收到android.intent.action.BOOT_COMPLETED的,从开机动画走完,锁屏界面跳出来 到你的apk收到这个广播,大概还是有个5s左右的时间。

原因是android.intent.action.BOOT_COMPLETED发出来的时候就不是最早的。它前面还有

android.intent.action.LOCKED_BOOT_COMPLETEDandroid.intent.action.MEDIA_MOUNTED等。

要等这几个广播处理完了,才轮到android.intent.action.BOOT_COMPLETED

 

我们的目的是让我们的apk尽早起来(一般都是收了广播,然后receiveronReceivestart我们的service)

那么我们有以下几种处理办法:

1.接收android.intent.action.BOOT_COMPLETED,调高优先级。

2.接收android.intent.action.MEDIA_MOUNTED,因为这个广播一方面比android.intent.action.BOOT_COMPLETED发送的要早,一方面监听它的apk比较少。

3.直接在AMS里面去start我们的service,过于粗暴且不通用。

4.自定义开机广播,这样监听这个广播的apk只有我们自己,并且尽早的发出这个广播。

 

我们要考虑的问题:

1.如果监听android.intent.action.MEDIA_MOUNTED,这个广播是挂载存储的时候发的,开机的时候挂载到手机的存储区(storage/emulated/0)会发一下,后面如果插入sdcard也会发。要评估多次触发广播是否会对自己的apk业务逻辑造成影响(以免自己本来stop了的service又被叫起来)

2.自定义开机广播,这个广播发出来的时机。需要考虑system是否Ready,这个一般都达到了,大家写也会注意。还有点需要考虑,apkAndroidManifest.xml的组件信息是何时导入的,如果广播发出来的时候,我们的apkreceiver信息还没被PackageManagerService导入,一样是收不到的,这个坑我自己在Android P上面踩到了。后面会详细说。

 

先直接上可行的结论:

Android O自定义开机广播

frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

finishBooting()方法里:

mUserController.sendBootCompletedLocked(
        new IIntentReceiver.Stub() {
            @Override
            public void performReceive(Intent intent, int resultCode,
                    String data, Bundle extras, boolean ordered,
                    boolean sticky, int sendingUser) {
                synchronized (ActivityManagerService.this) {
                    requestPssAllProcsLocked(SystemClock.uptimeMillis(),
                            true, false);
                }
            }
        });
scheduleStartProfilesLocked();
//potter add
Intent customIntent=new Intent("com.honeywell.intent.action.BOOT_COMPLETED");
customIntent.setPackage("com.honeywell.ezreceiver");
mContext.sendBroadcast(customIntent);
//potter end

有人可能会问,这样只有一个apk能收到,如何让所有apk都收到。按下面这么写即可。

//potter add
Intent customIntent=new Intent("com.honeywell.intent.action.BOOT_COMPLETED");
customIntent. addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mContext.sendBroadcast(customIntent);
//potter end

可能又有人会问,这样apk收到的顺序没法控制,那么按下面这么写:

//potter add
Intent customIntent=new Intent("com.honeywell.intent.action.BOOT_COMPLETED");
customIntent. addFlags(Intent.FLAG_RECEIVER_NO_ABORT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mContext. sendOrderedBroadcast(intent, null);
//potter end

我们多给加上一个Intent.FLAG_RECEIVER_NO_ABORTFlag让这个有序广播不能被abort掉。实际上系统里面的android.intent.action.BOOT_COMPLETED这个广播就是这两个flag

这么写,功能已经实现了。但是从设计的角度很不好。因为这么写作为一个在System发出去的广播并没有加权限,这是不符合android的规范的。

我们追下源码:

sendBroadcast>>>

ContextImpl.javasendBroadcast>>>

ActivityManagerService.javabroadcastIntent>>>

ActivityManagerService.javabroadcastIntentLocked

AMSbroadcastIntentLocked方法里的

if (isCallerSystem) {
    checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
            isProtectedBroadcast, receivers);
}

会报log

Sending non-protected broadcast…

虽然广播正常发送了,并没有影响到广播的收发,但是从设计上来说这么写不安全的。

要想消除掉这个log,可以去checkBroadcastFromSystem里面搞特殊,类似

if (isProtectedBroadcast
        || Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
        || Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(action)
 ....
        || AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION.equals(action)
        || "com.honeywell.intent.action.BOOT_COMPLETED".equals(action)) {
    // Broadcast is either protected, or it's a public action that
    // we've relaxed, so it's fine for system internals to send.
    return;
}

也可以sendBroadcast的时候加上权限,收广播的地方同样加上权限即可。

报这个log具体有哪些影响和怎么广播加权限,这里就不赘述了。

Android P自定义开机广播

frameworks\base\services\core\java\com\android\server\am\UserController.java

finishUserUnlockedCompleted方法里:

//potter add
final Intent bootIntent1 = new Intent("com.honeywell.intent.action.BOOT_COMPLETED", null);
bootIntent1.putExtra(Intent.EXTRA_USER_HANDLE, userId);
bootIntent1.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
        | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mInjector.broadcastIntent(bootIntent1, null, null, 0, null, null, null,AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
//potter end
final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
        | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mInjector.broadcastIntent(bootIntent, null, new IIntentReceiver.Stub() {
            @Override
            public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser)
                    throws RemoteException {
                Slog.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u" + userId);
            }
        }, 0, null, null,
        new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
        AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);

这里一定要放在android.intent.action.BOOT_COMPLETED之前发,如果放在它之后,

虽然发送广播的时间是差了很短的时间,实测不到100ms

但是由于处理的时候是按队列来的,也就是android.intent.action.BOOT_COMPLETED处理完(至少10s以上,我司设备长达30s)后处理自定义广播。这样自定义广播就没有意义了。

 

P和O处理方式不同的原因

这个原因其实一开始就提到了。如果按O的处理方法,发广播的时机太早了,这时候所有apkAndroidManifest.xml的组件信息还没有在PackageManagerService里面导入完毕。

导入AndroidManifest.xml是在PackageManagerServicescanDirLI方法里面做的。

P上面按O的代码来测试:

frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

finishBooting()方法里:

mUserController.sendBootCompleted(
        new IIntentReceiver.Stub() {
            @Override
            public void performReceive(Intent intent, int resultCode,
                    String data, Bundle extras, boolean ordered,
                    boolean sticky, int sendingUser) {
                synchronized (ActivityManagerService.this) {
                    requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
                }
            }
        });
mUserController.scheduleStartProfiles();
//potter add
Log.e("potter","amspotter begin----1111");
Intent customIntent=new Intent("com.honeywell.intent.action.BOOT_COMPLETED");
customIntent.setPackage("com.honeywell.ezreceiver");
mContext.sendBroadcastAsUser(customIntent,UserHandle.OWNER);
Log.e("potter","amspotter end----1111");
mHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
		Log.e("potter","amspotter begin----2222");
		mContext.sendBroadcastAsUser(customIntent,UserHandle.OWNER);
		Log.e("potter","amspotter end----2222");
    }
},5000);
//potter end

这里,我们发两次广播,一个是立即发送,一个是延迟5秒发送。

frameworks\base\services\core\java\com\android\server\am\UserController.java

finishUserUnlockedCompleted方法里:

//potter add
Log.e("potter","amspotter begin----3333");
final Intent bootIntent1 = new Intent("com.honeywell.intent.action.BOOT_COMPLETED", null);
bootIntent1.putExtra(Intent.EXTRA_USER_HANDLE, userId);
bootIntent1.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
        | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mInjector.broadcastIntent(bootIntent1, null, null, 0, null, null, null,AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
Log.e("potter","amspotter end----3333");
//potter end
final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
        | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mInjector.broadcastIntent(bootIntent, null, new IIntentReceiver.Stub() {
            @Override
            public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser)
                    throws RemoteException {
                Slog.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u" + userId);
            }
        }, 0, null, null,
        new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
        AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
//potter add
Log.e("potter","amspotter begin----4444");
final Intent bootIntent2 = new Intent("com.honeywell.intent.action.BOOT_COMPLETED", null);
bootIntent2.putExtra(Intent.EXTRA_USER_HANDLE, userId);
bootIntent2.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
        | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mInjector.broadcastIntent(bootIntent2, null, null, 0, null, null, null,AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
Log.e("potter","amspotter end----4444");
//potter end

android.intent.action.BOOT_COMPLETED前后各发一个广播。

frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

broadcastIntentLocked (…)方法里:

这里的逻辑是筛选出哪些Receiver是接受对应的广播的

// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
         == 0) {
    receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
    //potter add
	if(receivers==null){
		Log.e("potter","receivers==null");
	}else{
		Log.e("potter","receivers.size():"+receivers.size());
	}
	//potter end
}

frameworks\base\services\core\java\com\android\server\am\ActivityManagerDebugConfig.java

static final boolean DEBUG_BROADCAST = DEBUG_ALL || false;
static final boolean DEBUG_BROADCAST_BACKGROUND = DEBUG_BROADCAST || false;
static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
改成
static final boolean DEBUG_BROADCAST = DEBUG_ALL || true;
static final boolean DEBUG_BROADCAST_BACKGROUND = DEBUG_BROADCAST || true;
static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || true;

打开log。

frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java

public static final boolean DEBUG_PACKAGE_SCANNING = false;
改成
public static final boolean DEBUG_PACKAGE_SCANNING = true;

打开log

我的apk

<receiver
    android:name=".MyReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="com.honeywell.intent.action.BOOT_COMPLETED"/>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
</receiver>
public void onReceive(Context context, Intent intent) {
    LogUtils.e("potter", "MyReceiver action:" + intent.getAction());
    if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED") ||
            intent.getAction().equals("com.honeywell.intent.action.BOOT_COMPLETED")) {
        context.startService(new Intent(context, MyService.class));
    }
}

Ok,准备完毕。测试的log如下:

从上述log可以分析出:

1.发了4次广播,只收到了3次。广播1发的太早,此时我们的apkAndroidManifest.xml还没有导入完毕,导致筛选符合条件的receivers时,得到的结果是null

2.广播3,广播4和比广播15s发送的广播2,此时我们的apkAndroidManifest.xml已经导入完毕,所以receivers得到的结果是正确的,size1,对应我们的apk

3.最后按时间顺序收到的广播次序是

14:55:29.430      广播3

14:55:49.005      android.intent.action.BOOT_COMPLETED

14:56:00.200      广播4

14:56:00.225      广播2

可以看到广播4,和广播2由于发送的时候是在android.intent.action.BOOT_COMPLETED之后,所以由于队列的关系,推迟了很久才收到。

所以最佳的方案来看就是使用广播3,也是前面提到的solution

总的log如下:

时序如下:

开始开机动画>>>开始扫描apk,导入AndroidManifest.xml

>>>开机动画完毕>>>走入AmsfinishBooting>>>过一会才扫描apk结束

>>>这时候发广播才能保证是百分百ok

实测的结果就是如此,这里让人疑惑的是为什么finishBooting后竟然才所有的apk扫描结束,可以推论出PMS的扫描和bootanimation是异步的,有可能由于我们预装的apk比较多,才导致了开机动画结束后依然还没有scan结束。

这就很尴尬,因为即使我们找准代码位置,是在PMS 扫描完所有apk后去发自定义开机广播,或者直接去startService。但是这时候距离开机动画结束已经有一段时间了,上面打log1s左右。这样还是不是百分百完美,假设需求是开机就启动apk去禁止下拉状态栏,这样的话客户操作快的话,还是有可能在开机动画刚结束,就把statusbar拉了下来。

 

最后,之所以14:55:25发的广播,为什么14:55:29才收到。是因为25秒发广播的时候,广播队列里面已经有其它的广播了,而其它广播有的由于监听的apk比较多,耗时比较久。比较值得关注的是

android.intent.action.LOCKED_BOOT_COMPLETED

android.intent.action.MEDIA_MOUNTED

看下面的图就一目了然了。

广播发送的时序图:

 这里可以看到,我司其实发了两次android.intent.action.MEDIA_MOUNTED.原因是我司产品还新增了一个IPSM分区。

大家关注/storage/emulated/0的挂载广播即可。

广播接受的时序图:

总结

总而言之,针对我司的设备。

目前来看,Android O上自定义开机广播适用于AMS里面发广播。

Android P上自定义广播适用于UserController里面发广播,只要做到刚好在android.intent.action.BOOT_COMPLETED之前即可。

Android O上我暂时就没去加log一步步追为什么AMS里面发广播没有P上面碰到的问题了,有可能是O上面预置的apk少,所有PMS scan所有的apk比较快,在finishBooting前就scan 结束了,也可能是Android OAndroid P开机流程上在这块就有些许差异。

最后,可能有人会问,为什么不直接去监听android.intent.action.MEDIA_MOUNTED

其实这也是个办法,可以看到,android.intent.action.MEDIA_MOUNTED这个广播发出来的时候是14:55:24.967,而PMS scan apk14:55:24.920之前都没有结束scan apk。这两个时间点距离太接近了,考虑到后续OS可能还要再预制apk,到时候PMS 结束scan apk的时间节点还会往后推。其实监听android.intent.action.MEDIA_MOUNTED是可能有风险的,和上面的广播1一样。极端情况下可能receivers == null.

所以还是折衷用的自定义广播,这样稍微晚一点点也能接受。至少百分之百比android.intent.action.BOOT_COMPLETED要快。

 

 

 

 

 

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
0、ANDROID常用类库说明 6 1、ANDROID文件系统与应用程序架构 7 1.1、ANDROID 文件系统 7 1.2、ANDROID应用程序架构 9 2、ANDROID应用程序结构 11 2.1、ACTIVITY 12 2.1.1、概述 12 2.1.2、Activity的生命周期 15 2.1.3、Activity 的创建 16 2.1.4、Activity 的跳转(含Bundle传值) 17 2.1.5.Actvity 堆栈 18 2.1.6、Intent对象调用Activity实例 19 2.1.7、Activity透明 21 2.1.8、一次性关闭所有的Activity 22 2.1.9、PreferenceActivity 用法 22 2.1.10、Dialog风格的Activity 23 2.1.11、横竖屏切换不销毁当前Activity 23 2.2、INTENT RECEIVER 25 2.3、SERVICE 26 2.3.1、什么是Service 26 2.3.2、如何使用Service 27 2.3.3、Service的生命周期 32 2.3.4、判断服务开启状态 33 2.3.5、获取启动的服务 34 2.4、CONTENT PROVIDER 35 3、ANDROID UI LAYOUT 35 3.1、概述 35 3.2、线性布局(LINEAR LAYOUT) 36 3.3、相对布局(RELATIVE LAYOUT) 39 3.4、TABLELAYOUT 40 3.5、ABSOLUTELAYOUT 47 4、ANDROID UI 控件 48 4.1、IMAGEBUTTON 48 4.1.1、图案填充问题 48 4.2、TEXTVIEW 49 4.2.1、动态滚动 49 4.3、EDITTEXT 49 4.3.1、光标选择 49 4.4、TITLEBAR 50 4.4.1、非全屏状态下不显示title标题栏 50 4.4.2、标题栏进度指示器 50 4.4.3、titleBar 高级实现方法(更美观) 51 4.4.4、获取标题栏和状态栏高度 57 4.4.5、标题栏显示简单的进度框 57 4.5、MENU 58 4.5.1、简单的代码 58 4.5.2、menu实现的两种方法 58 4.5.3、自定义MENU背景 62 4.5.4、触发menu 64 4.5.5、Context Menu和Options Menu菜单的区别 64 4.5.6、Context menus for expandable lists 64 4.6、LISTVIEW 66 4.6.1、ListView自定义分割线 66 4.6.2、LIST例一 66 4.6.3、LIST例二 76 4.6.4、LIST例三 80 4.6.5、ListView 被选中item的背景颜色 82 4.6.6、ListView自定义背景颜色 83 4.6.7、List长按与短按消息映射 84 4.6.8、点击ListView改变背景色 87 4.6.9、自动滚动ListView 88 4.6.10、BaseExpandableListAdapter例 88 4.6.11、列表视图(List View) 96 4.6.12、NoteList 99 4.7、TAB与TABHOST 106 4.8、RATINGBAR 110 4.8.1、例一 110 4.8.2、例二 112 4.9、DATE/TIME SET 115 4.9.1、DatePicker/TimePicker 115 4.9.2、DatePickerDialog/TimePickerDialog 119 4.10、WEBVIEW 120 4.10.1、WebView的使用 120 4.11、SCROLLVIEW 121 4.11.1、ScrollView的使用 121 4.12、GRIDVIEW 124 4.12.1、GridView的使用 124 4.13、GAMEVIEW 127 4.13.1、显示到一个布局中 127 4.14、TOASTE 128 4.14.1、短时间显示 128 4.14.2、长时间显示 128 4.15、对话框 128 4.15.1、简单的对话框: 128 4.15.2、包含两个按钮的对话框 128 4.15.3、三个按钮的提示框 129 4.15.4、包含输入的dlg 131 4.15.5、圆形进度框 133 4.15.6、AlertDialog.Builder 133 4.15.7、模式对话框 134 4.16、拖动BUTTON获得位置 135 5、ANDROID UI 美化 137 5.1、简单美化BUTTON、IMAGEBUTTON、TEXTVIEW等控件 137 5.2、BUTTON美化案例☆ 139 5.3、IMAGEBUTTON 按下时的动画效果 142 5.4、滚动条显示与隐藏 143 5.5、LISTVIEW 与 SCROLLVIEW 解决办法 144 方法一:(重写ListView) 144 方法二: 150 5.6、3D魔方 151 6、ANDROID UI 动画 160 6.1、四种2D动画 160 6.1.1、透明度控制动画效果 alpha 160 6.1.2、旋转动画效果 rotate 161 6.1.3、尺寸伸缩动画效果 scale 162 6.1.4、位置转移动画效果 translate 163 6.1.5、四种动画效果的调用 164 7、异步调用 167 开辟一个线程: 167 THREAD: 168 HANDER 170 TIMER 173 ANDROID 界面刷新 174 MESSAGE HANDER 175 用法: 175 线程与子线程调用MessageHander 177 Messagehandler实例 177 8、数据存储与读取 179 1. PREFERENCES 179 2. FILES 180 3. DATABASES 180 4. NETWORK 183 5、CONTENTPROVIDER 183 6、执行SQL语句进行查询 188 用法1 188 其它: 188 详解: 189 查看SQLITE表格内容 192 9、常用功能的实现 193 9.1、获取手机型号以及系统版本号 193 9.2、更改应用程序图标 194 9.3、迎合不同的手机分辨率 194 9.4.ANDROID屏幕适应的四个原则 195 9.5、ANDROID常用单位 196 9.6、取得屏幕信息 197 9.7、横竖屏 197 9.8、程序完全全屏 200 9.8.1锁屏锁键盘 200 9.9、程序的开机启动 201 9.10、动态START页面 208 9.11、彻底退出当前程序 212 9.12、获取应用程序的名称,包名,版本号和图标 212 9.13、调用ANDROID INSTALLER 安装和卸载程序 215 9.14、后台监控应用程序包的安装&卸载 216 9.15、显示应用详细列表 224 9.16、寻找应用 224 9.17、注册一个BROADCASTRECEIVER 225 9.18、打开另一程序 225 9.19、播放默认铃声 225 9.20、设置默认来电铃声 226 9.21、位图旋转 227 9.22、手机震动控制 228 9.23、SENSOR2D感应实例 228 9.24、运用JAVA MAIL包实现发GMAIL邮件 230 9.26、ANDROID键盘响应 236 9.27、后台监听某个按键 238 9.28、VECTOR用法 239 9.29、CURSOR 242 9.30、把一个字符串写进文件 244 9.31、把文件内容读出到一个字符串 245 9.32、扫描WIFI热点演示实例教程 246 9.33、调用GOOGLE搜索 249 9.34、调用浏览器 载入某网址 249 9.35、获取 IP地址 249 9.36、从输入流中获取数据并以字节数组返回 250 9.37、通过ANDROID 客户端上传数据到服务器 251 9.38、文件下载类 255 9.39、下载文件的进度条提示 263 9.40、通过HTTPCLIENT从指定SERVER获取数据 265 9.41、通过FTP传输文件,关闭UI获得返回码 266 9.42、激活JAVASCRIPT打开内部链接 266 9.43、清空手机COOKIES 267 9.44、检查SD卡是否存在并且可以写入 267 9.45、获取SD卡的路径和存储空间 268 9.46、将程序安装到SD卡 268 9.47、创建一个SD映像 269 9.48、查看手机内存存储 269 9.49、在模拟器上调试GOOGLE MAPS 271 9.50、建立GPRS连接 273 9.51、获取手机位置 274 9.5* 获得经纬度,地名标注在地图上 274 9.52、获得两个GPS坐标之间的距离 276 9.53、通过经纬度显示地图 277 9.54、路径规划 277 9.55、将坐标传递到GOOGLE MAP并显示 277 9.56、获取本机电话号码 280 9.57、获得手机联系人 280 9.58、2.0以上版本查询联系人详细信息 282 9.59、2.0以上版本添加联系人 285 9.60、拨打电话 287 9.61、发送SMS、MMS 287 9.62、监听电话被呼叫状态 288 9.63、监听要拨打的电话(可以后台进行修改号码) 290 9.64、后台监听短信内容 291 9.65、删除最近收到的一条短信 292 9.66、调用发短信的程序 293 9.67、后台发送短信 293 9.68、调用发送彩信程序 294 9.69、发送EMAIL 294 9.70、播放多媒体 295 9.71、控制音量 296 9.72、定义CONTENTOBSERVER,监听某个数据表 302 9.73、打开照相机 303 9.74、从GALLERY选取图片 303 9.75、打开录音机 303 9.76、语音朗读 303 9.77、手机获取视频流显示在电脑上 305 9.78、蓝牙的使用 313 9.79、一个很好的加密解密字符串 316 9.80、DRAWABLE、BITMAP、BYTE[]之间的转换 318 9.81、高循环效率的代码 320 9.82、给模拟器打电话发短信 321 9.83、加快模拟器速度 321 9.83.1、模拟器 “尚未注册网络” 322 9.84、EMULATOR命令行参数 322 9.85、如何进行单元测试 323 9.86、ANDROID自动化测试初探 324 9.86.1、捕获Activity上的Element 324 9.86.2、Hierarchyviewer 捕获Element的 328 9.86.3、架构实现 330 9.86.4、模拟键盘鼠标事件(Socket+Instrumentation实现) 332 9.86.5、再述模拟键盘鼠标事件(adb shell 实现) 334 9.87、反编译APK 344 9.88、更换APK图标(签名打包) 348 9.89、利用ANDROID MARKET赚钱 363 9.90、ANDROID-MARKET 使用 365 9.91、传感器 369 9.91.1、获取手机上的传感器 369 9.91.2、 371 9.92、时间类 372 * 获得日期或时间字符串 372 * num天前的日期 373 * num天后的日期 373 * 判断 thingdate 的 dotime 天后是否在今天之后 374 * 判断testDate+testTime是否在两个时间之内 375 附录: 378 附录1、XML布局中的常用属性 378 1.通用属性 378 2.Edit Text部分属性 381 3.layout_alignParentRight android:paddingRight 384 附录2、INTENT ACTION 385 附录3、ANDROID的动作、广播、类别等标志 387 ★★★附带工具包说明 393 1.APK反编译工具.rar 393 2.APK安装工具.rar 393
内容简介   《google android sdk开发范例大全(第3版)》在上一版的基础上,以android手机应用程序开发(采用android sdk 2.3.3)为主题,超过200多个范例全面且深度地整合了手机、网络及服务等多个开发领域,为读者提高程序设计能力提供了很大的帮助。    全书共分11章,主要以范例集的方式来讲述android的知识点,详细介绍了开发android的人机交互界面、android常用的开发控件、android手机收发短信等通信服务、开发android手机的自动服务功能和娱乐多媒体功能以及整合android与google强大的网络服务等内容。随书光盘中包括了所有范例的程序代码。    《google android sdk开发范例大全(第3版)》继承前两版由浅入深的方式,范例总数由原先的160多个增加到了200多个,在用户交互界面、手机控件、交互式通信服务、手机自助服务、娱乐多媒体等方面均增加了相应的范例来介绍新的开发技术,特别是新增加了第11章来专门介绍html5技术在android移动设备里的应用,相信当下两个热门技术的交汇会碰撞出不一样的火花。    《google android sdk开发范例大全(第3版)》内容由android的基础知识到实际开发应用,结构清晰、语言简洁,非常适合android的初学者和android的进阶程序开发者阅读参考。 目录 《google android sdk开发范例大全(第3版)》 第1章 了解、深入、动手做 1 1.1 红透半边天的android 2 1.2 本书目的及范例涵盖范围 3 1.3 如何阅读本书 4 1.4 使用本书范例 5 1.5 参考网站 6 第2章 android初体验 7 2.1 安装android sdk与adt/ddms 8 2.2 创建第一个android项目(hello android!) 11 2.3 android应用程序架构——从此开始 15 2.4 可视化的界面开发工具 18 2.5 部署应用程序到android手机 19 第3章 用户人机界面 22 3.1 更改与显示文字标签 23 3.2 更改手机窗口画面底色 24 3.3 更改textview文字颜色 26 3.4 置换textview文字 28 3.5 取得手机屏幕大小 29 3.6 样式化的定型对象 30 .3.7 简易的按钮事件 32 3.8 手机页面的转换 34 3.9 调用另一个activity 37 3.10 不同activity之间的数据传递 41 3.11 返回数据到前一个activity 44 3.12 具有交互功能的对话框 49 3.13 置换文字颜色的机关 51 3.14 控制不同的文字字体 52 3.15 如iphone拖动相片特效 54 3.16 自制计算器 56 3.17 关于(about)程序信息 58 3.18 程序加载中,请稍候 61 3.19 全屏幕以按钮重写 63 3.20 今晚到哪儿打牙祭 64 3.21 android变脸 67 3.22 打勾显示输入的密码 69 3.23 android多语系支持 71 3.24 判断手机操作系统版本是否允许运行程序 72 3.25 两个不同的程序彼此调用 75 3.26 指定安装应用程序迁移至sd卡 78 3.27 手机动态layout主题随手势物换迁移 79 第4章 史上超豪华的手机控件 84 4.1 edittext与textview共舞 85 4.2 设计具有背景图的按钮 86 4.3 给圣诞老人的信息 88 4.4 我同意条款 90 4.5 消费券采购列表 92 4.6 向左或向右 94 4.7 专业相框设计 96 4.8 自定义下拉菜单模式 99 4.9 动态添加/删除的spinner菜单 102 4.10 心爱小宝贝相片集 104 4.11 快速地搜索手机文件引擎 107 4.12 按钮也能随单击变换 109 4.13 具自动提示功能的菜单 110 4.14 数字及模拟小时钟设计 112 4.15 动态输入日期与时间 114 4.16 猜猜红桃a在哪儿 117 4.17 后台程序运行进度提示 121 4.18 动态文字排版 124 4.19 在activity里显示列表 128 4.20 以动态列表配置选项 130 4.21 查找程序根目录下所有文件 134 4.22 加载手机磁盘里的图片文件 137 4.23 动态放大缩小imageview里的图片 139 4.24 动态旋转图片 142 4.25 猜猜我在想什么 145 4

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值