相信大家都有面试的经历,相对比面试官的问的一些问题其实都是基础的知识,但就是一些基础的知识我们也不是很完美的回答出来,我们也知道现在的开发人员很多,一家公司一个岗位就会有很多的开发者投递,在那么多开发者中你如何让面试官很深的认识你,给面试官一个很深的印象,能让他在技术水平差不多的情况的下第一个想起的是你。 从这篇文章对整个面试中所问到的问题进行梳理,查缺补漏。
Activity:
当面试官问你什么Activity,你是不是会觉得一阵懵* ?
在日常应用中,Android是用户交互的接口,他提供了一个界面,让用户进行点击,各种滑动操作等。
Activity的四种状态:
running / paused / stopped / killed
running:点击屏幕,屏幕做出响应,处于activity栈顶的状态
paused:失去焦点不能进行操作,或者是一个透明的在栈顶的Activity,注意并不是被销毁了啊,它的成员信息和变量都还在,当然还有另外一种状态,当内存紧张的时候会北回收掉
stopped:当一个Activity被另外一个Activity完全覆盖的时候,被覆盖的那个处于stopped状态,不可见,成员信息和变量都还在,如果内存紧张也是会被回收的
killed:已经被系统回收
生命周期:
启动:onCreate >> onStart >> onResume
点击HOME键回到主界面:onPause >> onStop
再次回到远Activity:onResrart>>onStart >> onResume
退出当前Activity:onPause >> onStop >> onDestroy
进程优先级:
前台 / 可见 /服务 /后台 / 空
前台:正在进行交互的Activity或者与前台activity绑定的services
可见:一个activity可见但并处于前台,不能点击
服务:在后台开启的服务
后台:当一个Activity被点击home键,退居后台,没有=被回收
空 :不属于前面四种进程的任意一种,处于缓存的目的而保留
启动模式:
standard / singletop / singletask / singleinstance
如何配置Activity的启动模式? 直接在AndroidManifest.xml配置的android:launchMode属性为以上四种之一即可
standrd:标准模式,每次启动都会重新创建一个activity实例加入到任务栈中,不会考虑是不是有此实例存在,不会复用,消耗内存资源
singletop :栈顶复用模式,只检测任务栈栈顶,只有在栈顶的Activity不会被创建,就算是在第二位也是会被创建
singletask:栈内复用模式,也是一个单例模式,检测整个任务栈,如果有并把在之上的实例全部移除掉,回掉onNewIntent方法
singleinstance:一个activity如果在整个系统中只存在一个实例,而且这个activity独享整个任务栈
应用场景:
singleTop:适合接收通知启动的内容显示页面。例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人,另外,singleTop启动模式适合于一些不常用的Activity页面,比如“找回密码”、“设置界面”等。
singleTask:最典型的样例就是应用中展示的主页(Home页),假设用户在主页跳转到其他页面,运行多次操作后想返回到主页,假设不使用SingleTask模式,在点击返回的过程中会多次看到主页,这明显就是设计不合理了。
singleInstance:比如说,使用微信调起自己的客户端某个页面,不做任何处理的情况下,按下回退或者当前Activity.finish(),页面不会停留在自己的客户端而是返回到微信的客户端页面。但是如果这个页面的启动模式设置为singleTask,当按下返回键或者Activity。finish(),页面都会停留在自己的客户端(因为自己的Application回退栈不为空),这明显不符合逻辑的。产品的要求是,回退必须回到微信客户端,而且要保证不杀死自己的Application.因此,显然其他的其他的启动模式都不具备这个功能。
scheme(sigeimo)跳转协议:
android中的scheme是一种页内跳转协议,是一种非常好的实现机制,通过定义自己的scheme协议,可以非常方便的在app内部跳转到各个界面;通过scheme协议,服务器可以定制化告诉app跳转到哪个页面,可以通过通知栏消息栏定制化跳转页面,也可以通过H5页面中定义连接跳转指定的activity页面等
应用场景:
1 服务端下发一个url路径,客户端根据下方的路径跳转到指定界面
2 从H5跳转到App内
3 App根据url挑战到另外的一个App
两个 Activity 之间跳转时必然会执行的是哪几个方法?
一般情况下比如说有两个 activity,分别叫 A,B,当在 A 里面激活 B 组件的时候, A 会调用 onPause()方法,然后 B 调用 onCreate() ,onStart(), onResume()。
这个时候 B 覆盖了窗体, A 会调用 onStop()方法. 如果 B 是个透明的,或者 是对话框的样式, 就不会调用 A 的 onStop()方法。
横竖屏切换时 Activity 的生命周期?
此时的生命周期跟清单文件里的配置有关系。
1.不设置 Activity 的 android:configChanges 时,切屏会重新调用各个生命周期默认首先销毁当前 activity,然后重新加载。 2.设置 Activity
android:configChanges=”orientation|keyboardHidden|screenSize”时,切 屏不会重新调用各个生命周期,只会执行
onConfigurationChanged 方法。
通常在游戏开发, 屏幕的朝向都是写死的。
如何将一个 Activity 设置成窗口的样式?
只需要给我们的 Activity 配置如下属性即可。
android:theme=”@android:style/Theme.Dialog”
Android 中的 Context, Activity,Appliction 有什么区别?
相同:Activity 和 Application 都是 Context 的子类。
Context 从字面上理解就是上下文的意思,在实际应用中它也确实是起到了管理 上下文环境中各个参数和变量的总用,方便我们可以简单的访问到各种资源。
不同:维护的生命周期不同。Context 维护的是当前的 Activity 的生命周期, Application 维护的是整个项目的生命周期。使用 context 的时候,小心内存泄露,防止内存泄露,注意一下几个方面:
1)不要让生命周期长的对象引用 activity context,即保证引用 activity 的对 象要与 activity 本身生命周期是一样的。
2 )对于生命周期长的对象,可以使用 application,context。
3 )避免非静态的内部类,尽量使用静态类,避免生命周期问题,注意内部类 对外部对象引用导致的生命周期变化。
如何获取当前屏幕Activity的对象?
使用ActivityLifecycleCallbacks
应用场景:可以利用ActivityLifecycleCallbacks 做一些数据埋点,统计之类的应用,对其统一做处理。这样对减少Activity的代码入侵。尽量简化和模块化的注入生命周期方法。
ActivityLifecycleCallbacks 是什么?
见名知意,Activity生命周期回调,Application通过此接口提供了一套回调方法,用于让开发者对Activity的生命周期事件进行集中处理。
但是这个要求API 14+ (Android 4.0+)以上使用,幸好我们这个最低支持,满足需求。
ActivityLifecycleCallbacks 怎么使用?
重写Application的onCreate()方法,或在Application的无参构造方法内,调用Application.registerActivityLifecycleCallbacks()方法,并实现ActivityLifecycleCallbacks接口
知道onNewIntent吗?
如果IntentActivity处于任务栈的顶端,也就是说之前打开过的Activity,现在处于onPause、onStop 状态的话,其他应用再发送Intent的话,执行顺序为:
onNewIntent,onRestart,onStart,onResume。
除了用Intent 去启动一个Activity,还有其他方法吗?
使用adb shell am 命令
1)ams启动一个activity
adb shell am start com.example.fuchenxuan/.MainActivity
2)am发送一个广播,使用action
adb shell am broadcast -a magcomm.action.TOUCH_LETTER
Android Service与Activity之间通信的几种方式?
通过Binder对象
1)当Activity通过调用bindService(Intent service, ServiceConnection conn,int flags),得到一个Service的一个对象,通过这个对象我们可以直接访问Service中的方法。
2)通过Broadcast Receiver(广播)的形式
3)EventBus 是一个Android开源事件总线框架
后面我们会有专门的讲解。
TaskAffinity 是什么?
标识Activity任务栈名称的属性:TaskAffinity,默认为应用包名
如果新Activity是透明主题时,旧Activity会不会走onStop?
不会!
android完全退出应用程序的三种方式?
第一种方法:首先获取当前进程的id,然后杀死该进程。 建议使用这种方式
android.os.Process.killProcess(android.os.Process.myPid())
第二种方法:终止当前正在运行的Java虚拟机,导致程序终止
System.exit(0);
第三种方法:强制关闭与该包有关联的一切执行
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
manager.restartPackage(getPackageName());
使用这种方式关闭应用程序需要加上权限
<uses-permission android:name="android.permission.RESTART_PACKAGES" />
Fragment:
三个小问题看你能完美解答几个
1 Fragment为什么被称为第五大组件?
2 Fragment的生命周期 ?
3 Fragment之间的通信 ?
1 Fragment为什么被称为第五大组件?
首先Fragment的使用频率并不低于其他四大组件,他有自己的生命周期,同时可以动态灵活的加载到Activity中,所以说Fragment可以被称为第五大组件
加载到Activity的两种方式:
1)添加Fragment到Activity的布局文件当中,也叫静态加载,name属性哦
2)动态的在activity中添加fragment ,也叫动态加载
步骤:
FragmentManage用来管理所有要启动的fragment,并用FragmentTransaction添加和替换相对应的fragment,并用容器资源来作为标志位来设置fragment所要显示到activity当中的位置,最后提交commit方法
(1)创建待添加的碎片实例
(2)获取FragmentManager,在活动中可以直接通过调用 getSupportFragmentManager()方法得到。
(3)开启一个事务,通过调用beginTransaction()方法开启。
(4)向容器内添加或替换碎片,一般使用repalce()方法实现,需要传入容器的id和待添加的碎片实例。
(5)提交事务,调用commit()方法来完成。
FragmentPageAdapter与FragmentStatePageAdapter的区别?
1 FragmentStatePageAdapter适合界面多,FragmentPageAdapter适合界面少
2 FragmentStatePageAdapter比FragmentPageAdapter更节省内存
源码分析:
FragmentPageAdapter适用于页面较少的情况下,因为只对ui分离并没有回收内存,
因为源码里面destoryItem是detach方法()只是对fragment和activity的ui脱离开来,并不回收内存
FragmentStatePageAdapter用于界面较多的情况下,界面多也就意味着更加的消耗内存,FragmentStatePageAdapter在每次切换fragment的时候,他是回收内存的,因为源码里面destoryItem的remove方法真正的释放的内存
Fragement的生命周期:
onAttach >> onCreate >> onCreateView >> onActivityCreated >>onStart >> onResume >> onPause >> onStop >> onDestoryView >> onDestory >>onDetach
很显然你要是像背书似的将上面的生命周期说一遍,你认为你跟其他的竞争者有什么优势?
你应该将Activity与Fragment的生命周期结合起来说:
首先,调用Activity的onCreate方法
当Fragment创建的时候会执行onAttach,是在Activity与fragment关联之后调用的
在之后执行onCreate方法,也就是在fragment创建的时候调用,注意,此时的activity还没有创建完毕
在调用fragment的onCreateView方法,系统首次绘制用户界面的时候调用
调用fragment的onActivityCreated方法,也就是activity被渲染绘制成功后调用,
现在是要调用activity的onStart的方法,当activity可见之后调用,
fragment的onStart方法,表示fragment也可见了
接着调用activity的onResume的方法,表示当前activity可以与用户交互了,当activity可见之后调用
fragment的onResume方法,表示当前fragment也可以与用户进行交互操作了,以上步骤完成了从创建到交互的所有步骤
在之后,Fragment的onPause
Activity的onPause
Fragment的onStop
Activity的onStop
现在来到了Frament的onDestoryView方法,表示当前fragment不在被使用,界面销毁,紧接着来到onDestory方法,表示fragment已经销毁了,最后调用onDetach来解除与activity的联系
最后调用Activity的onDestory方法
Fragment通信:
1)在Fragment中调用Activity的方法 geyActivity
2)在Activity中调用Fragment的方法 接口回调(在Fragment创建接口,在Activity实现)
3)在Fragment调用Fragment的方法 getActivity.findFragmentById 或者广播
Fragment的replace、add、remove?
add:将一个fragment实例添加到Activity的最上层,一般在使用add的时候会配合 hide,show一起使用,为了避免Fragment的重复创建节省资源。
remove:将fragment从fragment队列中删除
replace:替换fragment的实例,replace是FragmentManager的方法
commitAllowingStateLoss与commit的区别?
Activity被系统回收(界面已经不存在了),为了能在下次打开的时候恢复原来的样子,系统为我们保存界面的所有状态,这个时候再去修改界面理论上肯定是不被允许的,为了避免这种异常可以使用:
transaction.commitAllowingStateLoss();
来提交添加Fragment到Activity的事务,与commit()不同的是使用这种方法允许丢失界面的状态和信息。
ViewPager与Fragment结合使用时的懒加载问题?
所谓的 “懒加载” 就是数据只有在Fragment对于用户可见的时才进行加载,我们需要判定Fragment在什么时候是处于可见的状态。一般我们通常是通过Fragment中的生命周期方法onResume来判断Fragment是否可见,但是由于ViewPager预加载的特性,Fragment即便不可见也会执行onResume方法,可以通过setUserVisibleHint()方法来进行判断:
什么时候被调用?
当fragment被创建的时,setUserVisibleHint(boolean isVisibleToUser)方法会被调用,且传入参数值为false。
当fragment可见时,setUserVisibleHint(boolean isVisibleToUser)方法会被调用,且传入参数值为true。
当fragment由 可见 -> 不可见 时,setUserVisibleHint(boolean isVisibleToUser)方法会被调用,且传入参数值为false。
所以我们只需要当setUserVisibleHint(boolean isVisibleToUser)方法中的 isVisibleToUser 参数的值为true的时候我们才开始进行数据的加载就可以了。
但是有一点需要需要注意的是 setUserVisibleHint(boolean isVisibleToUser)方法在Fragment的生命周期方法onCreate 之前调用的,也就是说他并不在Fragment的生命周期中。既然是在 onCreate 方法之前被调用,这样就存在许多不确定因素,如果Fragmnet的View还没有完成初始化之前,就在setUserVisibleHint()方法中进行UI的操作,这样显然会导致空指针的出现。因此我们需要对Fragment创建的View进行缓存,确保缓存的View不为空的情况下我们才可以在setUserVisibleHint方法中进行UI操作。
Service
Service是什么?
四大组件之一,可以在后台处理一些耗时的逻辑,也可以执行某些长时间运行的任务,而且看不到界面,包括在程序退出的时候依然能在继续运行
Service与Broadcastrecevier有一个共同点,都是运行在主线程当中,都不能进行长耗时操作
Service与Thread的区别?
Thread程序最小的执行单元,Thread可以进行异步操作,相对独立;而Service是Android的一种机制,如果是本地的Service,依赖与它所在的主线程之上,相比Thread没有那么独立
为什么要用Service而不是Thread呢?
Thread的运行是独立于Activity的,也就是当一个Activity被finish之后,如果没有主动停止Thread或者Thread中的run没有执行完毕时那么这个线程会一直执行下去。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。
Service 是否在 main thread 中执行, service 里面是否 能执行耗时的操作?
默认情况,如果没有显示的指 servic 所运行的进程, Service 和 activity 是运 行在当前 app 所在进程的 main thread(UI 主线程)里面。
service 里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )
特殊情况 ,可以在清单文件配置 service 执行所在的进程 ,让 service
在另 外的进程中执行
<service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote" >
</service>
Service 里面可以弹吐司么?
可以的。弹吐司有个条件就是得有一个 Context 上下文,而 Service 本身就是 Context 的子类,因此在 Service 里面弹吐司是完全可以的。比如我们在 Service 中完成下载任务后可以弹一个吐司通知用户
Service 的 onStartCommand 方法有几种返回值?各代表什么意思?
有四种返回值,不同值代表的意思如下: START_STICKY:如果 service 进程被 kill 掉,保留 service 的状态为开始状态,但不保留递送的 intent 对象。随 后系统会尝试重新创建 service,由于服务状态为开始状态,所以创建服务后一定会调用 onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到 service,那么参数 Intent 将为 null。
START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完 onStartCommand 后,服务被异常 kill 掉,系统不会自动重启该服务。
START_REDELIVER_INTENT:重传 Intent。使用这个返回值时,如果在执行完 onStartCommand 后,服务被异 常 kill 掉,系统会自动重启该服务,并将 Intent 的值传入。
START_STICKY_COMPATIBILITY:START_STICKY 的兼容版本,但不保证服务被 kill 后一定能重启。
Service 的 onRebind(Intent)方法在什么情况下会执行?
如果在 onUnbind()方法返回 true 的情况下会执行,否则不执行。
Activity 调用 Service 中的方法都有哪些方式?
Binder:
通过 Binder 接口的形式实现,当 Activity 绑定 Service 成功的时候 Activity 会在 ServiceConnection 的类 的 onServiceConnected()回调方法中获取到 Service 的 onBind()方法 return 过来的 Binder 的子类,然后通过对象调用方法。
Aidl:
aidl 比较适合当客户端和服务端不在同一个应用下的场景。
Messenger: 它引用了一个Handler对象,以便others能够向它发送消息(使用mMessenger.send(Message msg)方法)。该类允许跨进程间基于Message的通信(即两个进程间可以通过Message进行通信),在服务端使用Handler创建一个Messenger,客户端持有这个Messenger就可以与服务端通信了。一个Messeger不能同时双向发送,两个就就能双向发送了
如何提高service的优先级?
可以用 setForeground(true) 来设置 Service 的优先级。
service 如何定时执行?
使用AlarmManager,根据AlarmManager的工作原理,alarmmanager会定时的发出一条广播,然后在自己的项目里面注册这个广播,重写onReceive方法,在这个方法里面启动一个service,然后在service里面进行网络的访问操作,当获取到新消息的时候进行推送,同时再设置一个alarmmanager进行下一次的轮询,当本次轮询结束的时候可以stopself结束改service。这样即使这一次的轮询失败了,也不会影响到下一次的轮询。这样就能保证推送任务不会中断
在 service 的生命周期方法 onstartConmand()可不可以执行网络操作?如何在 service 中执行网络操作?
可以直接在 Service 中执行网络操作,在 onStartCommand()方法中可以执行网络操作
Service 和 Activity 在同一个线程吗?
对于同一 app 来说默认情况下是在同一个线程中的,main Thread (UI Thread)。
什么是 IntentService?有何优点?
会创建独立的工作线程来处理所有的 Intent 请求;
会创建独立的工作线程来处理 onHandleIntent()方法实现的代码,无需
处理多线程问题;
所有请求处理完成后,IntentService 会自动停止,无需调用 stopSelf()方法
停止 Service;
为 Service 的 onBind()提供默认实现,返回 null;
为 Service 的 onStartCommand 提供默认实现,将请求 Intent 添加到队列
中;
Activity 怎么和 Service 绑定,怎么在 Activity 中启动自 己对应的 Service?
Activity 通过 bindService(Intent service, ServiceConnection conn, int flags)跟 Service 进行绑定,当绑定成功的时候 Service 会将代理对象通过回调 的形式传给 conn,这样我们就拿到了 Service 提供的服务代理对象。
在 Activity
中可以通过 startService 和 bindService 方法启动 Service。一 般情况下如果想获取 Service 的服务对象那么肯定需要通过 bindService()方 法,比如音乐播放器,第三方支付等。如果仅仅只是为了开启一个后台任务那么 可以使用 startService()方法。
IntentService 适用场景
IntentService 内置的是 HandlerThread 作为异步线程,每一个交给 IntentService 的任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理
正在运行的 IntentService 的程序相比起纯粹的后台程序更不容易被系统杀死,该程序的优先级是介于前台程序与纯后台程序之间的
Broadcast Receiver
广播的定义:
在Android中,Broadcast是一种广泛运用在程序之间的传输信息的机制,Android中我们要发送的广播内容中是一个Intent,这个Intent可以携带我们要传输的数据
广播的使用场景:
1)在同一个App具有多个进程的不同组件之间的消息传递
2)不同app之间的消息通信
广播的种类:
1)普通广播
2)系统广播 (sendOrderedBroadcast)
3 ) 本地广播(只在app内部传播)
不同注册方式广播接收器回调onReceive(context, intent)中context类型不一致?
manifest静态注册的ContextReceiver,回调onReceive(context, intent)中的context是ReceiverRestrictedContext;
代码动态注册的ContextReceiver,回调onReceive(context, intent)中的context是Activity Context;
内部实现机制?
1)自定义广播接受者Broadcast Receiver,并复写onRecvice方法
2)通过Binder机制像AMS进行注册
3)广播发送者通过Binder机制像AMS发送广播
4)AMS查找符合相应条件(IntentFilter/Permission等)的Broadcast Receiver,将广播发送到Broadcast Receiver相应的消息队列循环当中去(一般是Activity中)
5)消息循环拿到此广播,回调Broadcast Receiver中的onReceive方法、
如何让自己的广播只让指定的 app 接收?
通过自定义广播权限来保护自己发出的广播。 在清单文件里receiver必须有这个权限才能收到广播。 首先,需要定义权限: 然后,声明权限: 这时接收者就能收到发送的广播。
广播的优先级对无序广播生效吗?
生效的**
动态注册的广播优先级谁高?
谁先注册谁优先级高。
如何判断当前 BroadcastReceiver 接收到的是有序广播还是无序广播?
在 BroadcastReceiver 类中 onReceive()方法中,可以调用
boolean b = isOrderedBroadcast();判断接收到的广播是否为有序广播。
粘性广播有什么作用?怎么使用?
粘性广播主要为了解决,在发送完广播之后,动态注册的接收者,也能够收到广播。举个例子首先发送一广播,我的接收者是通过程序中的某个按钮动态注册的。如果不是粘性广播,我注册完接收者肯定无法收到广播了。这是通过发送粘性广播就能够在我动态注册接收者后也能收到广播。
网络
HttpConnection 与HttpURLConnection的区别?
在Android 2.2版本之前,HttpClient拥有较少的bug,因此使用它是最好的选择
2.3之后使用HttpURLConnection,它的API简单,体积较小,压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用,利于维护与优化
TCP与UDP的区别?
1)基于连接与无连接
2)对系统资源的要求(TCP较多,UDP较少)
3)UDP程序结构较简单一些
4)流模式与数据包模式
5)TCP保证数据的顺序性以及正确性,UDP不能保证,可能存在丢包
Socket:
soket是套接字,我们可以先在服务端初始化ServerSocket,然后对指定的端口进行绑定与监听,通过调用accept方法与getInputstream方法进行等待客户端的连接与数据的接收。现在客户端进行创建socket对象传入ip和端口号,通过getOutputStream进行数据的输入,并且制定结束字符,否则服务端会一直处于阻塞状态。
socket.close() 与socket.shutdownOutput()的区别?
1)在客户端或者服务端通过socket.shutdownOutput()都是单向关闭的,即关闭客户端的输出流并不会关闭服务端的输出流,所以是一种单方向的关闭流;
2)通过socket.shutdownOutput()关闭输出流,但socket仍然是连接状态,连接并未关闭
3)如果直接关闭输入或者输出流,即:in.close()或者out.close(),会直接关闭socket
socket长连接?
在不关闭流的情况下,开启循环线程进行定时发送与服务端约定的心跳包数据
Handler
什么是Handler?
handler通过发送和处理Message和Runnable对象来关联相对应线程的MessageQueue
作用:
1)可以让对应的Message和Runnable在未来的某个时间点进行相应处理
2)让自己想要处理的耗时操作放在子线程,让更新ui的操作放在主线程
Handler的使用?
1)post(Runnable)延迟消息处理
2)sendMessage(message)
Handler引起的内存泄漏以及解决办法?
HandlerThread是什么?有哪些特点
1)HandlerThread本质上是一个线程类,它继承了Thread
2)HandlerThread有自己内部Looper对象,可以进行Looper循环
3)通过获取HandlerThread的looper对象传递给Handler对象,可以在handlerMessage方法中执行异步任务
4)优点是不会阻塞,减少对性能的消耗,缺点是不能同时进行多任务的处理,需要等待进行处理
5)与线程池注重并发不同,HandlerThread是一个串行队列,HandlerThread背后只有一个线程
子线程为什么不能开启handler?
handler在调用sendMessage或者post(Runnable)的时候都需要一个MessageQueue 消息队列来保存发送的消息,而默认子线程中是没有开启Looper轮循器的,而消息队列又是由Looper来进行管理的,所以是没有办法开启的,
如果子线程想要开启,需要初始化looper,并且调用loop.loopers开启一个循环
ListView+RecyclerView
既然RecyclerView在很多方面能取代ListView,Google为什么没把ListView划上一条过时的横线?
ListView采用的是RecyclerBin的回收机制在一些轻量级的List显示时效率更高
ListView怎么和ScrollView兼容?
方法一:重写ListView, 覆盖onMeasure()方法
方法二:动态设置listview的高度,不需要重写ListView
方法三:在xml文件中,直接将Listview的高度写死
listview怎么优化?
1)、convertView复用,对convetView进行判空,当convertView不为空时重复使用,为空则初始化,从而减少了很多不必要的View的创建
2)定义一个ViewHolder,封装Listview Item条目中所有的组件,将convetView的tag设置为ViewHolder,不为空时通过ViewHolder的属性获取对应组件即可
3)、当ListView加载数据量较大时可以采用分页加载和图片异步加载
上拉加载和下拉刷新怎么实现?
实现OnScrollListener 接口重写onScrollStateChanged 和onScroll方法,
使用onscroll方法实现”滑动“后处理检查是否还有新的记录,如果有,调用 addFooterView,添加记录到adapter, adapter调notifyDataSetChanged 更新数据;如果没有记录了,把自定义的mFooterView去掉。使用onScrollStateChanged可以检测是否滚到最后一行且停止滚动然后执行加载
listview失去焦点怎么处理?
在listview子布局里面写,可以解决焦点失去的问题
android:descendantFocusability=”blocksDescendants”
ListView图片异步加载实现思路?
1.先从内存缓存中获取图片显示(内存缓冲)
2.获取不到的话从SD卡里获取(SD卡缓冲,,从SD卡获取图片是放在子线程里执行的,否则快速滑屏的话会不够流畅)
3.都获取不到的话从网络下载图片并保存到SD卡同时加入内存并显示(视情况看是否要显示)
你知道Listview里有Button就点不动了你知道吗?
原因是button强制获取了item的焦点,只要设置button的focusable为false即可。
listview分页加载的步骤?
通常实现分页加载有两种方式,一种是在ListView底部设置一个按钮,用户点击即加载。另一种是当用户滑动到底部时自动加载。
当用户滑动到底部时自动加载实现思路:
实现OnScrollListener 接口重写onScrollStateChanged 和onScroll方法,使用onscroll方法实现”滑动“后处理检查是否还有新的记录,如果有,添加记录到adapter, adapter调用 notifyDataSetChanged
更新数据;如果没有记录了,则不再加载数据。使用onScrollStateChanged可以检测是否滚到最后一行且停止滚动然后执行加载.
ViewHolder内部类非得要声明成static的呢?
因为非静态成员类的实例会包含一个额外的指向外围对象的引用,保存这份引用要消耗时间和空间,并且导致外围类实例符合垃圾回收时仍然被保留。如果没有外围实例的情况下,也需要分配实例,就不能使用非静态成员类,因为非静态成员类的实例必须要有一个外围实例。
RecyclerView滑动删除原理实现?
两种方法:
一种就是通过重写RecyclerView的onTouchEvent()方法来检测手势的变化实现的,大致的流程如下:
1、根据手指触摸的坐标点找到对应Item的ViewHolder,进而得到相应的Item布局View。
2、手指继续移动,在条件满足的情况下,通过scrollBy()使Item布局View内容跟随手指一起移动,当然要注意边界检测。
3、手指抬起时,根据Item布局View内容移动的距离以及手指的滑动速度,判断是否显示删除按钮,进而通过startScroll()使Item布局View自动滑动到目标位置。
4、点击删除按钮则删除对应Item,点击其它区域则隐藏删除按钮。
另外一种:
实现原理
主要是借助 ItemTouchHelper.Callback 类来实现,我们要关注的方法为
* getMovementFlags( )
* onMove()
* onSwiped()
* onSelectedChanged()
* clearView()
* isLongPressDragEnabled()
首先自定义一个MyCallback类继承 ItemTouchHelper.Callback ,定义两个int变量dragFlags 与 swipeFlags并实现下方法。这个方法主要是为了获取我们当前的事件是拖动还是滑动
其他:
Android View刷新机制?
在Android的布局体系中,父View负责刷新、布局显示子View;而当子View需要刷新时,则是通知父View来完成
RelativeLayout和LinearLayout性能比较?
1.RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View2次onMeasure
2.RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。
3.在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。
View和ViewGroup什么区别?
Android的UI界面都是由View和ViewGroup及其派生类组合而成的。其中,View是所有UI组件的基类,而ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的
音视频
SurfaceView是什么 ?
它继承自类View,因此它本质上是一个View。但与普通View不同的是,它有自己的Surface。有自己的Surface,在WMS中有对应的WindowState,在SurfaceFlinger中有Layer。我们知道,一般的Activity包含的多个View会组成View hierachy的树形结构,只有最顶层的DecorView,也就是根结点视图,才是对WMS可见的。这个DecorView在WMS中有一个对应的WindowState。相应地,在SF中对应的Layer。而SurfaceView自带一个Surface,这个Surface在WMS中有自己对应的WindowState,在SF中也会有自己的Layer。虽然在App端它仍在View
hierachy中,但在Server端(WMS和SF)中,它与宿主窗口是分离的。这样的好处是对这个Surface的渲染可以放到单独线程去做,渲染时可以有自己的GL context。这对于一些游戏、视频等性能相关的应用非常有益,因为它不会影响主线程对事件的响应。但它也有缺点,因为这个Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中,一些View中的特性也无法使用。
SurfaceView优点及缺点?
优点:可以在一个独立的线程中进行绘制,不会影响主线程。使用双缓冲机制,播放视频时画面更流畅
缺点:Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中。SurfaceView 不能嵌套使用
SurfaceView中双缓冲?
双缓冲:在运用时可以理解为:SurfaceView在更新视图时用到了两张Canvas,一张frontCanvas和一张backCanvas,每次实际显示的是frontCanvas,backCanvas存储的是上一次更改前的视图,当使用lockCanvas()获取画布时,得到的实际上是backCanvas而不是正在显示的frontCanvas,之后你在获取到的backCanvas上绘制新视图,再unlockCanvasAndPost(canvas)此视图,那么上传的这张canvas将替换原来的frontCanvas作为新的frontCanvas,原来的frontCanvas将切换到后台作为backCanvas。例如,如果你已经先后两次绘制了视图A和B,那么你再调用lockCanvas()获取视图,获得的将是A而不是正在显示的B,之后你讲重绘的C视图上传,那么C将取代B作为新的frontCanvas显示在SurfaceView上,原来的B则转换为backCanvas。
TextureView是什么?
在4.0(API level 14)中引入,与SurfaceView一样继承View, 它可以将内容流直接投影到View中,它可以将内容流直接投影到View中,可以用于实现Live preview等功能。和SurfaceView不同,它不会在WMS中单独创建窗口,而是作为View hierachy中的一个普通View,因此可以和其它普通View一样进行移动,旋转,缩放,动画等变化。值得注意的是TextureView必须在硬件加速的窗口中。它显示的内容流数据可以来自App进程或是远端进程。从类图中可以看到,TextureView继承自View,它与其它的View一样在View
hierachy中管理与绘制。TextureView重载了draw()方法,其中主要SurfaceTexture中收到的图像数据作为纹理更新到对应的HardwareLayer中。SurfaceTexture.OnFrameAvailableListener用于通知TextureView内容流有新图像到来。SurfaceTextureListener接口用于让TextureView的使用者知道SurfaceTexture已准备好,这样就可以把SurfaceTexture交给相应的内容源。Surface为BufferQueue的Producer接口实现类,使生产者可以通过它的软件或硬件渲染接口为SurfaceTexture内部的BufferQueue提供graphic
buffer。
TextureView优点及缺点?
优点:支持移动、旋转、缩放等动画,支持截图
缺点:必须在硬件加速的窗口中使用,占用内存比SurfaceView高,在5.0以前在主线程渲染,5.0以后有单独的渲染线程。
谁的性能更优?
播放器应该选择谁?
从性能和安全性角度出发,使用播放器优先选SurfaceView。 1、在android 7.0上系统surfaceview的性能比TextureView更有优势,支持对象的内容位置和包含的应用内容同步更新,平移、缩放不会产生黑边。 在7.0以下系统如果使用场景有动画效果,可以选择性使用TextureView
2、由于失效(invalidation)和缓冲的特性,TextureView增加了额外1~3帧的延迟显示画面更新
3、TextureView总是使用GL合成,而SurfaceView可以使用硬件overlay后端,可以占用更少的内存带宽,消耗更少的能量
4、TextureView的内部缓冲队列导致比SurfaceView使用更多的内存
5、SurfaceView: 内部自己持有surface,surface 创建、销毁、大小改变时系统来处理的,通过surfaceHolder 的callback回调通知。当画布创建好时,可以将surface绑定到MediaPlayer中。SurfaceView如果为用户可见的时候,创建SurfaceView的SurfaceHolder用于显示视频流解析的帧图片,如果发现SurfaceView变为用户不可见的时候,则立即销毁SurfaceView的SurfaceHolder,以达到节约系统资源的目的
未完待续