android-interview

  • 如何减小安装包的大小
    • 主要是减小资源的大小
      • 不常使用的资源,使用时再从网络下载。
      • 绘制代替图片资源
  • OOM (Out Of Memory)
  • https://www.zhihu.com/question/37483907 怎么准备Android面试?
  • ANR, Android各个版本特性,Dex2Oat
  • systrace l

你或许应该知道的LLVM, http://blog.csdn.net/khlljm/article/details/51822973

避免oom

https://www.zhihu.com/question/19772290/answer/13314769

在Android开发中,有哪些好的内存优化方式?如何避免 Out Of Memory(OOM) ?

  • 避免内存泄漏
    • 使用LinkedHashMap
  • ?

Android Release

Android 各版本历史主要变动(Version1.5–>4.0)全面整理

  • Android 2.2/2.2.1
    • 软件安装至扩展内存
    • Market中的批量和自动更新
  • Android 3.0.1
    • 支持平板电脑

Android Orea (Go editon)

https://developer.android.google.cn/about/versions/oreo/android-8.1.html

从Android 8.1 (API 27)开始,google 推出了go版本,作为entry phone的平台。

go版本的配置特性包括:

  • Memory optimization, 是应用可以在1GB 或更少RAM的设备上
  • Flexible targeting options, 新的hardware feature contstans使得你可以在Google Play发布normal版或low-Ram设备版本
  • Google Play, 当所有应用可以运行go版本上, Google play将给出若干优化guideline,

开发者可以优化现有的APK 或者是使用Google paly的 Multiple APK Feature,为go 版本指定特定的APK版本.

  • Autofill framework updates
  • Videl thumnail extrator
  • Notifications
  • EditText update

https://developer.android.google.cn/guide/topics/manifest/uses-sdk-element.html#ApiLevels

  • Android
  • Android 3.0.x (11)
    • Fragment
    • ActionBar
    • System clipboard
    • App widgets, 支持几种新的wiget类
    • Status bar notifacation, 可以支持更丰富内容的status bar
    • Content loader
  • Android 4.4 (19)
    • 只有用后READ_EXTERNAL_STORAGE权限, app才可以方位external storage的ahared files
    • WebView更新了,会有性能的提升,支持HTML5特喜感, 并且可以远程debug WebView的内容。
  • Android 5.0 (21) Lollipop
    • 在 Android 5.0 中,ART 运行时取代 Dalvik 成为平台默认设置。Android 4.4 中已引入处于实验阶段的 ART 运行时。
    • 低耗电模式,在屏幕不使用的一段时间内会进入该模式,定时顿时间恢复正常工作
    • 待机模式,一段时间未触摸屏幕,系统做出判处。
  • Android 6.0 (23) Marshmallow 棉花糖
    • 运行时权限,可以在运行时管理权限
    • Hotspot 2.0 Release 1 support
  • Android 7.0 (24) Nougat 牛轧糖
    • Multiple-window support , 可以一次pop open 两个一个用在屏幕上
      • 在android TV, 可以使用画中画模式
    • Notification enhancements,
    • Profile-guided JTI/AOT Compilation
  • Android 8.0 (26) Oreo
    • Picture in Picture mode
    • Autosiziting Textview, 支持根据TextView自动调整TextView的字体大小

26

Kotlin

https://developer.android.google.cn/kotlin/index.html

特点:expressive,concise简明, powerful,最重要的是interoperable with existing android languages and runtime.

  • 安全
1
2
3
4
5
6
7
var output: String
output = null
==================================
val name: String? = null // Nullable type
println(name.length())
  • Lambdas

    1
    2
    3
    4
    5
    6
    7
    8
    9
    Java
    button.setOnClickListener(new View.OnClickListener(){
    public void (View v){
    doSomething();
    }
    });
    Kotlin
    button.setOnClickListener { doSomething() }
  • default and amed arguments

    1
    2
    3
    4
    5
    6
    7
    fun format(str: String,
    normalizeCase: Boolean = true,
    upperCaseFirstLetter: Boolean = true,
    divideByCamelHumps: Boolean = false,
    wordSeparator: Char = ' ') {
    }

项目使用Apache 2.0 license 开源: https://github.com/JetBrains/kotlin

Android Studio3.0完全支持Kotlin

名字的来源

