android基础知识

Android 核心

阐述一下 Activity 的生命周期。

创建 onCreate - 启动onStart – 开始 onResume – 暂停 onPause – 结束 onStop – 销毁onDestroy

每一个活动( Activity )都处于某一个状态,对于开发者来说,是无法控制其应用程序处于某一个状态的,这些均由系统来完成。 但是当一个活动的状态发生改变的时候,开发者可以通过调用 onXX() 的方法获取到相关的通知信息。

在实现 Activity 类的时候,通过覆盖( override )这些方法即可在你需要处理的时候来调用。

•onCreate :当活动第一次启动的时候,触发该方法,可以在此时完成活动的初始化工作。 onCreate 方法有一个参数,该参数可以为空( null ),也可以是之前调用 onSaveInstanceState()方法保存的状态信息。

•onStart :该方法的触发表示所属活动将被展现给用户。

•onResume :当一个活动和用户发生交互的时候,触发该方法。

•onPause :当一个正在前台运行的活动因为其他的活动需要前台运行而转入后台运行的时候,触发该方法。这时候需要将活动的状态持久化,比如正在编辑的数据库记录等。

•onStop :当一个活动不再需要展示给用户的时候,触发该方法。如果内存紧张,系统会直接结束这个活动,而不会触发 onStop 方法。 所以保存状态信息是应该在onPause时做,而不是onStop时做。活动如果没有在前台运行,都将被停止或者Linux管理进程为了给新的活动预留足够的存储空间而随时结束这些活动。因此对于开发者来说,在设计应用程序的时候,必须时刻牢记这一原则。在一些情况下,onPause方法或许是活动触发的最后的方法,因此开发者需要在这个时候保存需要保存的信息。

•onRestart :当处于停止状态的活动需要再次展现给用户的时候,触发该方法。

•onDestroy :当活动销毁的时候,触发该方法。和 onStop 方法一样,如果内存紧张,系统会直接结束这个活动而不会触发该方法。

•onSaveInstanceState :系统调用该方法,允许活动保存之前的状态,比如说在一串字符串中的光标所处的位置等。 通常情况下,开发者不需要重写覆盖该方法,在默认的实现中,已经提供了自动保存活动所涉及到的用户界面组件的所有状态信息。

谈谈 Android 的四大组件。

活动:
Android 中,Activity是所有程序的根本,所有程序的流程都运行在Activity 之中,Activity可以算是开发者遇到的最频繁,也是Android 当中最基本的模块之一。在Android的程序当中,Activity 一般代表手机屏幕的一屏。如果把手机比作一个浏览器,那么Activity就相当于一个网页。在Activity 当中可以添加一些Button、Check box 等控件。可以看到Activity 概念和网页的概念相当类似。一般一个Android 应用是由多个Activity 组成的。这多个Activity 之间可以进行相互跳转,例如,按下一个Button按钮后,可能会跳转到其他的Activity。和网页跳转稍微有些不一样的是,Activity 之间的跳转有可能返回值,例如,从Activity A 跳转到Activity B,那么当Activity B 运行结束的时候,有可能会给Activity A 一个返回值。这样做在很多时候是相当方便的。   当打开一个新的屏幕时,之前一个屏幕会被置为暂停状态,并且压入历史堆栈中。用户可以通过回退操作返回到以前打开过的屏幕。可以选择性的移除一些没有必要保留的屏幕,因为Android会把每个应用的开始到当前的每个屏幕保存在堆栈中。

服务
Service 是android 系统中的一种组件,它跟Activity 的级别差不多,但是他不能自己运行,只能后台运行,并且可以和其他组件进行交互。Service 是没有界面的长生命周期的代码。Service是一种程序,它可以运行很长时间,但是它却没有用户界面。这么说有点枯燥,来看个例子。打开一个音乐播放器的程序,这个时候若想上网了,那么,打开Android浏览器,这个时候虽然已经进入了浏览器这个程序,但是,歌曲播放并没有停止,而是在后台继续一首接着一首的播放。其实这个播放就是由播放音乐的Service进行控制。当然这个播放音乐的Service也可以停止,例如,当播放列表里边的歌曲都结束,或者用户按下了停止音乐播放的快捷键等。Service 可以在和多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD 卡上文件的变化,再或者在后台记录地理信息位置的改变等等,总之服务嘛,总是藏在后头的。

