您的位置:首页 > 职场人生

Android 面试之 Android 篇 发表于 2016-10-27 | 分类于 Android 面试 | | 阅读次数 2249 本文出自 Eddy Wiki ,转载请注

2017-06-24 16:13 375 查看


Android 面试之 Android 篇

本文出自 Eddy
Wiki ,转载请注明出处:http://eddy.wiki/interview-android.html

本文收集整理了 Android 面试中会遇到与 Android 知识相关的简述题。

基本概念


Android
的四大组件

Acitivity、Service、BroadcastReceiver、ContentProvider
Activity :
应用程序中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应。
BroadcastReceiver广播接收器:
应用程序可以使用它对外部事件进行过滤只对感兴趣的外部事件(如当电话呼入时,或者数据网络可用时)进行接收并做出响应。广播接收器没有用户界面。然而,它们可以启动一个activity或serice 来响应它们收到的信息,或者用NotificationManager 来通知用户。通知可以用很多种方式来吸引用户的注意力──闪动背灯、震动、播放声音等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。
Service 服务:
一个Service 是一段长生命周期的,没有用户界面的程序,可以用来开发如监控类程序。
Content Provider内容提供者 :
android平台提供了Content Provider使一个应用程序的指定数据集提供给其他应用程序。这些数据可以存储在文件系统中、在一个SQLite数据库、或以任何其他合理的方式。其他应用可以通过ContentResolver类(见ContentProviderAccessApp例子)从该内容提供者中获取或存入数据.(相当于在应用外包了一层壳),只有需要在多个应用程序间共享数据是才需要内容提供者。例如,通讯录数据被多个应用程序使用,且必须存储在一个内容提供者中。它的好处:统一数据访问方式。
参考:
Android四大基本组件介绍与生命周期


四大组件的具体作用以及用法

Acitivity 用于显示界面,接收用户输入,和用户交互。
Service 运行于后台无界面的程序,用于在后台完成一下任务,例如:音乐播放等。
BroadCast Receiver 接收系统或应用发出的广播并作出响应,例如:电话的呼入呼出等。
Content Provider 用于把APP本身的数据共享给其他APP,提供本APP数据的存取接口给其他APP。


Android平台的framework的层次结构?

应用层、应用框架层、中间件(核心库和运行时)、Linux内核


Activity


Activity
生命周期




启动Activity:onCreate->onStart->onResume
锁屏或被其它Activity覆盖:onPause->onStop
解锁或由被覆盖状态再回到前台:onRestart->onStart->onResume
跳转到其它Activity或按Home进入后台:onPause->onStop
退回到此Activity:onRestart->onStart->onResume
退出此Activity:onPause->onStop->onDestory
对话框弹出不会执行任何生命周期(注:对话框如果是Activity(Theme为Dialog),还是会执行生命周期的)
从A跳转到B:当B的主题为透明时,A只会执行onPause(A-onPause->B-(onCreate->onStart->onResume))
从A跳转到B:A-onPause->B-(onCreate->onStart->onResume)-A-onStop(注意是A执行onPause后开始执行B的生命周期,B执行onResume后,A才执行onStop,所以尽量不要在onPause中做耗时操作)
从B返回到A:B-onPause->A-(onRestart->onStart->onResume)-B-(onStop->onDestroy)


Activity和Fragment生命周期有哪些?

Activity——onCreate->onStart->onResume->onPause->onStop->onDestroy
Fragment——onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onPause->onStop->onDestroyView->onDestroy->onDetach


Activity四种启动模式的区别(LanchMode
的应用场景)

standard 模式
这是默认模式,每次激活Activity时都会创建Activity实例,并放入任务栈中。
singleTop 模式
如果在任务的栈顶正好存在该Activity的实例,就重用该实例( 会调用实例的 onNewIntent() ),否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例,只要不在栈顶,都会创建新的实例。
singleTask 模式
如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的 onNewIntent() )。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。如果栈中不存在该实例,将会创建新的实例放入栈中。
singleInstance 模式
在一个新栈中创建该Activity的实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例( 会调用实例的 onNewIntent() )。其效果相当于多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。
设置启动模式的位置在 AndroidManifest.xml 文件中 Activity 元素的 Android:launchMode 属性。
singleTop适合接收通知启动的内容显示页面。例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。
singleTask适合作为程序入口点。例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。
singleInstance应用场景:闹铃的响铃界面。 你以前设置了一个闹铃:上午6点。在上午5点58分,你启动了闹铃设置界面,并按 Home 键回桌面;在上午5点59分时,你在微信和朋友聊天;在6点时,闹铃响了,并且弹出了一个对话框形式的 Activity(名为 AlarmAlertActivity) 提示你到6点了(这个 Activity 就是以 SingleInstance 加载模式打开的),你按返回键,回到的是微信的聊天界面,这是因为
AlarmAlertActivity 所在的 Task 的栈只有他一个元素, 因此退出之后这个 Task 的栈空了。如果是以 SingleTask 打开 AlarmAlertActivity,那么当闹铃响了的时候,按返回键应该进入闹铃设置界面。


Activity中类似onCreate、onStart运用了哪种设计模式,优点是什么

模板模式。每次新建一个Actiivty时都会覆盖onCreate,onStart等方法,这些方法在父类中就相当于一个模板。


如何将一个Activity设置成窗口的样式

在AndroidManifest.xml文件中设置当前需要改变成窗口样式的Activity的属性。
1
android:theme="@android:style/Theme.Dialog"
在styles.xml文件中自定义一个主题样式,改主题样式必须继承Dialog的样式.


Activity的启动过程

无论是通过Launcher来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都通过Binder进程间通信进入到ActivityManagerService进程中,并且调用ActivityManagerService.startActivity接口;
ActivityManagerService调用ActivityStack.startActivityMayWait来做准备要启动的Activity的相关信息;
ActivityStack通知ApplicationThread要进行Activity启动调度了,这里的ApplicationThread代表的是调用ActivityManagerService.startActivity接口的进程,对于通过点击应用程序图标的情景来说,这个进程就是Launcher了,而对于通过在Activity内部调用startActivity的情景来说,这个进程就是这个Activity所在的进程了;
ApplicationThread不执行真正的启动操作,它通过调用ActivityManagerService.activityPaused接口进入到ActivityManagerService进程中,看看是否需要创建新的进程来启动Activity;
对于通过点击应用程序图标来启动Activity的情景来说,ActivityManagerService在这一步中,会调用startProcessLocked来创建一个新的进程,而对于通过在Activity内部调用startActivity来启动新的Activity来说,这一步是不需要执行的,因为新的Activity就在原来的Activity所在的进程中进行启动;
ActivityManagerService调用ApplicationThread.scheduleLaunchActivity接口,通知相应的进程执行启动Activity的操作;
ApplicationThread把这个启动Activity的操作转发给ActivityThread,ActivityThread通过ClassLoader导入相应的Activity类,然后把它启动起来。


