Android6.0屏幕固定功能,如何开机只能运行当前app不能退出

需求:
接上回,还是那台小米平板4,终于拿到了root权限。并且实现了开机启动某app,现在的需求是:要求只能运行这个app,不能退出,不能回退到主屏幕,不能Home键,重启之后还是我的app,你不能退出,除非你输入万能密码。。。

背景:
然而之前用的是ScreenPin功能(也有翻译成报刊亭模式),这是Android自6.0开始系统内置的一个功能,主要用作商场演示等的场景,就是设定好之后,手机只能运行这个app(比如这个app是介绍手机的一个广告app,或者某工厂内的一个办公app,比如扫码,只能扫码用,别的干不了,因为你不能回到主屏幕,只能操作这一个)。这个系统内置功能长这个样子

可以看到有两个可操作项:“知道了”和”不用了“,那么这个时候如果点击”不用了“是不会激活ScreenPin的,跟操作普通app一样,想退出就退出,想结束任务就结束,没有任何限制。那么这一定不是我想要的。
PS. 如果进入了固定屏幕模式,除了重启手机之外另外一种方法是adb执行命令:
adb shell am force-stop xx.xx.xx 后面是你的包名。

步骤一  如果不想让用户看到上面的固定屏幕提示而直接固定了屏幕的话,你的应用必须要成为设备拥有者
来自StackoverFlow大神的解答:https://stackoverflow.com/questions/28437529/how-to-pin-an-app-without-a-dialog-android
这让我想起早年间用安卓机装某60安全卫士的时候提示绑定设备的场景,应该就是这里了。

那么问题来,如何将我的app注册为设备拥有者,直接搞之。

  1. AndroidManifest.xml注册一个继承自android.app.admin.DeviceAdminReceiver的receiver

    /rex/xml/device_admin内容:

    2. .DeviceAdminReceiver里毛都不用写

    3.ok代码部分到这里,然后adb shell进入到设备,切换su执行命令

    然而我却得到了这样的提示

    也是,都MIUI了,设备拥有者肯定不会空闲出来,但是打开设置却怎么也找不到绑定设备拥有者的地方,一定是雷总故意隐藏起来了。

    4.其他注册设备拥有者的方法,既然已经获取了root权限,那么系统目录简直我是畅行无阻,/data/system/device_owner.xml,创建这个文件,写入如下内容:

    然后reboot。挖槽还是不好死,而新建的device_owner.xml也不翼而飞,看来是遇到了鬼,于是便把目光投向了/system/app里的其他文件/夹,其中有一个叫XiaoMiFramework之类的名字,我居然删除了它,然后程序各种报错,然后reboot,然后再次执行

    居然出现了下面的提示:

后来的故事大家都知道了,白雪公主和七个小矮人从此过上了幸福快乐的生阿活。。。

参考链接:
1.How to pin an app without a dialog android
2.HOW TO TURN YOUR ANDROID APPLICATION INTO A KIOSK
3.Android Kiosk Mode Without Root
4.DeviceAdmin简单实践

#文章做折腾过程记录,不对任何变砖与异常负责

记录我是怎样把小米平板4(MIUI9.6)刷成开发板+获取root的

需求
实现一个app在小米平板4(MIUI9.6)上开机自动启动,如此而已。
然鹅,折腾的路确很长。

尝试一
作为一个半生熟的Android开发狗,那么开机启动一个app还不简单?我新建一个BootReceiver,我再申请权限android.permission.RECEIVE_BOOT_COMPLETED,我再声明Activity、Service、Intent什么的blablabla,整个流程做安卓开发的你一定不会不清楚,反正度娘是妥妥儿的告诉我。但是折腾完发现,无论如何就是不好死?开机app不启动,于是打开百度我会搜索这样的关键字“Android app 开机启动”,然后会找到这样的文章: https://blog.csdn.net/mmmccc000/article/details/52626075/ 其中你反复验证启动失败的原因:是不是Fast Boot模式?是不是权限添加的不对?是不是应用默认装到了sd卡里,我怎么样才能不装到sd卡而装到系统空间?各种各样的疑问,各种各样的尝试,但最后的结果就一个:还是不行。


