2017年4月21日,周结(九),android进阶学习之路

来源:互联网 发布:好记的淘宝店铺的店名 编辑:程序博客网 时间:2024/06/05 21:55

这周忽然意识到自己的英语已经放下有一段时间了,仔细想了想,觉得想好英语确实挺重要的,不过光把自己的英语水平停留在四级,应该把眼光放长远一点,以后会用得着的,所以这周开始我又重拾了英语,从单词开始积累,平时阅读一些官方文档时,把不会的单词查一下,顺便保存到有道云笔记中,每天早上起来之后打开笔记看一下.

学习安卓大概有两个月的时间了,现在的自己,基础还不算扎实,想从初级到中级进阶的话,还需要走很长的路.一些比较重要的但是不容易碰到的知识点,自己还是需要多去利用搜索引擎去查,去了解,去学习.

最近自己在看两本关于进阶的书,一本是android开发艺术探索,另一本是android群英传,这两本书中讲到的知识点很多都是进阶必须掌握的,自己平时还是要多看书,多练手敲代码.

为了以后走的更远,学习设计模式和数据结构也是很重要的,数据结构虽然大二的时候学过,但是现在也是忘的差不多了,不过自己重新拾起来,学一些基本的知识,应该不难.设计模式的话,就不是那么容易理解了,设计模式讲的更多的还是一种思想,想要使用某种设计模式,更重要的是去理解,这样使用起来这种模式才会轻松点.

借用一段昨天在一篇博客中看到的话,用来说明数据结构的重要性:

如果说 Java 是自动档轿车,C 就是手动档吉普。数据结构呢?是变速箱的工作原理。你完全可以不知道变速箱怎样工作,就把自动档的车子从 A 开到 B,而且未必就比懂得的人慢。写程序这件事,和开车一样,经验可以起到很大作用,但如果你不知道底层是怎么工作的,就永远只能开车,既不会修车,也不能造车。如果你对这两件事都不感兴趣也就罢了,数据结构懂得用就好。但若你此生在编程领域还有点更高的追求,数据结构是绕不开的课题。

Java 替你做了太多事情,那么多动不动还支持范型的容器类,加上垃圾收集,会让你觉得编程很容易。但你有没有想过,那些容器类是怎么来的,以及它存在的意义是什么?最粗浅的,比如 ArrayList 这个类,你想过它的存在是多么大的福利吗——一个可以随机访问、自动增加容量的数组,这种东西 C 是没有的,要自己实现。但是,具体怎么实现呢?如果你对这种问题感兴趣,那数据结构是一定要看的。甚至,面向对象编程范式本身,就是个数据结构问题:怎么才能把数据和操作数据的方法封装到一起,来造出 class / prototype 这种东西?

此外,很重要的一点是,数据结构也是通向各种实用算法的基石,所以学习数据结构都是提升内力的事情。

对自己的建议:不要操之过急,也不要心烦意乱,更不要眼高手低,要踏踏实实的一步一步的慢慢来.
接下来说一下这周学到的一些知识点:

LayoutInflater 的基本用法
首先需要获取到 LayoutInflater 的实例

第一种写法:LayoutInflater layoutInflater = LayoutInflater.from(context);  

第二种写法:
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  

第一种就是第二种的简单写法,只是 Android 给我们做了一下封装而已


得到了 LayoutInflater 的实例之后就可以调用它的 inflate() 方法来加载布局了
layoutInflater.inflate(resourceId, root);  
inflate() 方法一般接收两个参数,第一个参数就是要加载的布局 id,第二个参数是指给该布局的外部再嵌套一层父布局,如果不需要就直接传 null。

LayoutInflater 技术广泛应用于需要动态添加View的时候

layoutInflater= LayoutInflater.from(getApplicationContext());
linearLayout.addView(layoutInflater.inflate(R.layout.activity_button,null));

仅用两行代码即可实现添加 view