window和activity之间关系?


WindowManager
的相关知识


Activity、Window
和 View 三者的区别

一个 Activity 构造的时候一定会构造一个 Window(PhoneWindow),并且只有一个。
这个Window会有一个ViewRoot(View、ViewGroup)。
通过addView()加载布局。
WindowMangerService 接收消息,并且回到 Activity 函数,比如onKeyDown()。
Activity 是控制单元,Window 是承载模型,View 是显示视图


一个activity打开另外一个activity,再打开一个activity?回去的时候发生了什么操作?


onActivityResult(int
requestCode, int resultCode, Intent data)方法的用法;

如果你想在Activity中得到新打开Activity关闭后返回的数据,你需要使用系统提供的startActivityForResult(Intent intent,int requestCode)方法打开新的Activity,新的Activity关闭后会向前面的Activity传回数据,为了得到传回的数据,你必须在前面的Activity中重写onActivityResult(int requestCode, int
resultCode,Intent data)方法。


不用Service,B页面为音乐播放,从A跳到B,再返回,如何使音乐继续播放?

A使用startActivityForResult方法开启B,B类结束时调用finish;A类的Intent有一个子Activity结束事件onActivityResult,在这个事件里继续播放音乐。


内存不足时,怎么保持Activity的一些状态,在哪个方法里面做具体操作?

在onSaveInstanceState方法中保存Activity的状态,在onRestoreInstanceState或onCreate方法中恢复Activity的状态


onSaveInstanceState方法

用于保存Activity的状态存储一些临时数据
Activity被覆盖或进入后台,由于系统资源不足被kill会被调用
用户改变屏幕方向会被调用
跳转到其它Activity或按Home进入后台会被调用
会在onStop之前被调用,和onPause的顺序不固定的


onRestoreInstanceState(Bundle
savedInstanceState)方法

用于恢复保存的临时数据,此方法的Bundle参数也会传递到onCreate方法中,你也可以在onCreate(Bundle savedInstanceState)方法中恢复数据
onRestoreInstanceState和onCreate的区别:当onRestoreInstanceState被调用时Bundle参数一定是有值的,不用做为null判断,onCreate的Bundle则可能会为null。官方文档建议在此方法中进行数据恢复。
由于系统资源不足被kill之后又回到此Activity会被调用
用户改变屏幕方向重建Activity时会被调用
会在onStart之后被调用


同一个程序不同的Activity如何放在不同的任务栈中?

需要为不同的activity设置不同的affinity属性,启动activity的Intent需要包含FLAG_ACTIVITY_NEW_TASK标记。


如何安全退出已调用多个Activity的Application?

记录打开的Activity:每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
发送特定广播:在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
递归退出:在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。


有几种在activity之间切换的方法?

startActivity()
startActivityForResult()


Fragment


Fragment生命周期








Activity中如何动态的添加Fragment?

123456789101112131415161718
//向活动添加碎片,根据屏幕的纵向和横向显示//1,获取碎片管理器FragmentManager fragment=getFragmentManager();//2,碎片的显示需要使用FragmentTransaction类操作FragmentTransaction transacction=fragment.beginTransaction();//获取屏幕管理器和默认的显示Display display=getWindowManager().getDefaultDisplay();//判断横屏if(display.getWidth()>display.getHeight()){	//获取java类	Frament1 frament1 =  new Frament1();	transacction.replace(android.R.id.content, frament1);}else{	Frament2 frament2 =  new Frament2();	transacction.replace(android.R.id.content, frament2);}//使用FragmentTransaction必须要committransacction.commit();


Fragment
特点

Fragment可以作为Activity界面的一部分组成出现;
可以在一个Activity中同时出现多个Fragment,并且一个Fragment也可以在多个Activity中使用;
在Activity运行过程中,可以添加、移除或者替换Fragment;
Fragment可以响应自己的输入事件,并且有自己的生命周期,它们的生命周期会受宿主Activity的生命周期影响。
Fragment可以轻松得创建动态灵活的UI设计,可以适应于不同的屏幕尺寸。从手机到平板电脑。
Fragment 解决Activity间的切换不流畅,轻量切换。
Fragment 替代TabActivity做导航,性能更好。
Fragment做局部内容更新更方便,原来为了达到这一点要把多个布局放到一个activity里面,现在可以用多Fragment来代替,只有在需要的时候才加载Fragment,提高性能。


Fragment嵌套多个Fragment会出现bug吗?

参考:http://blog.csdn.net/megatronkings/article/details/51417510


怎么理解Activity和Fragment的关系?

Fragment 拥有和 Activity 一致的生命周期,它和 Activity 一样被定义为 Controller 层的类。有过中大型项目开发经验的开发者,应该都会遇到过 Activity 过于臃肿的情况,而 Fragment 的出现就是为了缓解这一状况,可以说 它将屏幕分解为多个「Fragment(碎片)」(这句话很重要),但它又不同于 View,它干的实质上就是 Activity 的事情,负责控制 View 以及它们之间的逻辑。
将屏幕碎片化为多个 Fragment 后,其实 Activity 只需要花精力去管理当前屏幕内应该显示哪些 Fragments,以及应该对它们进行如何布局就行了。这是一种组件化的思维,用 Fragment 去组合了一系列有关联的 UI 组件,并管理它们之间的逻辑,而 Activity 负责在不同屏幕下(例如横竖屏)布局不同的 Fragments 组合。
这种碎片不单单能管理可视的 Views,它也能执行不可视的 Tasks,它提供了 retainInstance 属性,能够在 Activity 因为屏幕状态发生改变(例如切换横竖屏时)而销毁重建时,依然保留实例。这示意着我们能在 RetainedFragment 里面执行一些在屏幕状态发生改变时不被中断的操作。例如使用 RetainedFragment 来缓存在线音乐文件,它在横竖屏切换时依然维持下载进度,并通过一个 DialogFragment 来展示进度。