尝试二
分割线分割前生,前生事此不再提,也就说使用开机广播那一套不知道是不行,还是还需要另外的协助?自省一下,前提条件是在小米平板4上装可以自动启动的app,那么小米平板4目前运行的是“MIUI9.6稳定版”,小米的系统肯定是深度定制版不知道有多深,但是小米可是有开发板的系统,是支持折腾的,那么问题来了,官网下载开发板地址是多少?此处内心独白:既然前面那套开机广播的脆脆弱弱(我自始至终都没有在模拟器上尝试,不知道为什么,可能是秀逗了),那么我可以不可以直接获取root权限,比如修改个init.d什么的直接就勾起我的Activity?脑回路有些大,但是没大胆就没大产不是。。。所以此处心里想的就是:开发板的系统自带肯定自带root权限,oh yes。。。
那刷小米的官方系统倒是很简单啊,直接设置里面手动选择安装包什么的就可以了,可是选来选取,刷来刷去我发现,账号依然不是root,adb连接到设备su依然不可用。

此处的插曲是,刷机之前需要解设备锁,也就是解锁BL(BootLoader),具体查看“更多设置” -> “开发者选项” -> “设备解锁状态“,如果因为下面这种情况卡住的话,告诉你只要在当前设备上换一个注册时间比较长,活跃度高的小米账号绑定设备,然后重新解锁就行。

请在此设备上登录该账号720小时后再尝试解锁该设备

 

迷茫时刻
可我真的记得有篇文章说的是小米开发板自带root,百度了N多文章,一天下来,脑子里什么都没有,全是这些内容,你只是个开发人员,你明白app生命周期,但系统原理你是无能为力的。要不淘宝上几十块刷一个吧,可是淘宝上问一下,有说能刷的,有说刷不了的。。。
屁不就刷个鸡?百度不行谷歌我还不行么。。。

尝试三 刷入TWRP
还是Google大法好,让我找到了这篇文章:《How to Install twrp Recovery Root XiaoMi Mi Pad 4》
文章清清爽爽,简单易懂,用到的几个文件清单如下,如果你不能下载的话,可以去这里:链接: https://pan.baidu.com/s/1NfYY2RRPmIwTILekDqv25w 提取码: zthz
1.TWRP 3.2 Xiaomi Mi Pad 4 对应Try.7z包里的recovery.img
2.SuperSu/Magisk
3.adb fast driver Try.7z包里没有这项,adb我觉得你自己能搞定
4.No-verity-opt-Entrypt
5.adb fastboot tools 参考3

参照着大神的文章,终于一步一步装上了TWRP,中间的过程如:

安装完成后手机是这样的,

 

然后adb shell进入设备,敲入su,发现$符号变成了#号才明白,root特么的成功了。

尝试四 怎么样把app安装到/system/app中
(以下操作在成功安装TWRP后进行)

既然机器已经root,那么我就可以乱来了是不是,我就可以直接
(以下操作在重启按住音量增大键+电源键进入TWRP后,选择Advanced->Terminal后进行,直接adb shell是没有vi等功能的)
1.vi init.d
2.GG 回车 a 回车 am start cc.lison.locked
3.Esc :wq
4.reboot
不好意思,轻度vim党,第二步的意思是翻到文件最后并加入am那句命令,然后保存重启,不好死,还是不好死,重启进入TWRP的Terminal发现刚才修改的init.d的内容没有了,改写的内容被覆盖掉了。。。怪不得一直提示我FileSystem read-only之类的,然后在TWRP中尝试文件管理器直接修改文件权限为755,还是不好死。。。又尝试了很多Magisk里的模块,不好死不好死。。。

尝试五
这一步尝试已经忘了搜索百度的什么关键字,总之是摸石头过河摸到了石头,详参这里:https://www.androidauthority.com/install-user-app-as-system-app-how-to-93522/
既然已经拿到了root权限,adb root + adb remount却不行,但是直接adb shell,然后切换su却可以(adb进入shell之后无法使用vi等工具),这是前提条件。于是又下载了一个ES 文件浏览器,安卓玩家对这个肯定不陌生,Magisk对其进行root授权(好像打开进入app就自动授权root权限),打开ES文件浏览器,把你要开机启动的app拷贝到/system/app目录,然后点击安装,世界就如此美好了。。。