Android遇上Kotlin. http://www.jianshu.com/p/e04b252e71b8 2017

Kotlin语言的开发者是JetBrains,公司总部位于布拉格,在俄罗斯的圣彼得堡和美国的波士顿设有分公司。

Kotlin的主要开发者是圣彼得堡分公司团队完成,Java的名字来源于一个岛,所以Kotlin也选了一个岛作为名字。

Kotlin的历史:

Android Studio目前所用的JVM是JetBrains公司的。

Kotlin的特点

基于JVM的静态编程语言。在Kotlin之前,JetBrains团队一直用Java创建他们的IDE,出于对Java语言略有失望,不能满足需求,Kotlin应运而生,它从其他语言如Java, Scale, Groovy, C#, Gosu等获取灵感。能够快速开发,编译也快,实现相同功能的diamagnetic长度比Java少很多。

  • 多平台开发, 基于JVM。Native 开发就更牛了,目前 Kotlin 官方在 Github 开源了 Native 开发的源码 https://github.com/JetBrains/kotlin-native,基于 LLVM(Low Level Virtual Machine 的缩写,表示「底层虚拟机」。LLVM 是一种编译器基础设施,以 C++ 写成。它是为了任意一种编程语言而写成的程序,利用虚拟技术创造出编译时期、链接时期、运行时期以及闲置时期的最优化)的后端,方便为各个平台编写原生应用,比如为 Mac OS,iOS,Linux,嵌入式系统,等等。作者:程序员联盟链接:http://www.jianshu.com/p/e04b252e71b8來源:简书著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 开源
  • 和 Java 100% 兼容 :Kotlin 调用 Java 已有的代码或库没有问题。在一个项目中也可以同时用 Java 和 Kotlin
    来编写代码。Android Studio 和 IntelliJ IDEA 都可以实现一键转换 Java 代码到 Kotlin。
  • 安全,防止在 Java 中很常见的 NullPointerException(空指针异常)问题
  • 容易学些,语法简单
  • Lambda表达式
  • 变量类型推断
  • when语句块,避免繁琐的switch
  • 无需手动添加get set
  • Anko官方库使Andorid应用开发更快捷
  • val, var, fun
  • 类的方法扩展方便
  • 可以创建自定义的DSL(领域特定语言)
  • Coroutine:协程

Android Basic

- User Permisssion

1
<uses-permission android:name="android.permission.INTERNET"/>

Android Framework

- Platform Architecture

https://developer.android.google.cn/guide/platform/index.html

android-interview

- View的绘制

深入理解Android之View的绘制流程. http://www.jianshu.com/p/060b5f68da79 2016

DecorView (root view, 本质上是一个FrameLayout)

|——LinearLayout

? |—–TitleView (ActionBar的容器)

? |—-ContentView (FrameLayout, setContentView()就是设置它的子view)

Window

android.view.Window,这是一个抽象类,是窗口的抽象。Android中,窗口独占一个surface实例的显示区域。每个窗口的Surface由WindowManagerService分配,可以通过Canvas或OpenGl在上面绘画。画好之后,通过SurfaceFlinger将多块Surface按照z-order进行混合,然后输出到FrameBuffer中。

  • WindowManager.LayoutParams
  • Callback
  • ViewTree

PhoneWindow

Window的具体实现.

http://www.jianshu.com/p/5a71014e7b1b

ViewRoot

际上,View的绘制是由ViewRoot来负责的。每个应用程序窗口的decorView都有一个与之关联的ViewRoot对象,这种关联关系是由WindowManager来维护的。

View的整个绘制流程可以分为以下三个阶段:

  • measure: 判断是否需要重新计算View的大小,需要的话则计算;
  • layout: 判断是否需要重新计算View的位置,需要的话则计算;
  • draw: 判断是否需要重新绘制View,需要的话则重绘制。

- Activiy的启动过程

Activity extends ContextThemeWrapper implements …

ContextWrapper –> Context (public abstract class Context)

Context, 一个应用环境的全局接口。

private Window mWindow

private WindowManager mWindowManager;

View mDecor

https://*.com/questions/9238078/android-activitymanager-vs-windowmanager

  • WindowManager,组织Screen,分配surface,组织层
  • ActivityManager,系统使用ActiviyManager管理不同状态(started, paused, stopped destroyed)的activity 的stack,

http://www.cnblogs.com/kernel-style/p/4770071.html