Service


Service的生命周期。




Service是运行在后台的android组件,没有用户界面,不能与用户交互,可以运行在自己的进程,也可以运行在其他应用程序的上下

文里。
Service随着启动形式的不同,其生命周期稍有差别。当用Context.startService()来启动时,Service的生命周期依次为:oncreate——>onStartCommand——>onDestroy
当用Context.bindService()启动时:onStart——>onBind——>onUnbind——>onDestroy


Service有哪些启动方法,有什么区别,怎样停用Service?

Service启动方式有两种;一是Context.startService和Context.bindService。
区别是通过startService启动时Service组件和应用程序没多大的联系;当用访问者启动之后,如果访问者不主动关闭,Service就不会关闭,Service组件之间因为没什么关联,所以Service也不能和应用程序进行数据交互。
而通过bindService进行绑定时,应用程序可以通过ServiceConnection进行数据交互。在实现Service时重写的onBind方法中,其返回的对象会传给ServiceConnection对象的onServiceConnected(ComponentName name, IBinder service)中的service参数;也就是说获取了serivce这个参数就得到了Serivce组件返回的值。Context.bindService(Intent
intent,ServiceConnection conn,int flag)其中只要与Service连接成功conn就会调用其onServiceConnected方法
停用Service使用Context.stopService


注册Service需要注意什么

无论使用哪种启动方法,都需要在xml里注册你的Service,就像这样:
123
<service  android:name=".packnameName.youServiceName"  android:enabled="true" />


service
可以执行耗时操作吗

不能,超过20s就会出现ARN


Service和Activity在同一个线程吗

默认情况下是在同一个主线程中。但可以通过配置android:process=”:remote” 属性让 Service 运行在不同的进程。
Service分为本地服务(LocalService)和远程服务(RemoteService):
1、本地服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,
也不需要AIDL。相应bindService会方便很多。主进程被Kill后,服务便会终止。
2、远程服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,
不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。
按使用方式可以分为以下三种:
startService 启动的服务:主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService;
bindService 启动的服务:该方法启动的服务可以进行通信。停止服务使用unbindService
startService 同时也 bindService 启动的服务:停止服务应同时使用stepService与unbindService
参考:http://www.cnblogs.com/linlf03/p/3296323.html


Service与Activity怎么实现通信

通过Binder对象。Activity调用bindService (Intent service, ServiceConnection conn, int flags)方法,得到Service对象的一个引用,这样Activity可以直接调用到Service中的方法,如果要主动通知Activity,我们可以利用回调方法。Binder 相关知识参考:http://blog.csdn.net/boyupeng/article/details/47011383
通过广播。Service向Activity发送消息,可以使用广播,当然Activity要注册相应的接收器。比如Service要向多个Activity发送同样的消息的话,用这种方法就更好。


Service里面可以弹出
dialog 或 Toast 吗

可以。
getApplicationContext()

Toast必须在UI主线程上才能正常显示,而在Service中是无法获得Acivity的Context的,在service中想显示出Toast只需将show的消息发送给主线程Looper就可以了。此时便可显示Toast。
1234567
Handler handler = new Handler(Looper.getMainLooper());  handler.post(new Runnable() {    public void run() {      Toast.makeText(getApplicationContext(), "存Service is runing!",                     Toast.LENGTH_SHORT).show();    }  });
Dialog的用法与此类似,但是要多加个权限,在manifest中添加此权限以弹出dialog
12
<uses-permission Android:name="android.permission.SYSTEM_ALERT_WINDOW" />dialog.getWindow().setType((WindowManager.LayoutParams.TYPE_SYSTEM_ALERT));


什么时候使用Service?

比如播放多媒体的时候,用户启动了其他的Activity这个时候程序要在后台继续播放。比如检测SD卡上文件的变化。在或者在后台记录你地理位置的改变等等。


说说Activity、Intent、Service是什么关系

一个Activity通常是一个单独的屏幕,每一个Activity都被实现为一个单独的类,这些类都是从Activity基类中继承来的,Activity类显示有视图控件组成的用户接口,并对视图控件的事件做出响应。
Intent的调用是用来进行架构屏幕之间的切换的。Intent是描述应用想要做什么。Intent数据结果中最重要的部分是动作和动作对应的数据,一个动作对应一个动作数据。
Service是运行在后台的代码,不能与用户交互,可以运行在自己的进程,也可以运行在其他应用程序的上下文里。需要通过某一个Activity或其他Context对象来调用。
Activity 跳转到Activity,Activtiy启动Service,Service打开Activity都需要Intent表明跳转的意图,以及传递参数,Intent是这些组件间信号传递的传承者。


怎么在启动一个activity时就启动一个service

在activity的onCreate里写startService(xxx);然后this.finish();结束自己..
这是最简单的方法 可能会有屏幕一闪的现象,如果UI要求严格的话用AIDL把


为什么在Service中创建子线程而不是Activity中

这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。


Service
与 Thread 的区别

很多时候,你可能会问,为什么要用 Service,而不用 Thread 呢,因为用 Thread 是很方便的,比起 Service 也方便多了,下面我详细的来解释一下。
1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。
2). Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!
既然这样,那么我们为什么要用 Service 呢?其实这跟 android 的系统机制有关,我们先拿 Thread 来说。Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该
Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。
举个例子:如果你的 Thread 需要不停地隔一段时间就要连接服务器做某种同步的话,该 Thread 需要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制之前创建的 Thread。因此你便需要创建并启动一个 Service ,在 Service 里面创建、运行并控制该 Thread,这样便解决了该问题(因为任何 Activity
都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例)。
因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread
做不到的。


如何保证
Service 在后台不被 kill

