如何下载并导入Android系统源代码到Android Studio
如何下载并导入Android系统源代码到Android Studio
StringBuffer与StringBuilder源代码分析
用def定义的变量时无类型的变量,这里所说的无类型的变量,并不表示该变量就不属于某一个类型了,def修饰变量正是Groovy为动态语言的标记,大概def修饰变量就相当于Java中Object来修饰变量吧。如果通过使用def关键字使用可选类型,那么整数的类型将是可变的:它取决于这个类型实际包含的值。
1 | assert a instanceof Integer |
如果所定义的函数没有参数,那么必须在调用的时候加上括号。
要有返回值的类型声明,如def、void、String等。
可以使用return返回值,若不写,则默认返回最后一行的值,没有则为null。
A closure in Groovy is an open, anonymous, block of code that can take arguments, return a value and be assigned to a variable. A closure may reference variables declared in its surrounding scope. In opposition to the formal definition of a closure, Closure in the Groovy language can also contain free variables which are defined outside of its surrounding scope.Apache Groovy Doc
1 | { println 'hi' } |
1 | def str='hello world' |
1 | def timesThree = { |
1 | def p = new Person(name:'Jessica', age:42) |
至此基本的东西差不多解决了。
使用友盟对应用进行信息收集时,其中包含有一个渠道名。渠道姑且可以认为是一个商店吧,如果应用要在很多个商店上面上架的话,一直改太麻烦了。有一个叫做多渠道打包的东西自然而然地走了过来。
1 | <meta-data |
如上所示,如果需要换一个渠道的话,重新改的话就特别麻烦了。先将其中的value替换成占位符${UMENG_CHANNEL_VALUE}
。接下来到模块下的build.gradle
中进行相应的修改。修改大致如下:
1 | <meta-data |
接下来配置build.gradle
1 | defaultConfig { |
在buildType{}前添加下段,并在buildType的release中添加signingConfig signingConfigs.release
1 | signingConfigs { |
打release版本的包时就会使用其中所配置的签名了。
不同gradle版本间存在一些差异,如果报错了,google修改一下。
1 | applicationVariants.all { variant -> |
build.gradle
真的是神奇,有一些用法还是可以去学学。当前的build.gradle
文件的整体如下所示:
1 | android { |
签名,顾名思义与生活中的签名类似,为某个东西签了名,那么这个东西就与所签的名字产生了某种关系,如归属等。
这是因为Android系统的要求就是这样,Android系统要求每一个Android应用程序必须要经过数字签名才能够安装到系统中,也就是说如果一个Android应用程序没有经过数字签名,就无法安装到系统中。
为什么在AS中直接RUN可以安装到系统上?
因为这种方式会使用Android Studio默认生成的debug签名,去给应用进行签名。
如果同一应用使用不同的签名,那么将不能覆盖安装,必须先卸载之前的,然后再安装。
1)两个程序的入口Activity是否相同。两个程序如果包名不一样,即使其它所有代码完全一样,也不会被视为同一个程序的不同版本; 2)两个程序所采用的签名是否相同。如果两个程序所采用的签名不同,即使包名相同,也不会被视为同一个程序的不同版本,不能覆盖安装。
所以这也是为什么,同样一份代码,由不同的机器RUN,然后安装到同一台设备上时,需要先卸载之前的应用,而后再安装此次的。
原因就是每台机器默认生成的debug签名都不一样!
应用商城不接受用debug签名签的应用,必须使用自己的签名。
使用自己的签名可以避免应用不具备升级功能。
其实关于堆栈的问题在脑海中盘旋了挺久的了。从C语言开始,到数据结构,再到现在的Java,它一直在!现在就让我们从头开始吧。
首先应该明确堆和栈是不同的东西,其次数据结构中的堆和栈与编程语言中的堆和栈不是同一个概念。
栈:即Stack,是一个LIFO队列。对它的操作有pop(),push(),peek()等。
堆:即Heap,是一棵完全二叉树(heap的某一种),它的特点是父节点的值大于(小于)两个子节点的值(分别称为大顶堆和小顶堆)。
具体内容可以参考后续关于数据结构的系列博客。
1 | int a = 0; //全局初始化区 |
一个比较直观的感受就是使用malloc()函数分配出来的空间在堆上,其它经过系统初始化的在栈上。堆上的不能自己回收,栈上的会随着函数结束后自动回收。
堆区:存放所有new出来的对象本身
栈区:存放基本类型的变量数据和对象的引用
静态域:存放静态成员(由static定义)
常量池:存放字符串常量和基本类型常量(public static final)
为什么会有这么一篇网上有很多种解说版本的博客?因为我看懂了很多次,都没有把自己的想法记下来,然后就忘了。那样不仅浪费时间、而且还有点伤积极性。
在《第一行代码》中看到了关于异步处理消息的用法时,有没有想过可以在子线程中去new一个Handler?现在就开始着手,从一个子线程中去new一个Handler,看看会有什么发生。
1 | new Thread(new Runnable() { |
结果就出现了RuntimeException异常,仔细看它的信息说明。
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
那么可知,在每个线程new Handler()
时,都必须先调用Looper.prepare()
或者调用一个能够达到相同效果的函数。那么在主线程中可以new Handler()
的原因,想必就是已经调用过了。以下代码位于AcitivityThread.java中,是一段初始化主线程的内容。
1 | Looper.prepareMainLooper(); |
其它的都忽略,就看Looper相关的。Looper.prepareMainLooper()
想必是达到了相同的效果吧。那么,这个效果到底是什么呢?让我们慢慢拨开云雾。
于是,我们很自然地在子线程中加入了Looper.prepare()
,并随手按着Ctrl,左键点击鼠标,进入了prepare()
函数中。
1 | /* |
当初的那个异常不就在眼前?但是,这sThreadLocal
又是什么?它是什么暂时抛开,这时我们知道了我们的线程中已经有了一个Looper
,并且为这个Looper设置好了一个MessageQueue。因为一个线程只能有一个Looper
,所以一个Looper也就只能拥有一个MessageQueue。但是AcitivityThread中,经过Looper.loop()
后就再也没有下文了?所以,这个loop()
又是干啥的呢?
loop()
1 | /** Return the Looper object associated with the current thread. Returns null if the calling thread is not associated with a Looper.*/ |
因为其中一个大大的死循环,所以调用了loop()
之后,其后就没有实际代码了。这个死循环就是用来处理Message,不断地从队列中取,然后不断地进行分发到相应的Handler,进行处理。此时,这个for(;;)
所处的线程,就是你调用Looper.loop()时所在的线程。因此,它分发msg给了相应的Handler的handleMessage之后,还是在此线程中执行。然后,在想想,发送Message时所处在的线程,就焕然大悟这个异步操作了。
1 | /** |
handleMessage(msg)
不正是我们创建Handler时候,所覆盖的方法吗?
进一步思考,如果我只在主线程中new Handler,那么Looper就是主线程,所有的msg都会在主线程中被处理;那如果我想让msg在子线程中被处理呢?当然可以Looper.prepare()
巴拉巴拉,然后Looper.loop()
。但是Android还为我们提供了一个更为便捷的封装。那就是HandlerThread
。
1 |
|
源代码比较短。它继承自Thread,并在run方法中初始化好了Looper,可以通过其getThreadHandler()
方法,获取到与该Looper所绑定的Handler,然后sendMessage(),最后在该线程中处理msg。
因此,一个Thread可以有一个Looper和一个MessageQueue,一个Looper却可以与多个Handler绑定,但是一个Handler只能与一个Looper绑定。原因可以从Handler的构造方法中寻找的。