android activity启动过程分析

桌面程序Launcher启动时,扫面各个app信息,activity可以在用户点击屏幕应用时由launcher启动

http://www.cnblogs.com/carlo/p/4947586.html

内部调用startActiviy和从桌面启动actiivy,都是通过ActivityManagerService服务进程,Service也由它启动.

在这个图中,ActivityManagerService和ActivityStack位于同一个进程中,而ApplicationThread和ActivityThread位于另一个进程中。其中,ActivityManagerService是负责管理Activity的生命周期的,ActivityManagerService还借助ActivityStack是来把所有的Activity按照后进先出的顺序放在一个堆栈中;

对于每一个应用程序来说,都有一个ActivityThread来表示应用程序的主进程,而每一个ActivityThread都包含有一个ApplicationThread实例,它是一个Binder对象,负责和其它进程进行通信。

Step 1. 无论是通过Launcher来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都通过Binder进程间通信进入到ActivityManagerService进程中,并且调用ActivityManagerService.startActivity接口;

? Step 2. ActivityManagerService调用ActivityStack.startActivityMayWait来做准备要启动的Activity的相关信息;

? Step 3. ActivityStack通知ApplicationThread要进行Activity启动调度了,这里的ApplicationThread代表的是调用ActivityManagerService.startActivity接口的进程,对于通过点击应用程序图标的情景来说,这个进程就是Launcher了,而对于通过在Activity内部调用startActivity的情景来说,这个进程就是这个Activity所在的进程了;

? Step 4. ApplicationThread不执行真正的启动操作,它通过调用ActivityManagerService.activityPaused接口进入到ActivityManagerService进程中,看看是否需要创建新的进程来启动Activity;

? Step 5. 对于通过点击应用程序图标来启动Activity的情景来说,ActivityManagerService在这一步中,会调用startProcessLocked来创建一个新的进程,而对于通过在Activity内部调用startActivity来启动新的Activity来说,这一步是不需要执行的,因为新的Activity就在原来的Activity所在的进程中进行启动;

? Step 6. ActivityManagerServic调用ApplicationThread.scheduleLaunchActivity接口,通知相应的进程执行启动Activity的操作;

? Step 7. ApplicationThread把这个启动Activity的操作转发给ActivityThread,ActivityThread通过ClassLoader导入相应的Activity类,然后把它启动起来。

http://www.jianshu.com/p/d4cc363813a7

系统会为每个App创建一个进程,系统进程和App进程之间通过Binder通信

AMS通知上一个activity(即想要打开新activity的activity)的ApplicationThread

- Android启动过程

Android启动过程深入分析. http://blog.jobbole.com/67931/ 2014

  1. Boot Room,-当电源按下,引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序到RAM,然后执行。

    ?

  2. Boot Loader 引导程序是在Android操作系统开始运行前的一个小程序。分两个阶段

    1. 设置内核运行必要的环境,内存、网络,设置内核
  3. Kernel,设置缓存、被保护存储器,完成系统设置后,首先在系统文件中寻找init文件,然后启动root进程或者系统的第一个进程

  4. Init 进程,root进程,是所有进程的父进程,

    1. 挂载目录如/sys,/dev,/proc
    2. 运行init.rc脚本
  5. Android为每个应用启动一个Dalvik虚拟机实例,但这样会太慢,所以Android做了改进,使用Zygote, 让虚拟机共享代码,Zygote是一个虚拟机进程。在这个工程可以看到启动画面

  6. 系统服务或服务,如电源管理器,ActivityManager,电话组词,定时服务,窗口管理器,启动电池、定时、传感、蓝牙,启动挂载服务… 转太烂 网络连接 硬件 音频 剪贴板 耳机…

  7. 引导完成,ACTION_BOOT_COMPLETED开发广播会发出去。

- Binder

锁屏

http://www.cnblogs.com/u3shadow/p/4639678.html

http://www.cnblogs.com/u3shadow/p/4639648.html