PS。如果要删除安装在/system/app的app的话,只需要删除这个apk文件即可。

#文章做折腾过程记录,不对任何变砖与异常负责

Android WebView JS 与 Java Native 相互调用示例

直接上代码,有注释,学习Android过程记录。

Android Activity代码

布局文件LinearLayout布局,orentation=vertical,一个EditText,一个Button一个WebView,长什么样子的话想象一下就好了。

html文件,同样非常简单

参考资料:developer.android.com WebView

源码下载:WebViewNJs

apktool反编译与重新打包学习,apk反编译与重新签名学习,keytool-jarsigner

有个玩无线电的朋友问我会不会破解软件,我说太难的搞不了,有些是混淆过的;他说有个好像是测无线电天线的设备(天调?)是绑定蓝牙mac的让我给搞定下,安卓的app。

于是完成之后记录下。之前没事时候用过apktool,jd-gui,dex2jar等工具还有在线的,不过玩着玩着就扔掉了,这次答应了人家,起码弄出个123吧。

本次用到的工具:

1.apktool2.2

2.keytool,位于jdk/bin目录

3.jarsigner,位于jdk/bin目录

最初使用的直接apk包改扩展名zip,拿出classex.dex,然后dex2jar,拿到java文件之后想把源码直接拿出来复制到一个新工程里去,跟重新做差不多,因为看到里面只有四个Activity :

DeviceListActivity.java

DrawChart.java

MainActivity.java

MyApplication.java

比较简单,字面意思都能猜出是干嘛的,设备列表Activity,显示匹配/未匹配的蓝牙设备吧?DrawChart绘制曲线的吧?MainActivity和MyApplication都不用说了,主界面和入口,哇塞我敏锐的直觉囧。。。然后软件运行截图是这样的:

Mini60X APP运行截图
Mini60X APP运行截图

玩无线电的就是高大上,直接看不懂。。。

打开设备列表Activity之后就能看到写死的蓝牙地址,于是数组里再加入一个

但是复制到新工程之后就各种报错,比如do{ return;xxx;xxx; }while(1);这种,do里面直接return,肯定是不对的,然后各种重新反编译最后都不能直接拿来用,是不是我想的太简单了。。。虽然拿到了源码,但是有错误,尤其DrawChart里面的代码,gdi编程的错误真心搞不了。

然后又使用apktool d xxx.apk反编译得到smali文件列表(smali语法也玩不转)找到DeviceListActivity直接替换掉数组里面的蓝牙mac地址,ok第一步算完成了;

接着使用apk b xxx(xxx代表刚才反编译得到的文件路径),重新打包,在xxx/dist目录下会生成新的apk文件;这个时候apk是没有签名的,也不能安装到安卓手机中,需要对apk文件进行签名,过程如下:

1.首先生成签名文件,直接切换至%JAVA_HOME%/bin目录,使用
keytool -genkey -alias new.keystore -keyalg RSA -validity 20000 -keystore new.keystore
命令生成文件,中间不断下一步,输入密码填信息什么的,上面的语句就会在当前目录生成的签名文件new.keystore

2.使用jarsigner签名apk,将apk拷贝至%JAVA_HOME%/bin目录,输入命令:
jarsigner -verbose -keystore new.keystore -signedjar Mini60X-signed.apk Mini60X.apk new.keystore

new.keystore就是1步生成的签名文件,Mini60X-signed.apk就是要生成的签名之后的文件名,Mini60X.apk是你的apk文件名,运行结果如下:

jarsigner签名apk运行结果

就会在当前目录生成Mini60X-signed.apk,下面的Warning我没管它,然后就安装到手机上吧。

声明:本文只为学习安卓打包与签名机制使用,不针对任何app生产厂商,本文及作者不承担任何法律内外责任。

Android Studio 启动 Device Monitor报错:An error has occurred. See the log file…

详细错误如图:

Android Studio启动Device Monitor报错提示对话框

D:\xxx\sdk是我的sdk路径,于是到此目录下查看日志文件,描述如下:

错误信息说目录是只读的,但目录只有C:/Users/Lison Liou/.android,后面就没有了,于是干脆给目录加上Everyone用户的Full Control权限,结果还是不行。

后来在StackOverFlow上找到答案,Android DDMS (Monitor) does not start if user profile contains a space in it,说DDMS不会启动如果用户名包含空格,我的用户名的确包含空格,但是之前也是好用的,不解。

解决方法如下:以管理员身份运行cmd(必须),输入如下:

将带空格的用户与正常用户名建立链接(软连接或者硬链接就不知道了),Lison Liou是我的计算机用户,成功后会提示:

symbolic link created for Lison%20Liou <<===>> Lison Liou

搞定。

 

使用Netty进行Android与Server端通信实现文字发送接收与图片上传 – 原创

ANOTHER TITLE:

Let’s use netty to achieve text send and receive and  image transfer to server based on android and jdk1.7

就让我来Rap<MC Hotdog>,使用netty进行安卓端发送接收文字,并且附带发送图片功能,折腾了几天的netty总算有点眉目了,做下记录。

需求是安卓端拍照上传到服务器,服务器返回上传成功或失败bla bla bla,需求比较简单。最初使用的传统的post加multipart/form-data,一般的手机照片大小1-2M,测试没问题,但实际情况是有的用户使用3G网络,有的4G,有的WIFI还有的使用2G,网络环境稍微有点差的上传图片时间持续到十多分钟(我都不好意思说了),然后想到了使用socket,然后google到了netty,有的大神说这样的需求没必要上netty啊,其实我就是想通过这个需求学习下关于socket,关于netty,关于channel,关于byte[],关于NIO,多学习点总是没坏处的,后面我也可以牛逼点说玩过高性能基于事件的异步网络框架了。

刚开始直接啃的netty.io的document,照葫芦画瓢抄完了TimeServer之后就满世界的google其他的netty知识,比较零散,然后入手了《Netty权威指南第二版》,啃了几章之后怎么也是TimeServer,不过对NIO一些基本组件有了一个初步的认识。

OK,入正题,我要实现一个Demo,就说是个Netty的聊天室吧(群聊,没有单聊的功能,demo味儿十足),不过客户端换成了安卓,一个服务器对多个客户端,所有数据经过服务器端,要定义中间信息交换组件。关于Google的Protobuf还有MessagePack和JBoss Marshalling这些编解码中间件都没有玩过,似乎有点看不懂,我的需求很简单,如下图(抱歉键盘党多年手已废掉,可能只有我自己看得懂):

Echo-Server、Echo-Pojo、Lets's Chat Relationship

一共包含三个对象:

Echo-Pojo,信息交换中间对象,用于Android端与Server端封装byte[]之后的序列化对象。

Let’s Chat,安卓客户端,构建EchoMessage或EchoFile对象,然后发送到channel;EchoMessage与EchoFile用于服务端判断信息对象的类别。

Echo-Server,服务端。ChannelRead时判断信息对象类型,决定是广播到所有用户还是保存文件。

对于ByteBuf对象一直没有弄很明白,所以上述也就没有使用。

来张安卓端(小米PAD)Let’s Chat的运行截图:

Let's Chat小米Pad运行截图
Let’s Chat小米Pad运行截图

三星手机Let’s Chat运行截图:

Let's Chat三星手机运行截图
Let’s Chat三星手机运行截图

服务端(Echo-Server)的运行截图:

Echo-Server输出日志与说明截图
Echo-Server输出日志与说明截图

上传的文件:

QQ截图20160518132859

文件名格式为:Build.MANUFACTURE+UUID.randomUUID()+”.jpg”,第二张图片为12.9M,上传时间六七秒钟,应该还有优化的空间。

Echo-Pojo的代码就不截图了,直接下载查看就可以,或者也可以继续扩展,目前只是图片跟文字。

上述功能一共分为三个程序,Echo-Pojo信息交换对象使用eclipse-Mars2开发,Echo-Server使用Intellij idea开发,Let’s Chat使用Android Studio2,有点蛋疼,但好在实现了功能,中间折腾的很多,尤其公司电脑跟家里电脑jdk不一致,一个1.8,一个1.7,因为这个出了很多莫名的错误,也浪费了很多时间,中间的各种折腾各种烦躁就不记录了。