onStartCommand方法,返回START_STICKY
START_STICKY 在运行onStartCommand后service进程被kill后,那将保留在开始状态,但是不保留那些传入的intent。不久后service就会再次尝试重新创建,因为保留在开始状态,在创建 service后将保证调用onstartCommand。如果没有传递任何开始命令给service,那将获取到null的intent。
START_NOT_STICKY 在运行onStartCommand后service进程被kill后,并且没有新的intent传递给它。Service将移出开始状态,并且直到新的明显的方法(startService)调用才重新创建。因为如果没有传递任何未决定的intent那么service是不会启动,也就是期间onstartCommand不会接收到任何null的intent。
START_REDELIVER_INTENT 在运行onStartCommand后service进程被kill后,系统将会再次启动service,并传入最后一个intent给onstartCommand。直到调用stopSelf(int)才停止传递intent。如果在被kill后还有未处理好的intent,那被kill后服务还是会自动启动。因此onstartCommand不会接收到任何null的intent。
提升service优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = “1000”这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
提升service进程优先级
Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为6个等级,它们按优先级顺序由高到低依次是:
1.前台进程( FOREGROUND_APP)

2.可视进程(VISIBLE_APP )

3.次要服务进程(SECONDARY_SERVER )

4.后台进程 (HIDDEN_APP)

5.内容供应节点(CONTENT_PROVIDER)

6.空进程(EMPTY_APP)
当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以使用startForeground 将service放到前台状态。这样在低内存时被kill的几率会低一些。
onDestroy方法里重启service
service +broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service;
Application加上Persistent属性
监听系统广播判断Service状态
通过系统的一些广播,比如:手机重启、界面唤醒、应用状态改变等等监听并捕获到,然后判断我们的Service是否还存活,别忘记加权限啊。


什么是IntentService?有何优点?

IntentService也是一个Service,是Service的子类;IntentService和Service有所不同,通过Looper和Thread来解决标准Service中处理逻辑的阻塞的问题。
优点:Activity的进程,当处理Intent的时候,会产生一个对应的Service,Android的进程处理器现在会尽可能的不kill掉你。
IntentService的使用场景与特点。

IntentService是Service的子类,是一个异步的,会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题

优点:
一方面不需要自己去new Thread
另一方面不需要考虑在什么时候关闭该Service
onStartCommand中回调了onStart,onStart中通过mServiceHandler发送消息到该handler的handleMessage中去。最后handleMessage中回调onHandleIntent(intent)。


IntentService
作用是什么

IntentService 是继承于 Service 并处理异步请求的一个类,在IntentService 内有一个工作线程来处理耗时操作,启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在 IntentService 的 onHandleIntent
回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。


IntentService
与 Service的异同

直接创建一个默认的工作线程,该线程执行所有的intent传递给onStartCommand()区别于应用程序的主线程。
直接创建一个工作队列,将一个意图传递给你onHandleIntent()的实现,所以我们就永远不必担心多线程。
当请求完成后自己会调用stopSelf(),所以你就不用调用该方法了。
提供的默认实现onBind()返回null,所以也不需要重写这个方法。so easy啊
提供了一个默认实现onStartCommand(),将意图工作队列,然后发送到你onHandleIntent()实现。真是太方便了


ContentProvider

参考:http://blog.csdn.net/coder_pig/article/details/47858489


ContentProvider
简介

ContentProvider(内容提供者):为存储和获取数据提供统一的接口。可以在不同的应用程序之间共享数据。Android已经为常见的一些数据提供了默认的ContentProvider
ContentProvider 为存储和读取数据提供了统一的接口
使用ContentProvider,应用程序可以实现 app 间数据共享
Android内置的许多数据都是使用ContentProvider形式,供开发者调用的(如视频,音频,图片,通讯录等)


请介绍下ContentProvider是如何实现数据共享的

创建一个属于你自己的Content provider或者将你的数据添加到一个已经存在的Content provider中,前提是有相同数据类型并且有写入Content provider的权限。


ContentProvider使用方法

参考:http://blog.csdn.net/juetion/article/details/17481039


Broadcast


注册广播有哪几种方式,有什么区别

在应用程序的代码中注册
12
registerReceiver(receiver,filter);// 注册BroadcastReceiverunregisterReceiver(receiver);// 取消注册BroadcastReceiver
当BroadcastReceiver更新UI,通常会使用这样的方法注册。启动Activity时候注册BroadcastReceiver,Activity不可见时候,取消注册。
在androidmanifest.xml当中注册
12345
<receiver>    <intent-filter>     <action Android:name = "android.intent.action.PICK"/>    </intent-filter></receiver>
1)第一种不是常驻型广播,也就是说广播跟随程序的生命周期。
2)第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
静态注册:在AndroidManifest.xml文件中进行注册,当App退出后,Receiver仍然可以接收到广播并且进行相应的处理
动态注册:在代码中动态注册,当App退出后,也就没办法再接受广播了


一个
app 被杀掉进程后,是否还能收到广播

静态注册的常驻型广播接收器还能接收广播。


Android引入广播机制的用意?


无序广播、有序广播


本地广播和全局广播有什么差别

全局广播 BroadcastReceiver 是针对应用间、应用与系统间、应用内部进行通信的一种方式。
本地广播 LocalBroadcastReceiver 仅在自己的应用内发送接收广播,也就是只有自己的应用能收到。因广播数据在本应用范围内传播,不用担心隐私数据泄露的问题。 不用担心别的应用伪造广播,造成安全隐患。 相比在系统内发送全局广播,它更高效。


Intent


Intent的使用方法,可以传递哪些数据类型。

通过查询Intent/Bundle的API文档,我们可以获知,Intent/Bundle支持传递基本类型的数据和基本类型的数组数据,以及String/CharSequence类型的数据和String/CharSequence类型的数组数据。而对于其它类型的数据貌似无能为力,其实不然,我们可以在Intent/Bundle的API中看到Intent/Bundle还可以传递Parcelable(包裹化,邮包)和Serializable(序列化)类型的数据,以及它们的数组/列表数据。
所以要让非基本类型和非String/CharSequence类型的数据通过Intent/Bundle来进行传输,我们就需要在数据类型中实现Parcelable接口或是Serializable接口。
参考:http://blog.csdn.net/kkk0526/article/details/7214247


介绍一下Intent、IntentFilter


Context


Context区别