开启Service有两种方式: (1) Context.startService():Service会经历onCreate -> onStart(如果Service还没有运行,则android先调用onCreate()然后调用onStart();     如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次 );     StopService的时候直接onDestroy,如果是调用者自己直接退出而没有调用StopService的话,Service会一直在后台运行。该Service的调用者再启动起来后可以通过stopService关闭Service。   *注意:多次调用Context.startservice()不会嵌套(即使会有相应的onStart()方法被调用),所以无论同一个服务被启动了多少次,一旦调用Context.stopService()或者StopSelf(),他都会被停止。   补充说明:传递给StartService(0的Intent对象会传递给onStart()方法。调用顺序为:onCreate --> onStart(可多次调用) --> onDestroy。 (2) Context.bindService():Service会经历onCreate() -->onBind(),onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind --> onDestroyed相应退出,所谓绑定在一起就共存亡了。

广播接收器
在Android 中,Broadcast是一种广泛运用的在应用程序之间传输信息的机制。而BroadcastReceiver 是对发送出来的Broadcast进行过滤接受并响应的一类组件。可以使用BroadcastReceiver 来让应用对一个外部的事件做出响应。这是非常有意思的,例如,当电话呼入这个外部事件到来的时候,可以利用BroadcastReceiver 进行处理。例如,当下载一个程序成功完成的时候,仍然可以利用BroadcastReceiver 进行处理。BroadcastReceiver不能生成UI,也就是说对于用户来说不是透明的,用户是看不到的。BroadcastReceiver通过NotificationManager 来通知用户这些事情发生了。BroadcastReceiver 既可以在AndroidManifest.xml 中注册,也可以在运行时的代码中使用Context.registerReceiver()进行注册。只要是注册了,当事件来临的时候,即使程序没有启动,系统也在需要的时候启动程序。各种应用还可以通过使用Context.sendBroadcast () 将它们自己的Intent Broadcasts广播给其他应用程序。

内容提供者
Content Provider 是Android提供的第三方应用数据的访问方案。   在Android中,对数据的保护是很严密的,除了放在SD卡中的数据,一个应用所持有的数据库、文件等内容,都是不允许其他直接访问的。Andorid当然不会真的把每个应用都做成一座孤岛,它为所有应用都准备了一扇窗,这就是Content Provider。应用想对外提供的数据,可以通过派生Content Provider类, 封装成一枚Content Provider,每个Content Provider都用一个uri作为独立的标识,形如:content://com.xxxxx。所有东西看着像REST的样子,但实际上,它比REST 更为灵活。和REST类似,uri也可以有两种类型,一种是带id的,另一种是列表的,但实现者不需要按照这个模式来做,给id的uri也可以返回列表类型的数据,只要调用者明白,就无妨,不用苛求所谓的REST。

Service 与 IntentService 的区别

Android中的Service是用于后台服务的,当应用程序被挂到后台的时候,问了保证应用某些组件仍然可以工作而引入了Service这个概念,那么这里面要强调的是Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,也就是说,在更多时候不建议在Service中编写耗时的逻辑和操作,否则会引起ANR。

那么我们当我们编写的耗时逻辑,不得不被service来管理的时候,就需要引入IntentService,IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去你执行你的耗时操作。

Android 应用的结构是什么?

Android 采用分层bai的架构,分为四层,从高du层到底层分为应用程序层,zhi应用程序框
架层,系统运行库层和Linux核心dao层
1,Android应用程序层
2,应用程序框架层
3,系统运行库层
4,Linux核心层

Android 应用中如何保存数据

android 五种数据存储 :SharePreferences、SQLite、Contert Provider、File、网络存储

两个 Fragment 之间如何通信

拿到Fragment实例然后调用它的函数
自定义接口回调
EventBus

两个不同的 app 之间如何交互

使用ContentProvider
使用文件或云端方式共享
BroadcastReceiver
使用AIDL

为什么 Bundle 被用来传递数据,为什么不能使用简单的 Map 数据结构

Bundle内部是由ArrayMap实现的,ArrayMap的内部实现是两个数组,一个int数组是存储对象数据对应下标,一个对象数组保存key和value,内部使用二分法对key进行排序,所以在添加、删除、查找数据的时候,都会使用二分法查找,只适合于小数据量操作,如果在数据量比较大的情况下,那么它的性能将退化。而HashMap内部则是数组+链表结构,所以在数据量较少的时候,HashMap的Entry Array比ArrayMap占用更多的内存。因为使用Bundle的场景大多数为小数据量,我没见过在两个Activity之间传递10个以上数据的场景,所以相比之下,在这种情况下使用ArrayMap保存数据,在操作速度和内存占用上都具有优势,因此使用Bundle来传递数据,可以保证更快的速度和更少的内存占用。
另外一个原因,则是在Android中如果使用Intent来携带数据的话,需要数据是基本类型或者是可序列化类型,HashMap使用Serializable进行序列化,而Bundle则是使用Parcelable进行序列化。而在Android平台中,更推荐使用Parcelable实现序列化,虽然写法复杂,但是开销更小,所以为了更加快速的进行数据的序列化和反序列化,系统封装了Bundle类,方便我们进行数据的传输。

解释下 Android 的 View

view是所有控件的父类,他的位置主要由他的四个顶点来决定。分别对应view的四个基本属性:left,top,right,bottom。其中top是左上角纵坐标,left是左上角的横坐标,right右下角的横坐标,bottom右下角的纵坐标。这些坐标都是相对于view的父控件来说的,因此它是一种相对坐标。在Android系统中,x轴和y轴的方向分别是向右和向下的

什么是 ViewGroup ,它与 View 的区别在哪里

View是所有UI组件的基类,而 ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的.简单的说就是:view指某些具体的控件,如Textview,imageview等,ViewGroup是用来盛放这些控件的容器,如LinearLayout和Relativelayout等

解释一下 Android 中的 Intent

Intent这个单词的意思就是"意图,目的,意向",Intent是一种运行时绑定(runtime binding)机制,它能在程序运行的过程中连接两个不同的组件。通过Intent,程序可以向Android表达某种请求或者意愿,Android会根据意愿的内容选择适当的组件来响应。Intent是由以下组件组成:
=component(组件):目的组件
action(动作):用来表现意图的行动
category(类别):用来表现动作的类别,或范畴
data(数据):表示与动作要操纵的数据
type(数据类型):对于data范例的描写
extras(扩展信息):扩展信息
Flags(标志位):期望这个意图的运行模式

Android 的权限有多少个不同的保护等级

normal:低风险权限,只要申请了就可以使用(在AndroidManifest.xml中添加标签),安装时不需要用户确认;
dangerous:高风险权限,安装时需要用户的确认才可使用;
signature:只有当申请权限的应用程序的数字签名与声明此权限的应用程序的数字签名相同时(如果是申请系统权限,则需要与系统签名相同),才能将权限授给它;
signatureOrSystem:签名相同,或者申请权限的应用为系统应用(在system image中)。
上述四类权限级别同样可用于自定义权限中。如果开发者需要对自己的应用程序(或部分应用)进行访问控制,则可以通过在AndroidManifest.xml中添加标签,将其属性中的protectionLevel设置为上述四类级别中的某一种来实现。

今日头条屏幕适配的原理?

1:首先计算出 density,计算公式:当前设备屏幕总宽度(单位为像素)/ 设计图总宽度(单位为 dp) = densitydensity 的意思就是 1 dp 占当前设备多少像素计算density 的原因:在布局文件中填写的是什么单位,最后都会被转化为 px,系统就是通过上面的方法,将你在项目中任何地方填写的单位都转换为 px

但是,今日头条适配方案默认项目中只能以高或宽中的一个作为基准,来进行适配

简述Android中的加固和使用平台?

加固:防止代码反编译,提高代码安全性

加固三方平台,梆梆安全,360加固,爱加密等

区别:梆梆安全,360加固看不到项目中的类,爱加密看的到Java类,单看不到里面的方法实现体,效果比前面差一点点

加固的底层原理:第三方加固的应用会生成一个Apk,然后把你的APK读取出来,在封装到这个第三方应用的APK里面.

如何对APK瘦身?

1)使用混淆,