开发锁屏程序的时候我们要面临的重要问题无疑是如何屏蔽三个按键,Back,Home,Menu

  • 屏蔽back, 重置onKeyDown 拦截

  • 屏蔽Menu按键, 在4.0以上的系统中,大多数情况下点击Menu按键会出现Recent app页面。

  • 屏蔽home键,屏蔽Home按键,Home按键由于其特殊性,无法被拦截。

    但是我们可以参考其他锁屏应用,设置一个自己的主屏幕应用,让每次点击Home按键的时候启动我们自己的主屏幕,再进行判断,是继续停留锁屏界面还是启动系统 的主屏幕页面。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <activity
    android:name=".Home"
    android:theme="@android:style/Theme.NoDisplay"//设置主题为不可见
    >
    <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.HOME" />//可以作为桌面被识别
    <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    </activity>

首先,点亮屏幕的时候,系统会发出一个广播,ACTION_SCREEN_ON,我们可以通过一个BroadcastReceiver来监听这个广播,并启动我们自己的Activity

在onCreate中关闭系统的锁屏

1
2
3
4
5
final Window win = getWindow();
win.addFlags(
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//解除系统锁屏
setContentView(R.layout.main_layout);

http://www.jb51.net/article/65537.htm

解锁、唤醒屏幕用到KeyguardManager,KeyguardLock,PowerManager,PowerManager.WakeLock

所需权限:
复制代码
代码如下:

- 事件分发机制,事件冲突处理

Input Events. https://developer.android.google.cn/guide/topics/ui/ui-events.html

在Android中有几种方法可以截获用户与应用之间的事件。

比起继承view重置view的事件处理方法,view提供了各种event listeners来实现事件处理。

view的event listener中的各种方法:

  • onClick()
  • onLongClick()
  • onFoucusChange()
  • onKey()
  • onTouch(), a touch event,包括press, release , or any movement getsture
  • onCreateContextMenu()

处理Focus

focus的移动按照基于算法进行,算法在给定方向上查找最近的邻居。如果默认的算法无法满足需求,可以在layout的xml文件中指定nextFocusDown, nextFocusLeft, nextFocusRight, nextFocusRight这些属性。

Managing Touch Events in a ViewGroup.

https://developer.android.google.cn/training/gestures/viewgroup.html

在ViewGroup中处理touch事件需要特别小心,因为通常子view是不同touch事件的target而不是view group本身。为了保证每个view正确接收到本应给它的touch事件,重置onInterceptTouchEvent()方法。

在ViewGroup中拦截Touch 事件

当在ViewGoup的surface上检测到了touch事件,则onInterceptTouchEvent方法会被调用,如果该方法返回true,则事件不会继续传递给child,而是传递给parent的onTouchEvent()方法。

onInterceptTouchEvent()方法给了parent一个在传递给child前处理event的机会。

  • 返回true,事件交给onTouchEvent方法,之前处理touch event的child view会收到ACTION_CANCEL,该事件中之后的动作会传给parent 的onTouchEvent
  • 返回false,则事件仍按照正常的传递流程到target。

处理ACTION_OUTSIDE 事件

如果ViewGroup收到了带有ACTION_OUTSIDE的MotionEvent,那么这个事件默认不会分发给child,可以在相应的Window.Callback中处理该事件,也可以通过重置dispatchTouchEvent(MotionEvent)分发给合适的view。

Understanding Android Input Touch Events

System Framework (dispatchTouchEvent, onInterceptTouchEvent,
onTouchEvent, OnTouchListener.onTouch)

http://codetheory.in/understanding-android-input-touch-events/ 有些地方说得不是很确切

理解事件分发机制是很重要的。

如果在ViewGroup如ScrollView中使用了ViewPager或者ListView(都可以scrollable) ,事件会像变戏法一样。

Touch事件的传播

按下屏幕(ACTION_DOWN)触发一个touch事件后,它会到达Activity.dispatchTouchEvent()方法,该方法将MotionEvent发送给root view(这里我认为是DecorView).

  • Activity.dispatchTouchEvent(MotionEvent ev)

    • 发送事件给window的root view
    • 该方法如果返回true,那么ACTION_DOWN之后的事件( MOVE, UP) 它也会消耗掉。如果返回false,那么这些事件就不再到达这个方法。
  • ViewGroup.diaptachTouchEvent,

    • root view的dispatchTouchEvent()方法首先会调用onInterceptTouchEvent()方法,查看是否该方法会拦截事件.
    • 如果拦截方法返回false,查找区域包含事件坐标的child, 然后调用child的dispatchTouchEvent,如果返回false则继续找下一个区域包含事件坐标的child。返回true则事件被处理。
      • 如果children都没有处理该事件,则交给ViewGroup的onTouchEvent()方法
    1
    2
    3
    4
    5
    6
    public boolean dispatchTouchEvent(MotionEvent ev) {
    是否因为安全问题过滤掉该事件
    ->no: flags定义中是否允许拦截 //requestDisallowInterceptTouchEvent() 方法设置是否允许拦截
    ->yes: onInterceptTouchEvent
    ->no: ...
    }
    • 如果拦截了,之前处理事件的child会收到ACTION_CANCEL
  • View.dispatchTouchEvent()

    • 如果存在listener, 发送事件给View.onTouchListener.onTouch(), 如果消息还没有被消耗,则交给View.onTouchEvent()

dispatchTouchEvent的返回值如何影响分发流程

- Android多线程

AsyncTask

使用FutureTask封装任务,重置了FutureTask的done方法(done方法在FutureTask的run方法中被间接调用),获取结果并发送消息到定义AsyncTask的线程中 :

1
2
3
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();

处理消息时会调用消息的handler,因此onPostExecute() 在这个线程中被执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class InternalHandler extends Handler {
...
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]); // onPostExecute在该方法中被调用
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
}