代码注释比较少,也有很多废弃的没有删掉,只是实现了功能可以运行,没有做完全整理,有问题可以直接回复或者@EMAIL ME

借鉴刘源的NettyFileTransfer,只是我把客户端修改成了Android,然后Netty版本我用的是4.0.36Final,感谢大神。

剩下的就是把功能揉进项目里了,Keep Fighting !

项目开源地址:https://github.com/LisonLiou/netty-learning.git

Android Camera: start preview failed; API10. Android 2.3 startPreview失败解决方法

代码中使用了开源项目(OSChina 客户端2.0)的源码,zxing做二维码扫描识别。搬过来之后在Android 2.3机器运行报错:
Unexpected error initializing camera java.lang.RuntimeException: startPreview failed

startPreview失败报错详细如下:

找到了一些文章,有的说Camera的open与startPreview不能多次调用,需要设置标记,查看OSChina的源码之后发现有标记,不是这个。

后来找到说低版本的SDK需要setType一下,设置成:SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS,尝试后依然没有解决问题。

最后是借鉴了这篇文章(不知道是不是原始链接)解决了问题,holderView要放在holder的allCallback前面,完整如下:

就是这两句:

if(Build.VERSION.SDK_INT<11)
scanPreview.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

scanPreview.getHolder().addCallback(this);

OSChina客户端的2.0支持的最低版本是15,已经不再支持API10,不能PullRequest一下了。

Android控件之带清空按钮(功能)的AutoCompleteTextView自动提示

功能折腾完了记录一下。带删除按钮的AutoCompleteTextView,普通的自动提示控件用起来比较简单,准备好数组给控件setAdapter一下行了,这里要说的是提取sqlite中的数据绑定并且加上清空按钮,先来张图片。

带删除按钮的AutoCompleteTextView

最初没有用过AutoCompleteTextView的时候,就直接百度了下,想必都会得到这样一段代码:

上面的代码简单,但是不大实用,比如我的需求就是,要有清空按钮。然后继续百度,又找到了这篇文章(继承AutoCompleteTextView自定义控件ClearableAutoCompleteTextView,自定义adapter方式实现)

然后就闭着眼抄了一下,修改一点,满足了需求。其实碰上问题就百度这种方式是很不对的,所有的控件使用方法在Android Develop Docs中都有介绍:/sdk/docs/reference/android/widget/AutoCompleteTextView.html。哎,我们都是应用程序猿,但我们又连API都不看。。。或许你觉得密密麻麻的英文看着头疼?或许你又翻不了墙?或许吧,还是那句老话,成功的人找方法,而失败的人嘛,对吧。

今天想给AutoCompleteTextView加个图标,就是上图左侧那个放大镜按钮,于是找好素材,设置drawableLeft,运行,发现没有效果。于是查看自定义控件的源码(就是上面使用自定义adapter的那个链接里提到的),发现是在init方法中绑定了setOnTouchListener, 然后onTouchListener中又通过MotionEvent判断触摸的区域,而触摸的对象使用的是setCompoundDrawablesWithIntrinsicBounds,这不就是drawableLeft、drawableRight所对应的方法嘛,果断删除自定义控件ClearableAutoCompleteTextView,使用原生AutoCompleteTextView,加入drawableLeft放大镜按钮,drawableRight使用删除小图标,然后对控件setOnTouchListener,代码如下:

一下子就腰不疼腿不酸了。注意“触摸点位置判断”那行,意思是当前触摸点如果大于AutoCompleteTextView的宽度减去paddingRight的值再剪掉一个固定值(R.dimen.space_4_touch,我这里是10dip),就算触摸到了删除小图标;固定值是多少根据情况来,值越大可以触摸的空间越大,相反越小,用户可能就点击不到那块区域(删除小图标的区域)从而激发不了事件,这也算是优化用户体验的一种手段吧。

所以,按照上述代码,也可以举一反三为放大镜按钮加上事件,或者为删除小图标设置隐藏/显示条件,比如文本框没有内容时删除图标隐藏,有内容则显示等。

Continue reading

Android Debug Bridge adb – 安卓调试桥 官方文档汉化记录(原创)