2)开启shrinkResourse(shrink-收缩),会将没有用到的图片变成一个像素点

3)删除无用的语言资源(删除国际化文件)

4)对于非透明的大图,使用JPG(没有透明度信息),代替PNG格式

5)使用tinypng进行图片压缩

6)使用webp图片格式,进一步压缩图片资源

7)使用第三方包时把用到的代码加到项目中来,避免引用整一个第三方库

简述多渠道打包及原理和常用操作?

针对每一个渠道(应用市场)都生成一个带有渠道标识的apk文件

原理:用户下载启动应用,获取渠道标识,和设备的唯一标识,并上传到服务器里面,服务器这里就 会根据获取的记录,根据渠道号然后判断是否存在该服务器的表里面.(打标记,取标记,上传标记)

1)友盟多渠道打包:在清单文件中定义一个占位符,在gradle脚本中替换占位符(会使用到Python)

2)美团打包,在meta-data中创建一个空的文件,以文件名标识渠道,做一个解压与压缩的操作,速度会比较快

3)新一代多渠道打包,将渠道标识添加到.apk文件的末尾,并不会对源文件损坏

1)内部存储,直接存储在内部文件中

2)外部存储,首先要判断外部存储条件是否可用,然后进行存储

3)SP存储,底层是Xml实现的,以键值对形式存储内部的数据,适宜于轻量级的存储,存储的数据类型有,boolean,String,int