郭神LitePal的进阶使用:
一对一关联的实现方式是用外键,多对一关联的实现方式也是用外键,多对多关联的实现方式是用中间表
save() 方法返回的是一个布尔值,用于表示存储成功还是失败,但同时也说明这个方法是不会抛出异常的。有些朋友希望如果存储失败的话就抛出异常,而不是返回一个 false,那就可以使用 saveThrows() 方法来代替.使用 saveThrows() 方法来存储数据,一旦存储失败就会抛出一个 DataSupportException 异常,我们可以通过对这个异常进行捕获来处理存储失败的情况。
刚才我们查询到的是所有匹配条件的前10条新闻,那么现在我想对新闻进行分页展示,翻到第二页时,展示第11到第20条新闻,这又该怎么实现呢?没关系,在LitePal的帮助下,这些功能都是十分简单的,只需要再连缀一个偏移量就可以了(offset),都对应了一个带有isEager参数的方法重载,这个参数相信大家一看就明白是什么意思了,设置成true就表示激进查询,这样就会把关联表中的数据一起查询出来了。激进查询的用法非常简单,就只有这么多,其它find()方法也都是同样的用法,就不再重复介绍了。但是这种查询方式LitePal并不推荐,因为如果一旦关联表中的数据很多,查询速度可能就会非常慢。而且激进查询只能查询出指定表的关联表数据,但是没法继续迭代查询关联表的关联表数据。因此,这里我建议大家还是使用默认的懒加载更加合适,至于如何查询出关联表中的数据,其实只需要在模型类中做一点小修改就可以了。

郭神博客中复制的:
我们知道,Android应用都是使用Java语言来编写的,那么大家可以思考一下,一个Android程序和一个Java程序,他们最大的区别在哪里?划分界限又是什么呢?其实简单点分析,Android程序不像Java程序一样,随便创建一个类,写个main()方法就能跑了,而是要有一个完整的Android工程环境,在这个环境下,我们有像Activity、Service、BroadcastReceiver等系统组件,而这些组件并不是像一个普通的Java对象new一下就能创建实例的了,而是要有它们各自的上下文环境,也就是我们这里讨论的Context。可以这样讲,Context是维持Android程序中各组件能够正常工作的一个核心功能类。




安卓大致分为四层:Linux内核层,库,Framework层,应用层.




Activity回顾:






Activity 的 onSaveInstanceState() 和 onRestoreInstanceState() 并不是生命周期方法,它们不同于 onCreate()、onPause() 等生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按 Home 键)由系统销毁一个 Activity 时,onSaveInstanceState() 会被调用。但是当用户主动去销毁一个 Activity 时,例如在应用中按返回键,onSaveInstanceState() 就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity 的状态。通常 onSaveInstanceState() 只适合用于保存一些临时性的状态,而 onPause() 适合用于数据的持久化保存。






关于 onSaveInstanceState (),是在函数里面保存一些 View 有用的数据到一个 Parcelable 对象并返回。在 Activity 的 onSaveInstanceState(Bundle outState) 中调用 View 的onSaveInstanceState (),返回 Parcelable 对象,接着用 Bundle 的 putParcelable 方法保存在Bundle  savedInstanceState中。
  当系统调用 Activity 的的 onRestoreInstanceState(Bundle savedInstanceState)时, 通过 Bundle 的 getParcelable 方法得到 Parcelable 对象,然后把该 Parcelable 对象传给 View 的 onRestoreInstanceState (Parcelable state)在的 View 的 onRestoreInstanceState中从 Parcelable 读取保存的数据以便 View 使用。

onSaveInstanceState方法会在什么时候被执行,有这么几种情况:

1、当用户按下HOME键时。
这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,故系统会调用onSaveInstanceState,让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则

2、长按HOME键,选择运行其他的程序时。

3、按下电源按键(关闭屏幕显示)时。

4、从activity A中启动一个新的activity时。

5、屏幕方向切换时,例如从竖屏切换到横屏时。
在屏幕切换之前,系统会销毁activity A,在屏幕切换之后系统又会自动地创建activity A,所以onSaveInstanceState一定会被执行
 
总而言之,onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。

 如果我们没有覆写 onSaveInstanceState() 方法, 此方法的默认实现会自动保存 activity 中的某些状态数据, 比如 activity 中各种 UI 控件的状态.。android 应用框架中定义的几乎所有 UI 控件都恰当的实现了 onSaveInstanceState() 方法,因此当 activity 被摧毁和重建时, 这些 UI 控件会自动保存和恢复状态数据. 比如 EditText 控件会自动保存和恢复输入的数据,而 CheckBox 控件会自动保存和恢复选中状态.开发者只需要为这些控件指定一个唯一的 ID (通过设置android:id属性即可), 剩余的事情就可以自动完成了.如果没有为控件指定 ID, 则这个控件就不会进行自动的数据保存和恢复操作。