Activity和Service以及Application的Context是不一样的,Activity继承自ContextThemeWraper.其他的继承自ContextWrapper
每一个Activity和Service以及Application的Context都是一个新的ContextImpl对象
getApplication()用来获取Application实例的,但是这个方法只有在Activity和Service中才能调用的到。那么也许在绝大多数情况下我们都是在Activity或者Service中使用Application的,但是如果在一些其它的场景,比如BroadcastReceiver中也想获得Application的实例,这时就可以借助getApplicationContext()方法,getApplicationContext()比getApplication()方法的作用域会更广一些,任何一个Context的实例,只要调用getApplicationContext()方法都可以拿到我们的Application对象。
Activity在创建的时候会new一个ContextImpl对象并在attach方法中关联它,Application和Service也差不多。ContextWrapper的方法内部都是转调ContextImpl的方法
创建对话框传入Application的Context是不可以的
尽管Application、Activity、Service都有自己的ContextImpl,并且每个ContextImpl都有自己的mResources成员,但是由于它们的mResources成员都来自于唯一的ResourcesManager实例,所以它们看似不同的mResources其实都指向的是同一块内存
Context的数量等于Activity的个数 + Service的个数 + 1,这个1为Application


Application
Context 和 Activity Context 异同


Context
的理解


Handler


Handler
原理

Andriod提供了Handler 和 Looper 来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)。
Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。
Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
Message Queue(消息队列):用来存放线程放入的消息。
线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。
参考:
Handler、Looper、Message、MessageQueue基础流程分析


Handler消息机制,postDelayed会造成线程阻塞吗?对内存有什么影响?


Handler,
Looper的理解


Handler,Message,Looper异步实现机制与源码分析

参考:
Android
消息处理机制(Looper、Handler、MessageQueue,Message)


Handler有何作用?如何使用之(具体讲需要实现什么function)?

Android设计了Handler机制,由Handler来负责与子线程进行通讯,从而让子线程与主线程之间建立起协作的桥梁,使Android的UI更新的问题得到完美的解决。
参考:
Handler有何作用?如何使用?


Handler、Thread
和 HandlerThread 的区别

Handler 会关联一个单独的线程和消息队列。Handler默认关联主线程(即 UI 线程),虽然要提供Runnable参数 ,但默认是直接调用Runnable中的run()方法。也就是默认下会在主线程执行,如果在这里面的操作会有阻塞,界面也会卡住。如果要在其他线程执行,可以使用 HandlerThread。
HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,主要的作用是建立了一个线程,并且创立了消息队列,有自己的looper,可以让我们在自己的线程中分发和处理消息。
android.os.Handler可以通过Looper对象实例化,并运行于另外的线程中,Android提供了让Handler运行于其它线程的线程实现,也是就HandlerThread。HandlerThread对象start后可以获得其Looper对象,并且使用这个Looper对象实例Handler。
参考:
Android中的Thread
& HandlerThread & Handler


使用
Handler 时怎么避免引起内存泄漏