4)数据库存储,SQlite存储,轻量级的数据库,强大的增删改查功能

5)内容提供者,ContentProvider,将自己愿意暴露的一部分数据供外部使用操作

6)网络存储,等等

Sharepreference 线程安全问题?

官方文档明确指出,SharedPreferences不支持多线程,进程也是不安全的

如果想要实现线程安全需重新实现其接口,如下

假设在多进程访问SharePreferences的情况下,该如何保证进程安全和共享数据?

解决办法就是:将需要共享数据的字段提出来统一存储到一个文件中。

Android开发下如何有效进行屏幕适配?

1:机型适配,去一些统计网站诸如友盟,现在叫友盟+去看一下市场上最流行的Android机型,有针对性的切图

2:屏幕适配,适配主流xhdpi屏幕尺寸,使用relativelayout,linerlayout等布局,多使用matchparent,wrapcontent,及配合weight,权重处理,

3:还有就是在代码中,设计到具体尺寸的要使用dp2px的转换,

4:图片使用可拉伸.9图片,imageview使用scaletype缩放;

5:使用权重,等比例,百分比布局等等

对象序列化:

为什么要序列化?

1)永久性保存对象,保存对象的字节序列到本地文件中;

2)通过序列化对象在网络中传递对象;

3)通过序列化在进程间传递对象。

在Android中实现序列化有两个选择:一是实现Serializable接口(是JavaSE本身就支持的),一是实现Parcelable接口(是Android特有功能,效率比实现Serializable接口高效,可用于Intent数据传递,也可以用于进程间通信(IPC))。实现Serializable接口非常简单,声明一下就可以了,而实现Parcelable接口稍微复杂一些,但效率更高,推荐用这种方法提高性能。两种实现方式依旧是贴url,方便大家快速查询