名词释义:
模拟器:指使用ADT或者第三方软件创建的安卓模拟器
安卓设备(设备):指运行安卓系统的硬件、含手机、Pad,TV等

Android Debug Bride简称adb,是一个多用途的命令行工具,能够让你与你的安卓模拟器或者安卓设备进行通讯。它是一个包含三个组件的C-S程序:

  1. 客户端。运行在你的开发机上。你可以通过shell发送一条adb命令用开调用一个客户端。其他的Android工具例如ADT插件和DDMS也可以创建adb客户端。
  2. 服务端。运行在你的开发机的后台进程中,服务端管理客户端与运行在模拟器或设备上的adb守护进程的通信工作。
  3. 守护进程。是一个运行在每个模拟器或者设备上的后台进程。

可以在<sdk>/plateform-tools目录找到adb工具。

当你启动一个adb客户端的时候,客户端会首先检查是否已经有adb服务端进程在运行。如果没有,就开启服务进程。当服务进程开启之后,它会绑定本地TCP的5037端口并且监听来自adb客户端的命令(所有的adb客户端都使用5037端口与服务端进行通信)。

然后服务端与所有正在运行的模拟器/设备建立连接。服务端通过扫描模拟器/设备的开放端口(5555-5585范围内的奇数端口)来定位设备。当服务端发现adb守护进程时,就与这个端口建立连接。需要注意的是模拟器/设备获取的是一对连续的端口号(偶数端口号用于控制台连接,奇数端口号用于adb连接)示例:

模拟器1   控制台端口号:5554
模拟器1   adb端口号:5555
模拟器2   控制台端口号:5556
模拟器2   adb端口号:5557

如上所述,模拟器已经与adb的5555端口建立了连接,与控制台监听5554端口是一样的。

一旦服务器与所有模拟器建立连接,就可以通过adb命令访问这些设备。基于服务端管理着所有模拟器/设备并且处理多个adb客户端的命令,你可以通过任意一个adb客户端控制任意的模拟器/设备(或者通过脚本)。

Enabling adb Debugging 开启adb调试


为使用usb连接的设备使用开启adb,需要在设备的系统设置->开发者选项中开启USB调试。

在Android4.2或者更高版本的系统中,开发者选项默认是隐藏的。显示的话,需要依次点击设置->关于手机,连续点击内部版本号(Build Number)七次。然后返回上一个界面的底部会出现开发者选项。

在有些设备中,开发者选项界面可能所在的位置或者名称会有不同。

注意:当用电脑连接一个运行着Android4.4.2或者更高版本的系统,系统会弹出一个对话框(显示RSA key)询问是否允许通过这台电脑进行调试。这个安全机制确保用户的设备不会被USB调试或者执行其他adb命令,除非用户点击对话框的确认按钮。这需要你的adb版本是1.0.31(在SDK Plateform-tools r16.0.01或者更高版本中)为了调试运行Android4.2.2或更高版本的系统。
更多关于连接一个通过USB连接的设备,请阅读Using Hardware Devices。

Syntax 语法


你可以从开发机上通过一个命令行工具发送一条adb命令(或者一个脚本),用法如下:

如果当前只连接了一台模拟器/设备,adb命令就会发送到这台默认的设备。如果有多个模拟器/设备在运行并且已连接,就需要使用-d-e、或者-s选项来指定目标设备并且执行命令。

Commands 命令


下面这张表列出了所有adb支持的命令,以及他们的解释及用途。
表1 可用的adb命令

类别 命令/选项 描述 注释
Target Device -d 向唯一连接的USB设备执行一条adb命令 如果连接多台设备将返回错误
-e 向唯一连接的模拟器执行一条adb命令 如果正在运行多个模拟器将返回错误
-s &lt;serialNumber&gt; 向指定的模拟器/设备执行一条adb命令,模拟器名称例如:emulator-5556 See Directing
Commands to a Specific Emulator/Device Instance
.
General devices 打印所有已经附加的模拟器/设备列表 See Querying for Emulator/Device Instances for more information.
help 打印adb支持的命令列表
version 打印adb版本号
Debug logcat [option] [filter-specs] 将log data输出到屏幕
bugreport 将系统信息,状态,logcat数据输出到屏幕
jdwp 在一个给定的设备上打印可用的JDWP进程列表 可以使用端口转发 jdwp:<pid> port 转发指定的连接到一个特定的JDWP进程,例如:
adb forward tcp:8000 jdwp:472
jdb -attach localhost:8000

 