AsyncTask默认使用SerialExecutor串行执行任务,可以调用executorOnexecuteOnExecutor(Executor, …)并行运行任务.

Message

使用了消息池,避免重复创建消息。每个消息有一个next域指向下一个消息,从而组成一个单链表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
大专栏  android-interviewline">46
// android 5.1.1
public final class [More ...] Message implements Parcelable {
public int what;
static final int FLAG_IN_USE = 1 << 0;
private static final int MAX_POOL_SIZE = 50;
int flagsl;
Handler target;
Runnable callback;
...
public static Message [More ...] obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
public void recycle() {
if(isInUse()) {
if(gCheckRecycle) {
throw new IllegalStateExectution("This message cannot be recycled because it"
+ "is still in use.");
}
return;
}
recycleUnchecked();
}
void recycleUnchecked() {
flags = FLAG_IN_USE;
...
synchronized(sPoolSync) {
if(sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
}

- Parcel

Android中新增的几个主要特性

- Loader

https://developer.android.google.cn/guide/components/loaders.html

Android 3.0 中引入了加载器,支持轻松在 Activity 或片段中异步加载数据。 加载器具有以下特征:

  • 可用于每个 ActivityFragment
  • 支持异步加载数据。
  • 监控其数据源并在内容变化时传递新结果。
  • 在某一配置更改后重建加载器时,会自动重新连接上一个加载器的游标。 因此,它们无需重新查询其数据。

相比AsyncTask, Loader使用LoaderManager来管理Loader实例,数据的加载和更新分开实现:

  • doInbackground(…),加载放在Loader中;
  • onPostExecute(…),更新放在LoaderManager.LoaderCallback中

Loader机制

  • LoderManager

    • 一种与 Activity 或 Fragment 相关联的的抽象类,用于管理一个或多个 Loader 实例。 这有助于应用管理与 Activity 或 Fragment 生命周期相关联的、运行时间较长的操作。它最常见的用法是与 CursorLoader 一起使用,但应用可*写入其自己的加载器,用于加载其他类型的数据。

      每个 Activity 或片段中只有一个 LoaderManager。但一个 LoaderManager 可以有多个加载器。

  • Loader, 负责加载数据。一种执行异步数据加载的抽象类。这是加载器的基类。 通常会使用 CursorLoader,但也可以实现自己的子类。加载器处于活动状态时,应监控其数据源并在内容变化时传递新结果。

    • AsyncTaskLoader,Loader的子类,提供AsyncTask执行任务,必须要重置的方法是loadInBackground()。
      • mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
    • CursorLoader, AsyncTaskLoader 的子类,它将查询 ContentResolver 并返回一个 Cursor。此类采用标准方式为查询游标实现 Loader 协议。它是以 AsyncTaskLoader 为基础而构建,在后台线程中执行游标查询,以免阻塞应用的 UI。使用此加载器是从 ContentProvider 异步加载数据的最佳方式,而不用通过片段或 Activity 的 API 来执行托管查询。
  • LoaderManager.LoaderCallback, 一种回调接口,用于客户端与 LoaderManager 进行交互。例如,您可使用 onCreateLoader() 回调方法创建新的加载器。

    • onCreateLoader(), 针对指定的 ID 进行实例化并返回新的 Loader
    • onLoadFinished():将在先前创建的加载器完成加载时调用
    • onLoaderReset():将在先前创建的加载器重置且其数据因此不可用时调用

加载器(特别是 CursorLoader)在停止运行后,仍需保留其数据。这样,应用即可保留 Activity 或片段的 onStop() 和 onStart() 方法中的数据。当用户返回应用时,无需等待它重新加载这些数据。您可使用 LoaderManager.LoaderCallbacks 方法了解何时创建新加载器,并告知应用何时停止使用加载器的数据。

Loader 与 AsyncTask

Loader提供了LoaderManager与Activity或Fragment关联,Activity/Fragment的生命周期中管理了LoaderManager.当配置发生变化时,Activity会在销毁前保存LoaderManager,并在重建后恢复LoaderManager。

1
2
3
4
5
LoaderManager给Activity提供了管理自己的一些方法;同时主动管理了对应的Loader,它把每一个Loader封装为LoadInfo对象,同时它负责主动调运管理Loader的startLoading()、stopLoading()、,forceLoad()等方法。
由于整个Activity和Fragment主动管理了Loader,所以关于Loader的释放(譬如Cursor要要主动关闭游标的等,文件流要置空等)不需要我们人为处理,Loader会帮我们很好的处理的;同时特别注意,对于CursorLoader,当我们数据源发生变化时Loader框架会通过ContentObserver调用onContentChanged的forceLoad方法重新请求数据进行回调刷新。
作者:Tamic
链接:http://www.jianshu.com/p/385327e35711

而AsyncTask则没有绑定到所在的Activity的生命管理周期中,当配置发生改变时Activity会被销毁,AsyncTask仍然存活,它就可能会对旧的被销毁的Activity执行UI更新,从而引发异常。此外,这也阻止了对旧的Activity进行垃圾回收。

An Loader Example

https://github.com/android-samples/android-loader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// Loader负责加载数据
class BigDataLoader extends AsyncTaskLoader<BigData>{
public BigDataLoader(Context context) {
super(context);
Log.d("test", "...BigDataLoader.");
}
public BigData loadInBackground() {
// BigData構築
Log.d("test", "...loadInBackground.");
BigData data = new BigData();
data.load();
return data;
}
}
// 实现了LoaderCallbacks<>接口,负责创建Loader, loader加载完成后的更新操作
public class MainActivity extends Activity implements LoaderCallbacks<BigData> {
public Loader<BigData> onCreateLoader(int id, Bundle args) {
Log.d("test", "------------onCreateLoader");
BigDataLoader loader = new BigDataLoader(this.getApplication());
loader.forceLoad();
return loader;
}
public void onLoadFinished(Loader<BigData> loader, BigData data) {
Log.d("test", "------------onLoadFinished");
TextView textView = (TextView)findViewById(R.id.textView1);
textView.setText(data.at(0));
ProgressBar progress = (ProgressBar)findViewById(R.id.progressBar1);
progress.setVisibility(View.GONE);
}
public void onLoaderReset(Loader<BigData> loader) {
Log.d("test", "------------onLoaderReset");
}
//---------MainActivity Methods
public void buttonMethodRestart(View button){
ProgressBar progress = (ProgressBar)findViewById(R.id.progressBar1);
progress.setVisibility(View.VISIBLE);
getLoaderManager().restartLoader(0, null, this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getLoaderManager().initLoader(0, null, this);
}

Loader 的实现

Loader

使用了观察者模式,提供registerListener方法

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Loader<D> {
...
public interface OnLoadCompleteListener<D> {
public void onLoadComplete(Loader<D> loader, D data);
}
public void registerListener(int id, OnLoadCompleteListener<D> listener){...}4
public boolean onStared();
public boolean onReset();
public void onStartLoading();
public void onStopLoading();
public void onAbandon();
...
}

AsyncTaskLoader

使用AsyncTask完成load任务,AsyncTask中的Executor默认是ThreadPoolExecutor。

数据加载完成会调用OnLoadCompleteListener对象的onLoadComplete()方法, 在LoaderManager中,该listener使用了LoaderManager.LoaderCallbacks类型对象。

LoaderManager

管理Loader,提供了一些Activity管理自己的方法。

- Fragment

图片加载框架

http://www.jianshu.com/p/3ac30878c72c

UniversalImageLoader

https://github.com/nostra13/Android-Universal-Image-Loader

  • ImageLoader图片加载器,对外的主要 API,采取了单例模式,用于图片的加载和显示。
  • Memory Cache, 使用LRU算法,即最近最少使用算法, 使用LinkedHashMap作为存储结构

  • DiskCache, 默认使用LruDiskCache算法

  • 图片加载过程

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      1.判断图片的内存缓存是否存在,若存在直接执行步骤 8;
      2.判断图片的磁盘缓存是否存在,若存在直接执行步骤 5;
      3.ImageDownloader从网络上下载图片;
      4.将图片缓存在磁盘上;
      5.ImageDecoder将图片 decode 成 bitmap 对象;
      6.BitmapProcessor根据DisplayImageOptions配置对图片进行预处理(Pre-process Bitmap);
      7.将 bitmap 对象缓存到内存中;
      8.根据DisplayImageOptions配置对图片进行后处理(Post-process Bitmap);
      9.执行DisplayBitmapTask将图片显示在相应的控件上。

Picasso

https://github.com/square/picasso

Square公司开源的一个Android图片加载框架

使用:

1
2
3
4
Picasso.with(this).load("url").placeholder(R.mipmap.ic_default).into(imageView);
/*
Picasso.with(Context),单例模式,返回单个Picasso对象,
Picasso对象的创建 : newBuilder(context).build();

原理

  • Downloader
    • DownLoader就是下载用的工具类,在Picasso当中,如果OKHttp可以使用的话,就会默认使用OKHttp,如果无法使用的话,就会使用UrlConnectionDownloader(默认使用HttpURLConnection实现)。
  • Cache

    • 默认实现为LruCache,就是使用LinkedHashMap实现的一个Cache类,注意的一个地方就是,在其他的地方,我们一般默认的是限制的capacity,但是这个地方我们是限制的总共使用的内存空间。
  • ExecutorService

    默认的实现为PicassoExecutorService,该类也比较简单,其实就是ThreadPoolExecutor,在其功能的基础上继续封装,在其中有一个比较细心的功能就是,Picasso通过PicassoExecutorService设置线程数量,来调整在2G/3G/4G/WiFi不同网络情况下的不同表现。

Glide

https://github.com/facebook/fresco

Google的一位员工基于Picasso实现。

Fresco 是 Facebook 出品。Fresco 将图片放到一个特别的内存区域叫 Ashmem 区,就是属于 Native 堆,图片将不再占用 App 的内存,Java 层对此无能为力,这里是属于 C++ 的地盘,所以能大大的减少 OOM。

推荐在主要都是图片的app中使用,一般的app使用Glide和Picasso就够了

  • Fresco在磁盘缓存方面,Picasso 只会缓存原始尺寸的图片,而 Glide 缓存的是多种规格,也就意味着 Glide 会根据你 ImageView 的大小来缓存相应大小的图片尺寸,比如你 ImageView 大小是200200,原图是 400400 ,而使用 Glide 就会缓存 200*200 规格的图
  • 最重要的一个特性是 Glide 支持加载 Gif 动态图,而 Picasso 不支持该特性。
  • 除此之外,还有很多其他配置选项的增加。

图片缓存

- LruCache

https://developer.android.google.cn/reference/android/util/LruCache.html

Android3.0引入LruCache(Least Recent Used)进行图片缓存。LruCache内部使用LinkedHashMap,持有缓存对象的强引用,没当对象被访问时,便会移到队列的头部,添加对象时如果队列满了,则移除队列尾部的对象从而可以被GC回收。

LruCache的使用,需要重置sizeOf(K, V)方法:

1
2
3
4
5
6
int cacheSize = 4 * 1024 * 1024; // 4MiB
LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
}

如果缓存的对象还持有其他需要显式释放的资源,重置enteryRemoved(boolean, K, V, V)方法。

LruCache是线程安全的 ,对操使用了同步。

1
2
3
4
5
synchronized (cache) {
if (cache.get(key) == null) {
cache.put(key, value);
}
}

不允许使用Null作为key或者value,从而get,put的返回值没有歧义,null值代表不存在。

- DiskLruCache

LruCache之LruCache分析. http://www.jianshu.com/p/4aaf93a67fc3 .2016

DiskLruCache并不是Android SDK中的类。不明白为啥,官方只进行推荐,为何不加入SDK中.

https://*.com/questions/28435860/what-does-oat-mean

We know that Dalvik uses APK, DEX, and ODEX files.And we know this abbreviation means via AOSP source or Developers site.

(like this - https://source.android.com/devices/tech/dalvik/dex-format.html)

  • DEX means Dalvik EXcutable file.
  • ODEX means Optimized Dalvik EXcutable file.
  • APK means Android PacKage.

ART (Android RunTime) uses OAT and ART,

Before AOT came to Android, dexopt was used to optimize DEX to ODEX (optimized DEX) which contains the optimized bytecode.

With AOT, dex2oat is used to optimize and compile DEX into an OAT file which may contain machine code in the ELF format.

oat- It’s Of Ahead Time, a silly reordering of Ahead Of Time.

Android开发——JVM、Dalvik以及ART的区别. http://blog.csdn.net/seu_calvin/article/details/52354964

Dalvik是Google公司自己设计用于Android平台的Java虚拟机。它可以支持已转换为.dex(即Dalvik Executable)格式的Java应用程序的运行,.dex格式是专为Dalvik应用设计的一种压缩格式,适合内存和处理器速度有限的系统。

1. Dalvik与JVM的区别

(1)Dalvik指令集是基于寄存器的架构,执行特有的文件格式——dex字节码(适合内存和处理器速度有限的系统)。而JVM是基于栈的。相对于基于栈的JVM而言,基于寄存器的Dalvik VM实现虽然牺牲了一些平台无关性,但是它在代码的执行效率上要更胜一筹。

(2)每一个Android 的App是独立跑在一个VM中的。因此一个App crash只会影响到自身的VM,不会影响到其他。Dalvik经过优化,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个 Dalvik应用作为一个独立的Linux进程执行。

2. Dalvik与ART的区别

(1)在Dalvik下,应用每次运行都需要通过即时编译器(JIT)将字节码转换为机器码,即每次都要编译加运行,这虽然会使安装过程比较快,但是会拖慢应用的运行效率。而在ART 环境中,应用在第一次安装的时候,字节码就会预编译(AOT)成机器码,这样的话,虽然设备和应用的首次启动(安装慢了)会变慢,但是以后每次启动执行的时候,都可以直接运行,因此运行效率会提高。

(2)ART占用空间比Dalvik大(原生代码占用的存储空间更大,字节码变为机器码之后,可能会增加10%-20%),这也是著名的“空间换时间大法”。

(4)预编译也可以明显改善电池续航,因为应用程序每次运行时不用重复编译了,从而减少了 CPU 的使用频率,降低了能耗。

dex2oat对应用启动性能的影响

http://blog.csdn.net/azhengye/article/details/73000419

chrome启动慢,没有生成odex文件

原来之前的同事在做开机优化时做了一个功能,将非重要应用的dex2oat操作放在了开机之后。可是没有考虑好更新应用时的逻辑处理,导致了问题的发生

Android 平台侧性能优化之应用启动[问题已解决]

http://blog.csdn.net/azhengye/article/details/67054941

systrace位于/platform-tools/systrace目录下

Email启动比参考机慢,参考机采用了后台一直运行的方式,相当于拿app的冷启动比参考机的热启动

为什么安卓手机升级系统后,首次启动会比较慢?

https://zhuanlan.zhihu.com/p/28951050

Android中的设计模式

  • Singleton, InputMethodManager
  • Adapter, 各种view的adapter, 随处可见,尤其是涉及到数据状态发生变化需要通知的情况下
  • 观察者模式,各种listenre
  • 责任链模式, 事件处理
  • 工厂模式
  • 组合模式, View ViewGroup
  • 命令模式,把请求封装成对象
  • Builder, Dialog

其他

  1. 60+ Android Secret Codes 2017 (Hidden Codes …*

    how to use top best **android secret codes 2017 motorola samsung vivo sony mi htc lg zte secret codes for android phone # codes and hacks working all mobile *code** pdf …

    https://safetricks.org/**android**-secret-**codes***2017-10-27*

  2. ?

android-interview

上一篇:Android TabLayout 平板下不能铺满全屏的问题


下一篇:详解js的bind、call、apply