两种序列化相关

既然Google推荐Parcelable这种序列化,在这里,推荐一键生成序列化的插件,

在Android Studio里面搜索插件,如下图,写起序列化(根本不用你写)那就是一个美滋滋呐~

OkHttp相关?

OkHttp支持同步和异步数据请求,但异步请求是在子线程 (因为原生OkHttp的使用时回调方法是在子线程进行的,要刷新界面还需要用Handler作处理,可以使用第三方的okhttp-utils,Okgo等等);

OkHttp里面封装了线程池、数据转换、GZIP压缩(减少流量的传输)、HTTP协议缓存等,

OKHttp优点—使用GZip压缩减少传输的数据量,缓存(减少重复请求);

失败重试(如果你的服务有多个IP地址,如果第一次连接失败,OKHttp将使用备用地址)

OKhttp是对http协议的封装,比较底层,因此拓展性强,便于封装;

OKhttp基于NIO(JDK1.5,非阻塞式IO)效率更高

ButterKnife相关?

简介:

一款快速高效的注入框架,节约开发时间减少代码量(依靠插件动态生成View,点击事件等等)

优点:

1.强大的View绑定和Click事件处理功能,简化代码,提升开发效率

2.方便的处理Adapter里的ViewHolder绑定问题

3.运行时不会影响APP效率,使用配置方便

4.代码清晰,可读性强

使用经验:

1.Activity ButterKnife.bind(this);必须在setContentView();之后,且父类bind绑定后,子类不需要再bind

2.Fragment ButterKnife.bind(this, mRootView);

3.属性布局不能用private or static 修饰,否则会报错,(注意权限)

4.setContentView()不能通过注解实现。(其他的有些注解框架可以)

原理:利用注解和反射去获取绑定ViewID,

关于原理详情可参考笔者的这一篇:Android-定制专属ButterKnife框架,该文详细介绍了ButterKnife框架并模仿了一个注解绑定View的框架

Rxjava概念,常用操作符及拓展?

简介:

一款优雅的异步框架,代替之前的AsyncTask / Handler / XXX / …

其强大的操作符和链式写法,线程切换等有助于提高开发效率和快速定位Bug

与Retrofit搭配使用更是有意想不到的效果,

底层原理:观察者模式

等一些相应的博客

缺点:

1:操作符太多会增加学习成本时间

2:使用不好,容易导致内存泄露(解决方式,推荐Rxlifecycle结合Rxjava,规避内存泄漏风险)

ANR相关

ANR全名Application Not Responding, 也就是"应用无响应". 当操作在一段时间内系统无法处理时, 系统层面会弹出上图那样的ANR对话框.

在Android里, App的响应能力是由Activity Manager和Window Manager系统服务来监控的. 通常在如下两种情况下会弹出ANR对话框:

A) 5s内无法响应用户输入事件(例如键盘输入, 触摸屏幕等).

B) BroadcastReceiver在10s内无法结束.

造成以上两种情况的首要原因就是在主线程(UI线程)里面做了太多的阻塞耗时操作, 例如文件读写, 数据库读写, 网络查询等等.

如何分析ANR?

ANR产生时, 系统会生成一个traces.txt的文件放在/data/anr/下. 开发人员可通过adb命令将其导出到本地 ($adb pull data/anr/traces.txt .)通过分析,我们可以根据具体的日志查看Anr原因( 如: 普通阻塞,CPU满负荷,内存泄露 )

Android中那些场景是执行在主线程的?

1)Activity生命周期回调都是执行在主线程的.

2)Service默认是执行在主线程的.

3)BroadcastReceiver的onReceive回调是执行在主线程的.

4)没有使用子线程的looper的Handler的handleMessage, post(Runnable)是执行在主线程的.

5)AsyncTask的回调中除了doInBackground, 其他都是执行在主线程的.

6)View的post(Runnable)是执行在主线程的.等等

