118、adb 连接设备出现unable to connect devices 问题
通过网络adb连接设备:
adb connect [设备的ip地址]
adb disconnect 或者adb disconnect [设备的ip地址]
未root的手机,不能连接,提示 unable to connect devices
解决方法:
先usb连接上,输入adb tcpip 5555
再输入 adb connect 192.168.1.7:5555就可以连接上
119、activity的生命周期回调函数:
onCreate()
onStart():用户可见
onResume():在前台,用户可见
onPause():用户可见
onStop()
-----onRestart()
onDestory()
打开应用时先后执行了onCreate()->onStart()->onResume三个方法.
按BACK键时,我们这个应用程序将结束,这时候我们将先后调用onPause()->onStop()->onDestory()三个方法.
按HOME键,onPause()->onStop()
再次启动ActivityDemo应用程序时,则先后分别执行了onRestart()->onStart()->onResume()三个方法
当用户点击A中按钮来到B时,假设B全部遮挡住了A,将依次执行A:onPause -> B:onCreate -> B:onStart -> B:onResume -> A:onStop。
此时如果点击Back键,将依次执行B:onPause -> A:onRestart -> A:onStart -> A:onResume -> B:onStop -> B:onDestroy。
120、一张图片在android中如果不压缩,实际占用内存计算
例如一张1440*2448(351K)大小的图片,加载到内存中,不压缩
1440*2448(个像素)*4(RGBA,每个像素有4个颜色值)*8(每个颜色值8bit) = 112803840 bit = 13.45MB(放大40倍左右)
121、今天分析了下activity的启动流程源码分析,大概总结下:
在我们学习AIDL的时候我们activity调用service里面的方法是通过Binder的(就是Service里面有个内部类实现了IBinder接口,在onBind方法中会把这个对象返回给activity里面
我们在activity里面就可以使用这个Binder类的应用来调用service里面的方法了)。
网上摘录:
在Actvity启动过程中,其实是应用进程与SystemServer进程相互配合启动Activity的过程,其中应用进程主要用于执行具体的Activity的启动过程,回调生命周期方法等操作,
而SystemServer进程则主要是调用其中的各种服务,将Activity保存在栈中,协调各种系统资源等操作。
注意细节:
a.
问题:
通过这里的代码我们可以发现,其实我们在Activity中调用startActivity的内部也是调用的startActivityForResult的。
那么为什么调用startActivityForResult可以在Activity中回调onActivityResult而调用startActivity则不可以呢
答案:
可以发现其主要的区别是调用startActivity内部调用startActivityForResult传递的传输requestCode值为-1,
也就是说我们在Activity调用startActivityForResult的时候传递的requestCode值为-1的话,那么onActivityResult是不起作用的。
实际上,经测试requestCode的值小于0的时候都是不起作用的,所以当我们调用startActivityForResult的时候需要注意这一点。
b.
在查看execStartActivity方法之前,我们需要对mInstrumentation对象有一个了解 什么是Instrumentation
Instrumentation是android系统中启动Activity的一个实际操作类,也就是说Activity在应用进程端的启动实际上就是Instrumentation执行的,那么为什么说是在应用进程端的启动呢
实际上acitivty的启动分为应用进程端的启动和SystemServer服务进程端的启动的,多个应用进程相互配合最终完成了Activity在系统中的启动的,
而在应用进程端的启动实际的操作类就是Intrumentation来执行的,可能还是有点绕口,没关系,随着我们慢慢的解析大家就会对Instrumentation的认识逐渐加深的。
可以发现execStartActivity方法传递的几个参数:
this,为启动Activity的对象;
contextThread,为Binder对象,是主进程的context对象;
token,也是一个Binder对象,指向了服务端一个ActivityRecord对象;
target,为启动的Activity;
intent,启动的Intent对象;
requestCode,请求码;
options,参数;
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
}
c.
Binder接口 –> ActivityManagerNative/ActivityManagerProxy –> ActivityManagerService;
这样,ActivityManagerNative与ActivityManagerProxy相当于一个Binder的客户端而ActivityManagerService相当于Binder的服务端,
这样当ActivityManagerNative调用接口方法的时候底层通过Binder driver就会将请求数据与请求传递给server端,并在server端执行具体的接口逻辑。
需要注意的是Binder机制是单向的,是异步的,也就是说只能通过client端向server端传递数据与请求而不同等待服务端的返回,也无法返回.
那如果SystemServer进程想向应用进程传递数据怎么办
这时候就需要重新定义一个Binder请求以SystemServer为client端,以应用进程为server端,这样就是实现了两个进程之间的双向通讯。
d.
这里通过我们刚刚的分析,ActivityManagerNative.getDefault()方法会返回一个ActivityManagerProxy对象,那么我们看一下ActivityManagerProxy对象的startActivity方法:
这里就涉及到了具体的Binder数据传输机制了,我们不做过多的分析,知道通过数据传输之后就会调用SystemServer进程的ActivityManagerService的startActivity就好了。
以上其实都是发生在应用进程中,下面开始调用的ActivityManagerService的执行时发生在SystemServer进程。
e.
Activity生命周期中的第一个生命周期方法终于被我们找到了。。。。也就是说我们在启动一个Activity的时候最先被执行的是栈顶的Activity的onPause方法。
(一般我们可能认为是新的activity的onCreate方法,通过源码分析可以知道不是的)
记住这点吧,面试的时候经常会问到类似的问题。
f.
Activity的启动流程一般是通过调用startActivity或者是startActivityForResult来开始的
startActivity内部也是通过调用startActivityForResult来启动Activity,只不过传递的requestCode小于0
Activity的启动流程涉及到多个进程之间的通讯这里主要是ActivityThread与ActivityManagerService之间的通讯
ActivityThread向ActivityManagerService传递进程间消息通过ActivityManagerNative,ActivityManagerService向ActivityThread进程间传递消息通过IApplicationThread。
ActivityManagerService接收到应用进程创建Activity的请求之后会执行初始化操作,解析启动模式,保存请求信息等一系列操作。
ActivityManagerService保存完请求信息之后会将当前系统栈顶的Activity执行onPause操作,并且IApplication进程间通讯告诉应用程序继承执行当前栈顶的Activity的onPause方法;
ActivityThread接收到SystemServer的消息之后会统一交个自身定义的Handler对象处理分发;
ActivityThread执行完栈顶的Activity的onPause方法之后会通过ActivityManagerNative执行进程间通讯告诉ActivityManagerService,栈顶Actiity已经执行完成onPause方法,继续执行后续操作;
ActivityManagerService会继续执行启动Activity的逻辑,这时候会判断需要启动的Activity所属的应用进程是否已经启动,若没有启动则首先会启动这个Activity的应用程序进程;
ActivityManagerService会通过socket与Zygote继承通讯,并告知Zygote进程fork出一个新的应用程序进程,然后执行ActivityThread的mani方法;
在ActivityThead.main方法中执行初始化操作,初始化主线程异步消息,然后通知ActivityManagerService执行进程初始化操作;
ActivityManagerService会在执行初始化操作的同时检测当前进程是否有需要创建的Activity对象,若有的话,则执行创建操作;
ActivityManagerService将执行创建Activity的通知告知ActivityThread,然后通过反射机制创建出Activity对象,并执行Activity的onCreate方法,onStart方法,onResume方法;
(源码看是通过类加载器来加载的,也是反射的一种)
ActivityThread执行完成onResume方法之后告知ActivityManagerService onResume执行完成,开始执行栈顶Activity的onStop方法;
ActivityManagerService开始执行栈顶的onStop方法并告知ActivityThread;
ActivityThread执行真正的onStop方法;
自己总结:
通过源码分析可以看到:
startActivity(客户端) --- ActivityManagerNative.getDefault() --- 进入到ActivityManagerService里面(服务端)。
【ActivityManagerNative是一个抽象类继承Binder,具体的实现类是ActivityManager】所以这两个进程是通过ActivityManagerNative这个Binder通信的。
服务端 --- app.thread.scheduleLauncherActivity(IApplicationThread) --- ApplicationThread(是ActivityThread的一个内部类)(客户端)
【app.thread是一个IApplicationThread,也是一个Binder接口,具体是实现类是ApplicationThread】所以最终调用到了ActivityThread里面的方法了,又回到客户端了
最终就是通过类加载器,加载Activity类,然后调用onCreate方法启动Activity
所以2个进程间通信是通过Binder实现的。具体Binder底层是怎么通信的,还需要继续研究。
122、iperf3.0编译
sudo -s
source /etc/profile
export PATH=/home/hw/CTS/cts/android-ndk-linux/AndroidToolChain/bin:$PATH
make distclean
./configure --host=arm-linux CC=arm-linux-androideabi-gcc CXX=arm-linux-androideabi-g++ CFLAGS=-static CXXFLAGS=-static
tempdir = "/data/data/com.example.test";
test->outfile = stdout;
make
123、android使用su命令
String cmd = "ls -l /data/log/LogService/0/";
process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("ls -l /data/log/LogService/0/\n");//一定要加\n分割
os.writeBytes("exit\n");
os.flush();
//process = Runtime.getRuntime().exec(cmd);
buf = new BufferedReader(new InputStreamReader(process.getInputStream(), "utf-8"));
int status = process.waitFor();//0正常,1无权限,2找不到文件
Log.d("gaoqiang", "status:" + status);
String str = "";
final StringBuffer sb = new StringBuffer();
while ((str = buf.readLine()) != null) {
Log.d("gaoqiang", str+"\n");
sb.append(str);
}
Toast.makeText(this, sb.toString(), 1).show();
124、非root的手机,将下载的命令push到手机上执行。
有时候我们需要在app中执行一个命令,例如iperf,我们不想重新写个demo,只是想验证下命令是不是能正常执行。
这个时候我们可以在 /data/local/tmp目录下执行
步骤:
1.push到/data/local/tmp/下(例如push iperf命令到这个目录下)
2.chmod 777 iperf
3./data/local/tmp/iperf -c 192.168.1.5
备注:其它的命令也一样,例如下载busybox也可以执行
125、android traceroute功能实现
在windows下面的命令【tracert】
C:\Users\CHINA\Desktop>tracert www.tencent.com
通过最多 30 个跃点跟踪
到 ssd.tcdn.qq.com [119.147.227.25] 的路由:
1 <1 毫秒 <1 毫秒 <1 毫秒 192.168.1.1
2 1 ms 1 ms <1 毫秒 192.168.0.200
3 3 ms 5 ms 4 ms 100.64.0.1
4 3 ms 3 ms 3 ms 253.185.37.59.broad.dg.gd.dynamic.163data.com.cn [59.37.185.2
5 * * * 请求超时。
6 * * * 请求超时。
7 * * * 请求超时。
8 * * * 请求超时。
9 13 ms 13 ms 13 ms 119.147.227.25
跟踪完成。
在linux下面的命令【traceroute】,但是android里面是没有这个命令的,使用busybox很多需要有root权限。
现在有2种实现方案:
1、使用交叉编译好的traceroute命令,这个暂时没有找到好的方法。
2、使用ping去实现。【github有很多这种案例,可以参考】
ping -c 1 -W 10 -t 1 www.baidu.com (获取每个节点的ip)
解析出ip地址,查询ip的位置
ping -c 1 - W 10 192.168.1.1 (解析出ping的时延,可以ping多次,window上的tracert命令是ping了3次)
MTU的探测方法
windows系统:
查看网卡的mtu的值
netsh interface ipv4 show interfaces
修改本地的mtu值
netsh interface ipv4 set subinterface "本地连接 2" mtu=1500 store=persistent
测试最大MTU值方法
ping -n 1 -f -l 1472 www.baidu.com
-f不允许私自拆分数据包
-l发送指定大小的数据包
android 系统 :
查看手机mtu值设置
cat /sys/class/net/wlan0/mtu
ifconfig命令也可以查看
ip ad |grep wlan0 也可以查看
【ping -c 1 -M do -s 1373 www.baidu.com】nova plus手机验证结果
1|shell@HWMLA:/sys/class/net/wlan0 $ ping -c 1 -M do -s 1373 www.baidu.com
ping -c 1 -M do -s 1373 www.baidu.com
PING www.a.shifen.com (163.177.151.109) 1373(1401) bytes of data.
ping: local error: Message too long, mtu=1400
--- www.a.shifen.com ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms
【ping -c 1 -M do -s 1373 www.baidu.com】p8max手机验证结果
shell@HWP8max:/ $ ping -c 1 -M do -s 1373 www.baidu.com
ping -c 1 -M do -s 1373 www.baidu.com
PING www.a.shifen.com (163.177.151.109) 1373(1401) bytes of data.
From 192.168.3.3: icmp_seq=1 Frag needed and DF set (mtu = 1400)
--- www.a.shifen.com ping statistics ---
0 packets transmitted, 0 received, +1 errors
只有设置1372才能通过,加上28的包头大小刚好1400。所以测试不了网关的mtu最大值
设置手机的mtu值(需要root手机)
ip link set dev wlan0 mtu 1500
126、在调试已安装好的应用方法(手机需要root)
有时候安装了app,在启动的时候想打断点调试,如果等点击app启动再在as中启动断点会很快就消失了,断点位置已经运行过了。
这个时候我们可以使用命令来启动指定的activity【am start -D -n com.hw.smarthome/com.hw.smarthome.about.AgreementActivity】
输入命令的时候页面会弹框提示连接debugger,这个时候在as中把调试器关联上就可以运行断点了
127、对文本指定的字符修改颜色和大小,加粗等的方法
SpannableString SpannableStringBody = new SpannableString(this.getString(R.string.app_policy_msg_new));
SpannableStringBody.setSpan(new StyleSpan(Typeface.BOLD), 29, 84, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
cView.setText(SpannableStringBody);
可以使用SpannableString,可以设置样式。
128、退出app方法:
App.systemExit();
自杀进程
Process.killProcess(Process.myPid());
129、调试本地mysql数据库
启动服务:【net start mysql57】启动这个服务名
130、将一键提单的代码放到linux上使用gradlew编译出现的问题:
a、访问不到gradle里面配置的仓库地址
解决方法:配置代理服务器
b、提示没有licence的错误 “Warning: License for package Android Support Repository not accepted.”
原因:这个是由于在uploadLog模块中使用了和linux电脑中sdk不一样的support-v4包,导致需要license。
解决方法:将版本修改为25.1.1