一旦Handler被声明为内部类,那么可能导致它的外部类不能够被垃圾回收。如果Handler是在其他线程(我们通常成为worker thread)使用Looper或MessageQueue(消息队列),而不是main线程(UI线程),那么就没有这个问题。如果Handler使用Looper或MessageQueue在主线程(main thread),你需要对Handler的声明做如下修改:
声明Handler为static类;
在外部类中实例化一个外部类的WeakReference(弱引用)并且在Handler初始化时传入这个对象给你的Handler;
将所有引用的外部类成员使用WeakReference对象。
12345678910111213141516
private static class MyHandler extends Handler {            private final WeakReference<HandlerActivity2> mActivity;     public MyHandler(HandlerActivity2 activity) {                	mActivity = new WeakReference<HandlerActivity2>(activity);            }    @Override            public void handleMessage(Message msg) {                	System.out.println(msg);                 if (mActivity.get() == null) {                      	return;                  }                  mActivity.get().todo();            }      }
当Activity finish后 handler对象还是在Message中排队。 还是会处理消息,这些处理有必要?正常Activitiy finish后,已经没有必要对消息处理,那需要怎么做呢?解决方案也很简单,在Activity onStop或者onDestroy的时候,取消掉该Handler对象的Message和Runnable。通过查看Handler的API,它有几个方法:removeCallbacks(Runnable
r)和removeMessages(int what)等。
12345678910
/**    * 一切都是为了不要让mHandler拖泥带水    */   @Override   public void onDestroy() {         mHandler.removeMessages(MESSAGE_1);         mHandler.removeMessages(MESSAGE_2);         mHandler.removeMessages(MESSAGE_3);          // ... ...           mHandler.removeCallbacks(mRunnable);           // ... ...   }
参考:
Handler内存泄漏分析及解决


AsyncTask


AsyncTask原理

参考:
深入理解AsyncTask的工作原理


网络请求是怎么做的异步呢?什么情况下用Handler,什么情况下用AsyncTask


Handler和AsyncTask的区别

这俩类都是用来实现异步的,其中AsyncTask的集成度较高,使用简单,Handler则需要手动写Runnable或者Thread的代码;另外,由于AsyncTask内部实现了一个非常简单的线程池,实际上是只适用于轻量级的异步操作的,一般不应该用于网络操作。(感谢网友指正,AsyncTask 通过重写的方式是可以用于长耗时操作的,而我只考虑了直接使用的情况就说它不适合网络操作,是不对的。)我问他Handler和AsyncTask的区别,一方面是因为他说用AsyncTask联网,因此我认为他对AsyncTask并不熟悉;但更重要的是在我问他实现异步的具体手段的时候,他同时提到了Handler和AsyncTask——用这种“混搭”的使用方式来写联网框架,就算不考虑AsyncTask的可用性,也显得非常怪异,这听起来更像是在“列举Android实现异步操作最常用的类”,而非“讲述实现网络异步操作的具体方式”。也就是说,我听了这句话后开始怀疑他封装过联网框架这件事的真实性。但我只是怀疑,并不确定,因此接着问了我想问的。
参考:
https://www.zhihu.com/question/30804052


AsyncTask的优缺点?能否同时并发100+AsyncTask呢?

参考:
AsyncTask到底是什么

线程


子线程中更新UI的方法

第一种:Handler+Message
第二种:
123456
new Handler(context.getMainLooper()).post(  new Runnable(){    public void run(){    //更新UI    }  });
第三种:
1234567
((Activity)context)runOnUiThread(  new Runnable(){    public void run(){      //更新UI    }  }  );


多线程

继承 Thread 类
实现 Runnable 接口
HandlerThread
Handler
AsyncTask
Activity.runOnUiThread(Runnable)
View.post(Runnable),View.postDelay(Runnable,long)
 ServiceThreadIntentServiceAsyncTask
When to use ?Task with no UI, but shouldn’t be too long. Use threads within service for long tasks.- Long task in general.- For tasks in parallel use Multiple threads (traditional mechanisms)- Long taskusually with no communication to main thread.(Update)- If communication is required, can use main thread handler or broadcast intents- When callbacks are needed (Intent triggered tasks).- Small task having to communicate with main thread.- For tasks in parallel use multiple instances OR Executor
TriggerCall to methodonStartService()Thread start() methodIntentCall to method execute()
Triggered From (thread)Any threadAny ThreadMain Thread (Intent is received on main thread and then worker thread is spawed)Main Thread
Runs On (thread)Main ThreadIts own threadSeparate worker threadWorker thread. However, Main thread methods may be invoked in between to publish progress.
Limitations /**Drawbacks**May block main thread- Manual thread management- Code may become difficult to read- Cannot run tasks in parallel.- Multiple intents are queued on the same worker thread.- one instance can only be executed once (hence cannot run in a loop) - Must be created and executed from the Main thread


线程同步

使用 synchronized 关键字创建 synchronized 方法。
使用 synchronized 创建同步代码块。
参考:
http://www.itzhai.com/java-based-notebook-thread-synchronization-problem-solving-synchronization-problems-synchronized-block-synchronized-methods.html#2.1%E3%80%81%E4%BD%BF%E7%94%A8synchronized%E5%85%B3%E9%94%AE%E5%AD%97%E5%88%9B%E5%BB%BAsynchronized%E6%96%B9%E6%B3%95%EF%BC%9A
http://www.juwends.com/tech/android/android-inter-thread-comm.html

进程


进程优先级

前台进程:即与用户正在交互的Activity或者Activity用到的Service等,如果系统内存不足时前台进程是最后被杀死的
可见进程:可以是处于暂停状态(onPause)的Activity或者绑定在其上的Service,即被用户可见,但由于失去了焦点而不能与用户交互
服务进程:其中运行着使用startService方法启动的Service,虽然不被用户可见,但是却是用户关心的,例如用户正在非音乐界面听的音乐或者正在非下载页面自己下载的文件等;当系统要空间运行前两者进程时才会被终止
后台进程:其中运行着执行onStop方法而停止的程序,但是却不是用户当前关心的,例如后台挂着的QQ,这样的进程系统一旦没了有内存就首先被杀死
空进程:不包含任何应用程序的程序组件的进程,这样的进程系统是一般不会让他存在的


AIDL
解决了什么问题

AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在 Android 设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如 Service, 设置了属性 android:process=”:remote” 后,Service 就会运行在另外一个进程)对象的操作,就可以使用AIDL生成可序列化的参数。
AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量级。它是使用代理类在客户端和实现端传递数据。


AIDL的全称是什么?如何工作?能处理哪些类型的数据

ADIL是一种接口定义语言,用于约束两个进程之间的通信规则,供编译器生成代码,实现android设备之间的进程通信。
进程之间的通信信息首先会被转换成AIDL协议消息,然后发送给对方,对方受到AIDL协议消息后在转换成相应的对象。AIDL支持类型包括java基础类型和String,List,Map,CharSequence,如果使用自定类型,必须实现Parcelable接口


Broadcast、Content
Provider 和 AIDL的区别和联系

这3种都可以实现跨进程的通信,那么从效率,适用范围,安全性等方面来比较的话他们3者之间有什么区别?
Broadcast:用于发送和接收广播!实现信息的发送和接收!
AIDL:用于不同程序间服务的相互调用!实现了一个程序为另一个程序服务的功能!

Content Provider:用于将程序的数据库人为地暴露出来!实现一个程序可以对另个程序的数据库进行相对用的操作!
Broadcast,既然是广播,那么它的优点是:注册了这个广播接收器的应用都能够收到广播,范围广。缺点是:速度慢点,而且必须在一定时间内把事情处理完(onReceive执行必须在几秒之内),否则的话系统给出ANR。
AIDL,是进程间通信用的,类似一种协议吧。优点是:速度快(系统底层直接是共享内存),性能稳,效率高,一般进程间通信就用它。
Content Provider,因为只是把自己的数据库暴露出去,其他程序都可以来获取数据,数据本身不是实时的,不像前两者,只是起个数据供应作用。一般是某个成熟的应用来暴露自己的数据用的。 你要是为了进程间通信,还是别用这个了,这个又不是实时数据。


进程间传输方式


Android进程间通信,Binder机制


Android跨进程通讯的方式


Android
Mashup设计的理解

触摸事件


View
的触摸事件分发机制

基础知识
所有Touch事件都被封装成了MotionEvent对象,包括Touch的位置、时间、历史记录以及第几个手指(多指触摸)等。
事件类型分为ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每个事件都是以ACTION_DOWN开始ACTION_UP结束。
对事件的处理包括三类,分别为传递——dispatchTouchEvent()函数、拦截——onInterceptTouchEvent()函数、消费——onTouchEvent()函数和OnTouchListener
传递流程
事件从Activity.dispatchTouchEvent()开始传递,只要没有被停止或拦截,从最上层的View(ViewGroup)开始一直往下(子View)传递。子View可以通过onTouchEvent()对事件进行处理。
事件由父View(ViewGroup)传递给子View,ViewGroup可以通过onInterceptTouchEvent()对事件做拦截,停止其往下传递。
如果事件从上往下传递过程中一直没有被停止,且最底层子View没有消费事件,事件会反向往上传递,这时父View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到Activity的onTouchEvent()函数。
如果View没有对ACTION_DOWN进行消费,之后的其他事件不会传递过来。
OnTouchListener优先于onTouchEvent()对事件进行消费。
上面的消费即表示相应函数返回值为true。
View不处理事件流程图:



View处理事件流程图:
View.onTouchEvent()
 返回true



拦截事件流程图:
ViewGroup.onInterceptTouchEvent()
 对MOVE、UP事件进行拦截



参考:
Android
Touch事件传递机制
事件分发机制


onInterceptTouchEvent()和onTouchEvent()的区别?

onInterceptTouchEvent()用于拦截触摸事件。
onTouchEvent()用于处理触摸事件。


view的事件冲突处理

View


View
绘制流程

当 Activity 接收到焦点的时候,它会被请求绘制布局,该请求由 Android framework 处理。绘制是从根节点开始,对布局树进行 measure 和 draw。整个 View 树的绘图流程在ViewRoot.java类的 performTraversals() 函数展开,该函数所做 的工作可简单概况为是否需要重新计算视图大小(measure)、是否需要重新安置视图的位置(layout)、以及是否需要重绘(draw),流程图如下:






View的绘制流程是从ViewRoot的
performTraversals()
方法开始,依次经过
measure()
layout()
draw()
三个过程才最终将一个View绘制出来。
参考:
公共技术点之
View 绘制流程


Android
绘图机制原理

参考:
Android中的绘制机制


requertlayout
onlayout onDraw drawChild 的区别和联系

requestLayout()方法 :会导致调用measure()过程 和 layout()过程 。 将会根据标志位判断是否需要ondraw。
onLayout()方法:如果该View是ViewGroup对象,需要实现该方法,对每个子视图进行布局。
调用onDraw()方法绘制视图本身,每个View都需要重载该方法,ViewGroup不需要实现该方法。
drawChild()去重新回调每个子视图的draw()方法。


View
刷新机制

在Android的布局体系中,父View负责刷新、布局显示子View;而当子View需要刷新时,则是通知父View来完成。
子View调用invalidate时,首先找到自己父View(View的成员变量mParent记录自己的父View),然后将AttachInfo中保存的信息告诉父View刷新自己。
在invalidate中,调用父View的invalidateChild,这是一个从第向上回溯的过程,每一层的父View都将自己的显示区域与传入的刷新Rect做交集。
这个向上回溯的过程直到ViewRoot那里结束,由ViewRoot对这个最终的刷新区域做刷新。
参考:
Android
View刷新机制


invalidata()
和 postInvalidata() 的区别及使用

invalidata() 必须在 UI 线程中调用,所以一般都是配合 Handler 使用。
postInvalidata() 可以在其他线程直接调用。


notifyDataSetChanged和notifyDataSetInvalidated的区别

notifyDataSetInvalidated(),会重绘整个控件(还原到初始状态)
notifyDataSetChanged(),重绘当前可见区域


SurfaceView和View的区别是什么?

SurfaceView中采用了双缓存技术,在单独的线程中更新界面。而View在UI线程中更新界面。


RemoteView在哪些功能中使用

在 AppWidget(桌面小插件)和 Notification(通知栏)中使用。
参考:
Android
widget 之RemoteView


自定义
View


自定义View相关方法

自定义属性的声明和获取
分析需要的自定义属性
在res/values/attrs.xml定义声明
在layout文件中进行使用
在View的构造方法中进行获取

测量onMeasure
布局onLayout(ViewGroup)
绘制onDraw
onTouchEvent
onInterceptTouchEvent(ViewGroup)
状态的恢复与保存


如何自定义控件


有哪些实现自定义控件的方法?

自定义控件的实现有三种方式,分别是:组合控件、自绘控件和继承控件。
参考:
Android自定义View的三种实现方式


优化自定义
View

为了加速你的view,对于频繁调用的方法,需要尽量减少不必要的代码。先从onDraw开始,需要特别注意不应该在这里做内存分配的事情,因为它会导致GC,从而导致卡顿。在初始化或者动画间隙期间做分配内存的动作。不要在动画正在执行的时候做内存分配的事情。
你还需要尽可能的减少onDraw被调用的次数,大多数时候导致onDraw都是因为调用了invalidate().因此请尽量减少调用invaildate()的次数。如果可能的话,尽量调用含有4个参数的invalidate()方法而不是没有参数的invalidate()。没有参数的invalidate会强制重绘整个view。
另外一个非常耗时的操作是请求layout。任何时候执行requestLayout(),会使得Android UI系统去遍历整个View的层级来计算出每一个view的大小。如果找到有冲突的值,它会需要重新计算好几次。另外需要尽量保持View的层级是扁平化的,这样对提高效率很有帮助。
如果你有一个复杂的UI,你应该考虑写一个自定义的ViewGroup来执行他的layout操作。与内置的view不同,自定义的view可以使得程序仅仅测量这一部分,这避免了遍历整个view的层级结构来计算大小。这个PieChart 例子展示了如何继承ViewGroup作为自定义view的一部分。PieChart 有子views,但是它从来不测量它们。而是根据他自身的layout法则,直接设置它们的大小。


自定义view控件以及自定义属性的使用


NavigationDrawer,PageAdapter等UI模式的使用和定制


Layout
布局


Android中常用的五种布局

FrameLayout(框架布局)
LinearLayout (线性布局)
AbsoluteLayout(绝对布局)
RelativeLayout(相对布局)
TableLayout(表格布局)


LinearLayout和RelativeLayout性能对比

RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View2次onMeasure
RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。
在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。
最后再思考一下文章开头那个矛盾的问题,为什么Google给开发者默认新建了个RelativeLayout,而自己却在DecorView中用了个LinearLayout。因为DecorView的层级深度是已知而且固定的,上面一个标题栏,下面一个内容栏。采用RelativeLayout并不会降低层级深度,所以此时在根节点上用LinearLayout是效率最高的。而之所以给开发者默认新建了个RelativeLayout是希望开发者能采用尽量少的View层级来表达布局以实现性能最优,因为复杂的View嵌套对性能的影响会更大一些。
参考 :
http://www.jianshu.com/p/8a7d059da746


Android中px,sp,dip,dp的区别与联系

px: pixel,即像素,1px代表屏幕上的一个物理的像素点。但px单位不被建议使用。因为同样像素大小的图片在不同手机显示的实际大小可能不同。要用到px的情况是需要画1像素表格线或阴影线的时候,如果用其他单位画则会显得模糊。
dip (dp): device independent pixel。dp (dip)是最常用也是最难理解的尺寸单位。与像素密度密切相关。Android系统定义了四种像素密度:低(120dpi)、中(160dpi)、高(240dpi)和超高(320dpi),它们对应的dp到px的系数分别为0.75、1、1.5和2,这个系数乘以dp长度就是像素数。例如界面上有一个长度为“80dp”的图片,那么它在240dpi的手机上实际显示为80x1.5=120px,在320dpi的手机上实际显示为80x2=160px。如果你拿这两部手机放在一起对比,会发现这个图片的物理尺寸“差不多”,这就是使用dp作为单位的效果。
sp: Scale-independent Pixel,即与缩放无关的抽象像素。sp和dp很类似但唯一的区别是,Android系统允许用户自定义文字尺寸大小(小、正常、大、超大等等),当文字尺寸是“正常”时,1sp=1dp=0.00625英寸,而当文字尺寸是“大”或“超大”时,1sp>1dp=0.00625英寸。类似我们在windows里调整字体尺寸以后的效果——窗口大小不变,只有文字大小改变。


asset目录与res目录的区别。

res 目录下面有很多文件,例如 drawable,mipmap,raw 等。res 下面除了 raw 文件不会被压缩外,其余文件都会被压缩。同时 res目录下的文件可以通过R 文件访问。
Asset 也是用来存储资源,但是 asset 文件内容只能通过路径或者 AssetManager 读取。
参考:
官方文档


Android屏幕适配

动画


Android属性动画特性

Android 起初有两种动画:Frame Animation(逐帧动画) Tween Animation(补间动画),但是在用的时候发现这两种动画有时候并不能满足我们的一些需要,所以Google在Androi3.0的时候推出了(Property Animation)属性动画,至于为什么前边的两种动画不能满足我们的需要,请往下看:
Frame Animation(逐帧动画)
逐帧动画就是UI设计多张图片组成一个动画,然后将它们组合链接起来进行动画播放。该方式类似于早期电影的制作原理:具体实现方式就不多说了,你只需要让你们的UI出多张图片,然后你顺序的组合就可以(前提是UI给您做图)
Tween Animation(补间动画)
Tween Animation:是对某个View进行一系列的动画的操作,包括淡入淡出(Alpha),缩放(Scale),平移(Translate),旋转(Rotate)四种模式
Tween Animation(补间动画)的一些缺点:
Tween Animation(补间动画)只是针对于View,超脱了View就无法操作了,这句话的意思是:假如我们需要对一个Button,ImageView,LinearLayout或者是其他的继承自View的各种组件进行动画的操作时,Tween Animation是可以帮我们完成我们需要完成的功能的,但是如果我们需要用到对一个非View的对象进行动画操作的话,那么补间动画就没办法实现了。举个例子:比如我们有一个自定义的View,在这个View中有一个Point对象用于管理坐标,然后在onDraw()方法中的坐标就是根据该Pointde坐标值进行绘制的。也就是说,如果我们可以对Point对象进行动画操作,那么整个自定义的View,那么整个自继承View的当前类就都有了动画,但是我们的目的是不想让View有动画,只是对动画中的Point坐标产生动画,这样补间动画就不能满足了。
Tween Animation动画有四种动画操作(移动,缩放,旋转,淡入淡出),但是我们现在有个需求就是将当前View的背景色进行改变呢?抱歉Tween Animation是不能帮助我们实现的。
Tween Animation动画只是改变View的显示效果而已,但是不会真正的去改变View的属性,举个例子:我们现在屏幕的顶部有一个小球,然后通过补间动画让他移动到右下角,然后我们给这个小球添加了点击事件,希望位置移动到右下角的时候点击小球能的放大小球。但是点击事件是绝对不会触发的,原因是补间动画只是将该小球绘制到了屏幕的右下角,实际这个小球还是停在屏幕的顶部,所以你在右下角点击是没有任何反应的。
Property Animatior(属性动画)
属性动画是Android3.0之后引进的,它更改的是动画的实际属性,在Tween Animation(补间动画)中,其改变的是View的绘制效果,真正的View的属性是改变不了的,比如你将你的Button位置移动之后你再次点击Button是没有任何点击效果的,或者是你如何缩放你的Button大小,缩放后的有效的点击区域还是只有你当初初始的Button的大小的点击区域,其位置和大小的属性并没有改变。而在Property
Animator(属性动画)中,改变的是动画的实际属性,如Button的缩放,Button的位置和大小属性值都会发生改变。而且Property Animation不止可以应用于View,还可以应用于任何对象,Property Animation只是表示一个值在一段时间内的改变,当值改变时要做什么事情完全是你自己决定的。


Android动画框架实现原理

Animation 框架定义了透明度,旋转,缩放和位移几种常见的动画,而且控制的是整个View。实现原理:
每次绘制视图时,View 所在的 ViewGroup 中的 drawChild 函数获取该View 的 Animation 的 Transformation 值,然后调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧,如果动画没有完成,继续调用 invalidate() 函数,启动下次绘制来驱动动画,动画过程中的帧之间间隙时间是绘制函数所消耗的时间,可能会导致动画消耗比较多的CPU资源,最重要的是,动画改变的只是显示,并不能相应事件。
参考:
Android动画原理分析

图片缓存


图片三级缓存实现?自己设计一个图片加载框架

参考:
Android中图片的三级缓存
开源选型之Android三大图片缓存原理、特性对比



LruCache 的理解

参考:
内存缓存LruCache实现原理
Android提供的LruCache类简介


DiskLruCache

参考:
Android
DiskLruCache完全解析,硬盘缓存的最佳方案


缓存算法


Bitmap的分析与使用

参考:
Android
从具体实例分析Bitmap使用时候内存注意点
Android之Bitmap大图加载处理
Loading
Large Bitmaps Efficiently


Bitmap
压缩

123456789101112131415161718192021222324252627282930
public static Bitmap create(byte[] bytes, int maxWidth, int maxHeight) {		//上面的省略了        option.inJustDecodeBounds = true;        BitmapFactory.decodeByteArray(bytes, 0, bytes.length, option);        int actualWidth = option.outWidth;        int actualHeight = option.outHeight;        // 计算出图片应该显示的宽高        int desiredWidth = getResizedDimension(maxWidth, maxHeight, actualWidth, actualHeight);        int desiredHeight = getResizedDimension(maxHeight, maxWidth, actualHeight, actualWidth);        option.inJustDecodeBounds = false;        option.inSampleSize = findBestSampleSize(actualWidth, actualHeight,                desiredWidth, desiredHeight);        Bitmap tempBitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, option);        // 做缩放        if (tempBitmap != null                && (tempBitmap.getWidth() > desiredWidth || tempBitmap                .getHeight() > desiredHeight)) {            bitmap = Bitmap.createScaledBitmap(tempBitmap, desiredWidth,                    desiredHeight, true);            tempBitmap.recycle();        } else {            bitmap = tempBitmap;        }    }    return bitmap;}
你这么做,decodeByteArray两次不是更占内存吗?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