三级缓存:

当我们第一次打开应用获取图片或其它资源时,首先到网络去下载,然后依次存入内存缓存,磁盘缓存,

当我们再一次需要用到刚才下载的这张图片时,就不需要再重复的到网络上去下载,直接可以从内存缓存和磁盘缓存中找,由于内存缓存速度较快,我们优先到内存缓存中寻找该图片,如果找到则运用,

如果没有找到(内存缓存大小有限),那么我们再到磁盘缓存中去找。

只要我们合理的去协调这三层缓存运用,便可以提升应用性能,给用户更好的体验

三级缓存指的是:内存缓存、本地缓存、网络缓存。其各自的特点是内存缓存速度快, 优先读取,本地缓存速度其次, 内存没有该资源信息就去读取本地内存,网络缓存速度较慢(比较对象是内存缓存和本地缓存),假设本地内存也没有,才请求网络获取。

内存泄漏:

当应用内部不再需要某个实例后,但是这个对象却仍然被引用,这个情况就叫做内存泄露(Memory Leak)。安卓虚拟机为每一个应用分配一定的内存空间,当内存泄露到达一定的程度就会造成内存溢出。

导致内存泄露常见原因:

1)静态变量直接或者间接地引用了Activity对象就会造成内存泄露

2)Activity使用了静态的View(View会持有Activity的对象的引用)

3)Activity定义了静态View变量???

4)ImageSpan引用了Activity Context

5)单例中引用了Activity的Context(需要使用Application的Context)

6)对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,从而造成内存泄漏。

7)静态集合保存的对象没有及时消除(不使用的时候置为null)

8)在Java中,非静态(匿名)内部类会引用外部类对象,而静态内部类不会引用外部类对象

9)在Activity中,创建了非静态内部类(内部类直接或者间接引用了Activity)的静态成员变量

10)线程包括AsyncTask的使用,Activity退出后线程还在运行(线程在死循环),并且在线程中使用了Activity或view对象(解决方法:不要直接写死循环,可以设置一个布尔类型的TAG,当activity推出的时候,设置TAG为False)

11)Handler对象的使用,Activity退出后Handler还是有消息需要处理(解决方法:在退出activity之后,移除消息)

12)WebView造成的内存泄漏(在onDestory中销毁)

如何进行内存泄露分析?

A: 通过Android Studio 窗口进行分析,查看内存分配情况,如果操作应用是内存一直往上涨说明存在内存泄露

B: 定位内存泄露分析的工具—MAT(Memory Analyzer tool)

C: 使用开源库LeakCanary快速定位内存泄露

Activity四种启动模式?

Activity的启动模式指,可以根据实际开发需求为Activity设置对应的启动模式,从而可以避免创建大量重复的Activity等问题。

1)standard

standard为Activity的默认启动模式,可以不用写配置。在这个模式下,都会默认创建一个新的实例。因此,在这种模式下,可以有多个相同的实例,也允许多个相同Activity叠加。(点back键会依照栈顺序依次退出)

2)singleTop

singleTop模式下,Activity可以有多个实例,但是不允许多个相同Activity叠加。即,如果Activity在栈顶的时候,启动相同的Activity,不会创建新的实例,而会调用其onNewIntent方法。

3)singleTask

singleTask表示只有一个实例。在同一个应用程序中启动他的时候,若Activity不存在,则会在当前task创建一个新的实例,若存在,则会把task中在其之上的其它Activity destory掉并调用它的onNewIntent方法。如果是在别的应用程序中启动它,则会新建一个task,并在该task中启动这个Activity,singleTask允许别的Activity与其在一个task中共存,也就是说,如果我在这个singleTask的实例中再打开新的Activity,这个新的Activity还是会在singleTask的实例的task中。

4)singleInstance

只有一个实例,并且这个实例独立运行在一个task中,这个task只有这个实例,不允许有别的Activity存在。

BraodcastReceiver:(待补充)