这也就说明了,想保存一些特殊的界面数据时,需要在调用super方法之前添加代码


如果需要保存额外的数据时, 就需要覆写 onSaveInstanceState()方法。需要注意的是: onSaveInstanceState() 方法只适合保存瞬态数据, 比如 UI 控件的状态, 成员变量的值等,而不应该用来保存持久化数据,持久化数据应该当用户离开当前的 activity 时,在 onPause() 中保存(比如将数据保存到数据库或文件中)。说到这里,还要说一点的就是在 onPause() 中不适合用来保存比较费时的数据,所以这点要理解。由于 onSaveInstanceState() 方法方法不一定会被调用, 因此不适合在该方法中保存持久化数据, 例如向数据库中插入记录等. 保存持久化数据的操作应该放在 onPause() 中。若是永久性值,则在 onPause() 中保存;若大量,则另开线程吧,别阻塞UI线程。 

onSaveInstanceState() 和 onRetainNonConfigurationInstance() 都可以实现保存数据的功能,如果是两个同时使用时,执行顺序是哪个在先,哪个在后呢?根据 Android 官方网站上介绍,如果两个方法同时出现时,onSaveInstanceState() 方法执行在先,而onRetainNonConfigurationInstance() 方法执行在后。它们的执行顺序都在 onStop() 和 onDestroy() 之间,关于这点需要我们大家注意。之前在其它网站上看到有的朋友说:" onSaveInstanceState()和onRetainNonConfigurationInstance() 既然都可以实现保存数据的功能,而且 onSaveInstanceState() 相比 onRetainNonConfigurationInstance() 方法可以实现更多情况下的数据保存功能,那么 onRetainNonConfigurationInstance() 岂不是多余的吗?"。关于这点,从设计的角度看,onRetainNonConfigurationInstance() 并不是多余的函数。一般情况下,如果我们要保存的数据不太大,而且适合放在 Bundle 中,那么使用onSaveInstanceState() 是比较合适的;如果要保存的数据不适合放在 Bundle 中(比如: 一个 socket )或是数据比较大(比如:一个 Bitmap ),那么这个时间我们就应该使用 onRetainNonConfigurationInstance(),而且我们使用 onRetainNonConfigurationInstance() 可以保存任何类型的对象,像 AsyncTask 和 SQLiteDatabse,我们都可以进行保存。这些类型的数据可能会被一个新的 Activity 实例所重新使用。所以 onSaveInstanceState() 和 onRetainNonConfigurationInstance() 在我们的程序中扮演的是不同的角色,需要在不同的时机下调用,用来处理不同类型的数据。


启动模式:




如果我们的程序是在单线程下运行,或者是不必考虑到线程同步问题,我们应该优先使用 StringBuilder 类;如果要保证线程安全,自然是 StringBuffer。

IO 流,读进来,写出去

IPC:Inter-process Communication 进程间通信
使用多进程的方法:四大组件中指定 android:process 属性
进程名以":"开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中
而进程名不以":"开头的进程属于全局进程,其它应用通过 ShareUID 方式可以和它跑在一个进程中

Android 为每个应用分配了一个独立的虚拟机,或者说为每个进程分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这就导致在不同的虚拟机中访问用一个类的对象会产生多个副本.
一般来说,使用多进程会造成如下几个方面的问题:
(1)静态成员和单例模式完全失效.
(2)线程同步机制完全失效.
(3) SharePreferences 的可靠性下降.
(4) Application 会多次创建.

进程间通信的几种方式:
1.使用 Bundle
2.使用文件共享
3.使用 Messenger
4.使用 AIDL
5.使用 ContentProvider
6.使用 Socket

遇到的bug: Unsupported method: AndroidProject.getPluginGeneration().


解决办法:关闭 Instant Run



希望以后的自己能不迷茫,能有方向.加油~~@

0 0