Data install &lt;path-to-apk&gt; 将一个安卓应用程序(指定apk文件的全路径)发送到模拟器/设备
pull &lt;remote&gt; &lt;local&gt; 从模拟器/设备拷贝一个指定的文件到开发机。
push &lt;local&gt; &lt;remote&gt; 将一个指定的文件拷贝至模拟器/设备上。
Ports and Networking forward &lt;local&gt; &lt;remote&gt; 将本地socket连接的指定端口转发至指定的远程模拟器/设备端口 指定端口可以使用这些格式:

  • tcp:&lt;portnum&gt;
  • local:&lt;UNIX domain socket name&gt;
  • dev:&lt;character device name&gt;
  • jdwp:&lt;pid&gt;
ppp &lt;tty&gt; [parm]... 通过USB运行PPP(点对点协议):

  • &lt;tty&gt; — the tty for PPP stream. For example dev:/dev/omap_csmi_ttyl.
  • [parm]... — zero or more PPP/PPPD options, such as defaultroute, local, notty, etc.

    注意不要自动启动一个PPP连接

Scripting get-serialno 打印adb示例的序列号串 查看 Querying for Emulator/Device Instances 获取更多信息
get-state 打印模拟器/设备的adb状态
wait-for-device 在设备上线前阻止命令执行。 可以向adb预置这条命令,这种情况下,adb会等待模拟器/设备连接后才执行adb命令,示例:

注意这条命令不会导致adb一只等待整个系统启动完毕。因此,你不应该预置一条需要等待整个系统完全启动的命令。举例来说,安装命令需要Android Package Manager启动,而Android Package Manager需要整个系统完全启动,类似于这样的命令

会发送安装命令当模拟器或设备连接到adb服务端,但之前Android系统已经完全启动,因此会得到一个错误的结果。

Server start-server 检查adb服务端进程是否正在运行,如果没有运行,则运行它。
kill-server 结束adb服务端进程
Shell shell 在目标模拟器/设备上开启一个远端shell 查看 Issuing Shell Commands 获取更多内容
shell [shellCommand] 在目标模拟器/设备上发送一个shell命令执行后退出。

要不先到这儿。

Android解决:The content of the adapter has changed but ListView did not receive a notification

项目中的错误,记录一下。

完整的错误信息如下:

大意是说adapter内容已改变,但listview未收到通知,上下文不同步了。

精简一下,我有两个ActivityA和ActivityB。首先打开ActivityA,显示一个列表(listView),然后点击一个按钮startActivityForResult打开了B,B中添加了信息提交后setResult到A。B负责添加数据,添加完数据回到A,通知A重新load一遍远端数据,没问题(不要问我为什么要重新load一遍)。

在Activity A中单独起了一个线程去处理任务(请求远端service获取数据),handler收到message之后启动这个线程t,然后Activity A又startActivityForResult了另一个Activity B(这时候ActivityA已经onPause了,但是线程依然在运行,而且还在handler的callback队列中),当Activity B处理完逻辑setResult给Activity A(并且把自己给finish掉),需要让ActivityA重新请求service数据,也就是说线程t要重新运行一次,这时候handler里面已经有线程t这个对象了,然后就导致了上述的错误(好像这么说很牵强啊),参照CSDN牛人的文章,还是线程与上下文的事。

解决办法,在ActivityA的onPause将线程t从handler的callback中移除(然后handler再次收到同样的请求service的message时会重新将此线程t加入到callback队列中),如下:

 

ActivityA的完整代码如下:

贴首歌在:

新解:

还是上面的错误信息,注意这句:

确保adapter的内容不要在后台线程中修改,只能从UI线程中修改。而我的代码是直接message交给handler去处理的,难道这也算后台线程?于是想到了Runnable对象,它是依附于UI线程的,然后使用了handler.post(new Runnable())的方法,测试成功。