使用了设计模式中的观察者模式:基于消息的发布/订阅事件模型。

注册的方式分为两种:静态注册、动态注册

ContentProvider:(待补充)

外界可以通过ContentResolver接口来访问ContentProvider(内容提供者)中的数据。Uri 通用资源标志符(Universal Resource Identifier)Uri代表要操作的数据,Android中可用的每种资源 - 图像、视频片段等都可以用Uri来表示。ContentProvider共享数据是通过定义一个对外开放的统一的接口来实现的。然而,应用程序并不直接调用这些方法,而是使用一个 ContentResolver 对象,调用它的方法作为替代。ContentResolver可以与任意内容提供者进行会话,与其合作来对所有相关交互通讯进行管理。当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver类来完成,要获取ContentResolver对象,可以使用Context提供的getContentResolver()方法。

IntentService:

IntentService是Service的子类,比普通的Service增加了额外的功能。IntentService会创建独立的worker线程来处理所有的Intent请求;会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程的问题;所有请求处理完成后,IntentService会自动停止,开发者无需手动调用stopSelf()方法停止Service;

简述System.exit(0) 、onDestory()、Activity.finish()三者的区别

1)System.exit(0) 是你正常结束程序,kill 掉当前进程,针对的是整个Application

2)onDestory()方法是Activity生命周期的最后一步,资源空间等就被回收了。当重新进入此Activity的时候,必须重新创建,执行onCreate()方法.

3)Activity.finish()当你调用此方法的时候,系统只是将最上面的Activity移出了栈,并没有及时的调用onDestory()方法,也就是占用的资源没有被及时释放。

图片优化,以及图片加载框架的使用,如Picasso、 Fresco、Glide等?

1)尽量使用小的图片,对图片进行压缩,bitmapfactory.options图片配置类,insimplesize进行缩放,设置图片的编码方式;对图片使用软引用,内存不够时即时释图片内存;对图片的复用,三级缓存的使用;

即时回收不再使用的bitmap对象;

2)Picasso,不支持gif,缓存的是Argb8888的原图,占用内存较大,图片的框架使用了OkHttp缓存机制,使用Http协议缓存,也是异步加载.

3)Fresco,框架是FaceBook公司推出的,适合批量加载图片,底层是通过三级缓存(2级内存,1级磁盘)

加载成功后自动替换成目标图片

4)glide,Google公司14年推出来的,可以加载GIF图,也可以根据指定图片清晰度,底层的原理:为Bitmap维护一个对象池,对象池的目的是通过减少对象的分配,以重用来提高性能.对象池也可以帮助提高滚动的性能。API简洁易调用

Handle相关:

Handler 工作流程基本包括 Handler、Looper、Message、MessageQueue 四个部分。但我们在日常开发中,经常都只会用到 Handler 和 Message 两个类。Message 负责消息的搭载,里面有个target用于标记消息,obj用于存放内容,Handler 负责消息的分发和处理。

一般在开发中是怎么使用 Handler 的?
官方不允许在子线程中更新 UI,所以我们经常会把需要更新 UI 的消息直接发给处理器 Handler,通过重写 Handler 的handleMessage()方法进行 UI 的相关操作。

Handle使用中就没什么需要注意的吗?
有,Handler 如果设置为私有变量的话,Android Studio 会报警告,提示可能会造成内存泄漏,这种情况可以通过设置为静态内部类 + 弱引用,或者在onDestroy()方法中调用Handler.removeCallbacksAndMessages(null)即可避免

Handler 整体工作流程浅析分为以下四个步骤:

异步通信准备 => 消息入队 => 消息循环 => 消息处理

A:异步通信准备

I:假定是在主线程创建 Handler,则会直接在主线程中创建处理器对象Looper、消息队列对象MessageQueue和 Handler 对象。

需要注意的是,Looper和MessageQueue均是属于其创建线程的。

II:Looper对象的创建一般通过Looper.prepareMainLooper()和Looper.prepare()两个方法,而创建Looper对象的同时,将会自动创建MessageQueue。

III:创建好MessageQueue后,Looper将自动进入消息循环。此时,Handler自动绑定了主线程的Looper和MessageQueue。

B:消息入队

工作线程通过Handler发送消息Message到消息队列MessageQueue中,消息内容一般是 UI 操作。发送消息一般都是通过Handler.sendMessage(Message msg)和Handler.post(Runnabe r)两个方法来进行的。而入队一般是通过MessageQueue.enqueueeMessage(Message msg,long when)来处理。

C:消息循环

主要分为「消息出队」和「消息分发」两个步骤,Looper会通过循环取出消息队列MessageQueue里面的消息Message,并分发到创建该消息的处理者Handler。如果消息循环过程中,消息队列MessageQueue为空队列的话,则线程阻塞。

D:消息处理

Handler接收到Looper发来的消息,开始进行处理。

先简单介绍下你自己?

分析:除了向面试官做简单的基本自我介绍之外,还需向面试官展现自身对该职业所必须具备的一些自身特质,

比如,面试程序员职业需要间接的向面试官表示自己思维严谨,对细节的处理,理性思维,假设论证等等;面试产品等职业,需要向面试官通过自己的一些故事间接展现对产品的看法以及独特的思维个性等等

切入点:自身特质能否符合该职位的预期需求

对自己的期望和规划?

分析:职业发展规划表面上看是在考察你(求职者)、职位、公司三者之间长期的契合程度,但实际上,这么大的一个问题完全不是三眼两语间能够表达清楚的。面试官(无论HR还是专业部门的)主要是看你回答问题时的思路是否清晰,回答中表现出的工作态度如何,顺便看看你是否对公司和职位有足够的了解。所以不管答案如何,最关键的就是不能茫然。

切入点:依旧自身特点,对未来期望和规划需表述清晰,思维敏捷

android中的进程优先级

前台/可见/服务/后台/空

前台:包含正在处于和用户交互的Activity或者是前台Activity绑定了service
可见:activity处于可见状态但不可与用户进行交互
服务:包含一个service服务的进程
后台:处于不可见的状态下(比如按了home键)
空:没有活跃的组件 知识为了缓存的目的存在的,随时都可能被系统杀掉

Android任务栈

用于存储Activity,当用户启动Activity或者退出Activity的时候,都会在栈中做一些添加或删除的操作。

Activity启动模式

1.standard
默认的启动模式,每次启动Activity的时候都会创建一个新的实例。不会复用Activity,对内存消耗较大。

2.singleTop
栈顶复用模式,如果要创建的Activity已经在栈顶的话,那么不会重新创建,直接复用,否则,仍然会重新创建。

3.singletask
栈内复用模式,如果要创建的Activity在栈内已经存在的话,不会重新创建,直接复用栈内存在的Activity,且会调用onNewIntent()方法,并且将该Activity以上的所有的Activity销毁。

4.singleInstance
单一实例,独享一个任务栈,整个手机操作系统里面只有一个实例存在。用的较少。

scheme跳转协议
android中的scheme是一种页面内跳转协议,通过自定义的scheme协议,可以方便的跳转app中的各个页面。通过scheme协议,服务端可以定制化告诉App跳转到哪个页面,可以通过通知栏消息定制化跳转页面,也可以通过H5页面跳转页面等。
Socket 传输的特点:

优点

  1. 传输数据为字节级,传输数据可自定义,数据量小(对于手机应用讲:费用低)

2)传输数据时间短,性能高

3)适合于客户端和服务器端之间信息实时交互

4)可以加密,数据安全性强

缺点:

1)需对传输的数据进行解析,转化成应用级的数据

2)对开发人员的开发水平要求高

3)相对于Http协议传输,增加了开发量

链接: link.https://blog.csdn.net/MaybeForever/article/details/90612395?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-3.control

你可能感兴趣的:(android,java,编程语言,面试)