Activity生命周期?保存activity的一些信息在哪个生命周期方法中?
共有七个周期函数:
void onCreate(Bundle savedInstanceState) 第一次创建时调用
void onStart() 被用户可见时调用
void onResume() 当获得焦点即可与用户交互时调用
void onPause() 当失去焦点时调用
void onStop() 当不可见时调用
void onRestart() 当Activity处于stop状态又被重新启动时调用
void onDestroy() 当销毁时调用
onPause() 保存
说说Activity,Intent,Service是什么关系
一个 Activity 通常是一个单独的屏幕,每一个Activity 都被实现为一个单独的类,这些类都是从Activity 基类中继承来的,Activity 类会显示由视图控件组成的用户接口,并对视图控件的事件做出响应。
Intent 的调用是用户进行架构屏幕之间的切换的,Intent 是描述应用想要做什么。Intent 数据结构中两个最重要的部分是动作和动作对应的数据,一个动作对应一个动作数据。
Android Service 是运行在后台的代码,不能与用户交互,可以运行在自己的进程,也可以运行在其他应用程序进程的上下文里。需要通过某一个Activity 或者其他 Context 对象来调用.
Activity 跳转到 Activity ,Activity 启动Service ,Service 打开Activity都需要Intent 表时跳转的意图,以及传递参数,Intent 是这些组件间信号传递的承载者。
BroadcastReceive广播接收器:你的应用可以使用它 对外部事件进行过滤只对感兴趣的外部事件(如当电话呼入时,或者数据网络可用时)进行接收并做出响应。
当系统或用户应用程序发送了某广播之后,符合条件的广播接收者都将收到该条广播。
什么是IntentService,有何优点
IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent,对于异步的startService请求,IntentService会处理完成一个之后再处理第二个,每一个请求都会在一个单独的worker thread中处理,不会阻塞应用程序的主线程,这里就给我们提供了一个思路,如果有耗时的操作与其在Service里面开启新线程还不如使用IntentService来处理耗时操作。
android将进程的优先级分为5个层次,按照优先级由高到低排列如下:
- 前台进程(Foreground process)。它表明用户正在与该进程进行交互操作,android系统依据下面的条件来将一个进程标记为前台进程:
- 可见进程(Visible process)。它表明虽然该进程没有持有任何前台组件,但是它还是能够影响到用户看得到的界面。android系统依据下面的条件将一个进程标记为可见进程:
- 服务进程(Service process)。除了符合前台进程和可见进程条件的Service,其它的Service都会被归类为服务进程。
- 后台进程(Background process)。持有不可见Activity(调用了onStop()方法)的进程即为后台进程。通常情况下都会有很多后台进程,当内存不足的时候,在所有的后台进程里面,会按照LRU(最近使用)规则,优先回收最长时间没有使用过的进程。
- 空进程(Empty process)。不持有任何活动组件的进程。保持这种进程只有一个目的,就是为了缓存,以便下一次启动该进程中的组件时能够更快响应。当资源紧张的时候,系统会平衡进程缓存和底层的内核缓存情况进行回收。
Android Jetpack
对于任何一个产品来说,我们开发中都会面对哪些问题?如:产品交互、用户体验、代码结构、数据获取、数据存储、网络优化、任务调度等等,虽然在现在的阶段这些问题已经有了很好的解决和优化,也有很多大神的开源组件方便开发者去使用,Android Jetpack就是Google给出的一个官方的处理方法(当然知识处理其中基本问题),Android Jetpack组件的优势:
轻松管理应用程序的生命周期
构建可观察的数据对象,以便在基础数据库更改时通知视图
存储在应用程序轮换中未销毁的UI相关数据,在界面重建后恢复数据
轻松的实现SQLite数据库
系统自动调度后台任务的执行,优化使用性能
Android Jetpack组件推荐的使用项目架构
上面架构组件的功能如下:
Activity和Fragment负责产品与用户的交互
ViewModel作为数据的存储和驱动
Resposity负责调度数据的获取
Room储存本地序列化的数据
Retrofit获取远程数据的数据
SharedPreferences
/同步保存更改的方法/
boolean commit();
异步保存到磁盘,原子提交,性能更高,不保证结果/
void apply();
- SharedPreferences 是线程安全的. 内部由大量 synchronized 关键字保障
- SharedPreferences 不是进程安全的
Service的详解
Service生命周期可以从两种启动Service的模式开始讲起,分别是context.startService()和context.bindService()。
(1).startService的启动模式下的生命周期:当我们首次使用startService启动一个服务时,系统会实例化一个Service实例,依次调用其onCreate和onStartCommand方法,然后进入运行状态,此后,如果再使用startService启动服务时,不再创建新的服务对象,系统会自动找到刚才创建的Service实例,调用其onStart方法;如果我们想要停掉一个服务,可使用stopService方法,此时onDestroy方法会被调用,需要注意的是,不管前面使用了多个次startService,只需一次stopService,即可停掉服务。
(2).bindService启动模式下的生命周期:在这种模式下,当调用者首次使用bindService绑定一个服务时,系统会实例化一个Service实例,并一次调用其onCreate方法和onBind方法,然后调用者就可以和服务进行交互了,此后,如果再次使用bindService绑定服务,系统不会创建新的Service实例,也不会再调用onBind方法;如果我们需要解除与这个服务的绑定,可使用unbindService方法,此时onUnbind方法和onDestroy方法会被调用。
两种模式有以下几点不同之处:startService模式下调用者与服务无必然联系,即使调用者结束了自己的生命周期,只要没有使用stopService方法停止这个服务,服务仍会运行;通常情况下,bindService模式下服务是与调用者生死与共的,在绑定结束之后,一旦调用者被销毁,服务也就立即终止
Service 进程内与服务通信
进程内与服务通信实际上就是通过bindService的方式与服务绑定,获取到通信中介Binder实例,然后通过调用这个实例的方法,完成对服务的各种操作。
应用组件(客户端)可以调用bindService()绑定到一个service.Android系统之后调用service的onBind()方法,它返回一个用来与service交互的IBinder.
绑定是异步的.bindService()会立即返回,它不会返回IBinder给客户端.要接收IBinder,客户端必须创建一个ServiceConnection的实例并传给bindService().ServiceConnection包含一个回调方法,系统调用这个方法来传递要返回的IBinder.
IBinder是接口,你看前面有个I,理解为接口,他的实现类必须自己编写代码逻辑来实现功能。
Binder是实现了IBinder的具体实现类,他具有具体的功能,继承了Binder的类就是IBinder对象了。
服务端
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind called.");
return new MyBinder();
}
/**
* 绑定对象
*
* @author user
*/
public class MyBinder extends Binder {
//Activity调用
public void greet(String name) {
Log.i(TAG, "hello, " + name);
}
}
Activity里面 的代码。
bindService(intent, conn, Context.BIND_AUTO_CREATE);
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//connected
binder = (MyService.MyBinder) service; //获取其实例Service里面的MyBinder
binder.greet("scott"); //调用其方法
Log.i("MyService", "onServiceConnected called.");
}
/**
* Called when a connection to the Service has been lost.
* This typically happens when the process hosting the service has crashed or been killed.
* This does not remove the ServiceConnection itself.
* this binding to the service will remain active,
* and you will receive a call to onServiceConnected when the Service is next running.
*/
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
AIDL实现跨进程通讯
服务端
新建AIDL接口 编译器会自动生成一个和AIDL名字相同的JAVA类,这个 .java 文件才是与我们的跨进程通信密切相关的东西。
在服务端实现AIDL中定义的方法接口的具体逻辑,然后在客户端调用这些方法接口,AIDL接口相当于暴露出去可以给其他应用调用
写服务端代码的时候,第一块是初始化。在 onCreate() 方法里面我进行了一些数据的初始化操作。第二块是重写 BookManager.Stub 中的方法。在这里面提供AIDL里面定义的方法接口的具体实现逻辑。第三块是重写 onBind() 方法。在里面返回写好的 BookManager.Stub 。
客户端和服务端AIDL的包名必须完全一致。
客户端:
客户端我们要完成的工作主要是调用服务端的方法,但是在那之前,我们首先要连接上服务端,
首先bindService()建立连接,然后在 ServiceConnection 里面获取 服务端的AIDL接口 对象,(方法返回我们的接口的引用。接着客户端就可以通过它来对服务端发送请求了)
两种AIDL文件:在我的理解里,所有的AIDL文件大致可以
分为两类。一类是用来定义parcelable对象,以供其他AIDL文件使用AIDL中非默认支持的数据类型的。一类是用来定义方法接口,以供系统使用来完成跨进程通信的
AIDL可用数据类型
Java中的八种基本数据类型,包括 byte,short,int,long,float,double,boolean,char。
String 类型。
CharSequence类型。
List类型:List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable。List可以使用泛型
Map类型 Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable。Map是不支持泛型的
哪些地方是执行在主线程的
- [Activity的所有生命周期(https://www.jianshu.com/p/ec6984aa1bb4)都是执行在主线程的.
- Service默认是执行在主线程的
- BroadcastReceiver的onReceive回调是执行在主线程的.
- 没有使用子线程的looper的Handler的handleMessage, post(Runnable)是执行在主线程的.
- AsyncTask的回调中除了doInBackground, 其他都是执行在主线程的.
- View的post(Runnable)是执行在主线程的.
android如何动态刷新UI
1.利用Looper更新UI界面
2.AsyncTask利用线程任务异步更新UI界面 如果是后台任务,像是下载任务等,就需要使用AsyncTask。
3.利用Runnable更新UI界面
请描述一下Intent 和 Intent Filter。
Intent在Android中被翻译为"意图",熟语来讲就是目的,他们是三种应用程序基本组件—activity,service和broadcast receiver之间互相激活的手段。在调用Intent名称时使用ComponentName也就是类的全名时为显示调用。这种方式一般用于应用程序的内部调用,因为你不一定会知道别人写的类的全名。我们来看看隐式Intent怎么用?首先我们先配置我们的Activity的Intent Filter
<intent-filter><actionandroid:name="com.example.project.SHOW_CURRENT"/></intent-filter>
这样在调用的时候指定Intent的action,系统就是自动的去对比是哪个intent-filter符合我们的Activity,找到后就会启动Activity。
一个intent filter是IntentFilter类的实例, 但是它一般不出现在代码中,而是出现在android Manifest文件中, 以<intent-filter>的形式. (有一个例外是broadcast receiver的intent filter是使用Context.registerReceiver()来动态设定的, 其intent filter也是在代码中创建的.)
一个filter有action, data, category等字段. 一个隐式intent为了能被某个intent filter接受, 必须通过3个测试. 一个intent为了被某个组件接受, 则必须通过它所有的intent filter中的一个.
广播如何调用,有什么方式,各自的区别?
程序中发送广播通过sendBroadcastReceiver()实现
接收广播通过定义一个类继承BroadcastReceiver并重写onReceive()方法实现
注册广播有两种方式:
第一种静态方式:在清单文件中通过<receive>标签声明
第二种代码动态方式:
IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
IncomingSMSReceiver receiver = new IncomgSMSReceiver();
registerReceiver(receiver.filter);
1)第二种不是常驻型广播,也就是说广播跟随activity的生命周期。注意: 在activity结束前,移除广播接收器。
2)第一种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
Android中asset文件夹和raw文件夹区别?
res/raw和assets的相同点:
两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制。
res/raw和assets的不同点:
1)res/raw中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即 R.raw.filename;assets文件夹下的文件不会被映射到R.java中,访问的时候需要AssetManager类。
2)res/raw不可以有目录结构,而assets则可以有目录结构,也就是assets目录下可以再建立文件夹
3)读取文件资源举例:
读取res/raw下的文件资源,通过以下方式获取输入流来进行写操作
InputStream is = getResources().openRawResource(R.raw.filename);
读取assets下的文件资源,通过以下方式获取输入流来进行写操作
AssetManager am = null;
am = getAssets();
InputStream is = am.open("filename");
android系统架构
1)应用程序层 java语言 应用程序开发
2)应用程序框架层 java语言 OS定制 framework层开发
3)系统运行库层 C C++ 实现 so库
4)Linux内核层
请介绍下Android的数据存储方式。
使用SharedPreferences存储数据;
文件存储数据;
SQLite数据库存储数据;
使用ContentProvider存储数据;
网络存储数据
请介绍下ContentProvider是如何实现数据共享的。
答:当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。
虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;
采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。
而使用ContentProvider共享数据的好处是统一了数据访问方式。
当应用需要通过ContentProvider对外共享数据时,
第一步需要继承ContentProvider并重写下面方法:
第二步需要在AndroidManifest.xml使用<provider>对该ContentProvider进行配置,为了能让其他应用找到该ContentProvider , ContentProvider 采用了authorities(主机名/域名)对它进行唯一标识,你可以把 ContentProvider看作是一个网站(想想,网站也是提供数据者),authorities 就是他的域名:
你后台的Activity被系统回收怎么办? 如何在回收之前保存当前状态
当一个Activity被pause或者stop的时候,这个Activity的对象实际上还是保存在内存中,因此这个Activity中的信息(成员和状态信息)还可以重新获取到.
如果系统为了整理内存而销毁了整合各Activity对象时,系统没法简单的原封不动地恢复先前的Activity对象及其状态信息. Activity中提供了一个方法:onSavedInstanceState(Bundle obj).当系统销毁一个Activity时,会将Activity的状态信息已键值对形式存放在bundle对象中.
第一次启动Activity时,这个bundle对象是空的,null.如果Activity被系统销毁了,然后用户要回退回去看的话,系统会调用这个Activity的onCreate方法,并把bundle对象传递过去.
这个函数有默认的行为,因此就算你不覆盖它,它在Activity中也有实现.
另外,刚才查看了一下Activity的源码,发现Activity还有个onRestoreInstanceState(Bundle outState)方法.这个方法的描述中也写到在Activity恢复先前保存的状态时会被调用.
第二种情况 在OnStop中保存状态在本地,然后在OnResume中本地恢复状态。
如何将一个Activity设置成窗口的样式。 ]
1.在你的styles.xml文件-中可以新建一如下的style:
<style name="Theme.FloatActivity" parent="android:style/Theme.Dialog">
在AndroidManifest.xml中在你需要显示为窗口的activity中添加如果属性:android:theme="@style/Theme.FloatActivity"。
设置透明模式
android:theme="@android:style/Theme.Translucent"
如何退出Activity?如何安全退出已调用多个Activity的Application
1、抛异常强制退出: 该方法通过抛异常,使程序Force Close。 验证可以,但是,需要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。
2、记录打开的Activity: 用到Task杖 每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
3、发送特定广播: 在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
4、递归退出 在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。 除了第一个,都是想办法把每一个Activity都结束掉,间接达到目的。 但是这样做同样不完美。 你会发现,如果自己的应用程序对每一个Activity都设置了nosensor,在两个Activity结束的间隙,sensor可能有效了。 但至少,我们的目的达到了,而且没有影响用户使用。
Android App 安全策略
Activity window view 的关系
Activity、View、Window的理解一篇文章就够了
window 视图承载器
Activity在attch方法的时候,会创建一个phonewindow(window的子类)
onCreate中的setContentView方法,会创建DecorView
DecorView 的addview方法,会把layout中的布局加载进来。
java class 初始化和对象的创建顺序
静态变量/静态代码块 -> 普通代码块 -> 构造函数
- 父类静态变量和静态代码块;
- 子类静态变量和静态代码块;
- 父类普通成员变量和普通代码块;
- 父类的构造函数;
- 子类普通成员变量和普通代码块;
- 子类的构造函数。
class 文件被加载到内存中需要经过 3 大步:装载、链接、初始化
模块化 vs 组件化
模块化粒度更小,更侧重于重用,而组件化粒度稍大于模块,更侧重于业务解耦.
LeakCanary的实现原理。
用ActivityLifecycleCallbacks接口来检测Activity生命周期
主要是在Activity的&onDestroy方法中,手动调用 GC,然后利用ReferenceQueue+WeakReference,来判断是否有释放不掉的引用,然后结合dump memory的hpof文件, 用HaHa分析出泄漏地方。
WebView优化
- 全局WebView
方法:
在客户端刚启动时,就初始化一个全局的WebView待用,并隐藏;
当用户访问了WebView时,直接使用这个WebView加载对应网页,并展示。 - 客户端代理数据请求
方法:
在客户端初始化WebView的同时,直接由native开始网络请求数据;
当页面初始化完成后,向native获取其代理请求的数据
Android自定义组件实现思路
Android自定义组件有三种实现思路:
- 继承某个现有组件,在其基础上添加额外功能,如继承Gallery实现CoverFlow效果
- 继承某个Layout,实现复合组件自定义,如TextView和EditText组合实现登录注册组件
- 继承View,实现onDraw()方法,实现自己绘制组件,如翻页效果组件
版本更新的实现思路
答:在服务器相应URL上有版本文件, 客户端同时存储该应用当前版本号 (SharedPreferences/Sqlite), 每次打开应用,去检测服务器版本号与本地版本号是否一致,如果不一 致,则自定义对话框提示是否下载更新
实现一个自定义view的基本流程
1、自定义View的属性 编写attr.xml文件
2、在layout布局文件中引用,同时引用命名空间
3、在View的构造方法中获得我们自定义的属性 ,在自定义控件中进行读取(构造方法拿到attr.xml文件值)
4、重写onMesure
5、重写onDraw
View的整个绘制流程可以分为以下三个阶段:
measure: 判断是否需要重新计算View的大小,需要的话则计算;
layout: 判断是否需要重新计算View的位置,需要的话则计算;
draw: 判断是否需要重新绘制View,需要的话则重绘制。
这三个子阶段可以用下图来描述:
OnMeasure理解
首先会对父容器的MeasureSpec进行测量得出specMode和specSize(尺寸大小),然后对specMode进行判断是哪种类型,在对子元素的LayoutParams进行判断,最后来确定子元素的MeasureSpce,MeasureSpec由resultSize和resultMode组成,resultSize是View尺寸大小,resultMode是View类型。
specMode的类型有三种,每一种都有特殊含义:
1、EXACTLY
它对应于LayoutParams中的match_parent和具体的数值这两种模式
2、AT_MOST
父容器指定了一个可用大小即SpecSize,View的大小不能超过这个值,它对应于LayoutParams中的wrap_content。
- UNSPECIFIED
表示开发人员可以将视图按照自己的意愿设置成任意的大小,没有任何限制。这种情况比较少见,不太会用到。
NDK开发流程?(JNI运行原理)
答: NDK应用的开发流程(在应用中定义本地接口(native), 编译成.h头文件,交由C程序员实现,将.c实现通过NDK编译成.so动态链接库,导入项目中libs/armeabi,代码中调用该本地接口)
应用场景: 音频,视频解码,拍摄车牌号,识别车牌号
如何实现一键退出?
定义一个类继承Application,定义一个集合存放所有的activity,
定义一个添加的方法,再写一个退出的方法,使用for循环全部调用finish方法,然
后在每个Activity的onCreate方法中调用自定义类里的添加方法,然后在需要使用一
键退出的地方调用类中的退出方法即可。
android客户端如何实现自动登录
答: 通过SharedPreferences存储用户名,密码,当存储不为空时实现自动登录功能
ArrayList和LinkedList的大致区别:
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 (LinkedList是双向链表,有next也有previous)
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
HandlerThread 的原理和使用场景;
HandlerThread源码实现还是挺清楚的,首先我们看一下它的run()方法,可以发现该方法中调用Looper.myLooper()创建了一个Looper对象mLooper,并把该对象放到线程变量sThreadLocal中,然后通过调用Looper.loop()开启消息循环,Looper.loop()方法会不断循环从MessageQueue中取出消息处理消息,没有消息是则会阻塞。
HandlerThread有什么作用呢?能干什么?
比如说我们现在有个需求必须要Handler创建在子线程进行工作
我们需要手动创建子线程然后在子线程中创建Looper一些操作:
new Thread(new Runnable() {
@Override
public void run() {
// 在当前线程创建Looper对象
Looper.prepare();
// 创建Handler对象传入当前线程的Looper
Handler handler = new Handler(Looper.myLooper());
// 开始循环消息队列
Looper.loop();
}
}).start();
然而谷歌提供的HandlerThread类可以简化如上代码
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
就是这么简单,Handler就创建并工作在线程了
Android Studio 3.0 中 Gradle 的 api 和 implementation 有什么区别;
api:和 compile 的作用一样,当前 module 会暴露其依赖的其他 module 内容。
implementation:只在内部使用了该 module,不会向外部暴露其依赖的 module 内容。
EventBus原理
总结一下:register会把当前类中匹配的方法,存入一个map,而post会根据实参去map查找进行反射调用
Android的四大组件是什么?它们的作用是什么?
Android有四大组件:Activity、Service、Broadcast Receiver、Content Provider。
Activity :应用程序中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应。Activity之间通过Intent进行通信。
Service 服务:一个Service 是一段长生命周期的,没有用户界面的程序,可以用来开发如监控类程序。
BroadcastReceive广播接收器:你的应用可以使用它对外部事件进行过滤只对感兴趣的外部事件(如当电话呼入时,或者数据网络可用时)进行接收并做出响应。广播接收器没有用户界面。然而,它们可以启动一个activity或serice 来响应它们收到的信息。
Content Provider内容提供者 :主要用于多个应用间数据共享。这些数据可以存储在文件系统中或SQLite数据库。
二叉树的遍历:
一般来说,二叉树常用的遍历方式有:前序遍历、中序遍历、后序遍历、层序遍历 四种遍历方式,不同的遍历算法,其思想略有不同,我们来看一下这四种遍历方法主要的算法思想:
1、先序遍历二叉树顺序:根节点 –> 左子树 –> 右子树,即先访问根节点,然后是左子树,最后是右子树。
上图中二叉树的前序遍历结果为:0 -> 1 -> 3 -> 4 -> 2 -> 5 -> 6
2、中序遍历二叉树顺序:左子树 –> 根节点 –> 右子树,即先访问左子树,然后是根节点,最后是右子树。
上图中二叉树的中序遍历结果为:3 -> 1 -> 4 -> 0 -> 5 -> 2 -> 6
3、后续遍历二叉树顺序:左子树 –> 右子树 –> 根节点,即先访问左子树,然后是右子树,最后是根节点。
上图中二叉树的后序遍历结果为:3 -> 4 -> 1 -> 5 -> 6 -> 2 -> 0
4、层序遍历二叉树顺序:从最顶层的节点开始,从左往右依次遍历,之后转到第二层,继续从左往右遍历,持续循环,直到所有节点都遍历完成
上图中二叉树的层序遍历结果为:0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6
Android--判断App处于前台还是后台的方案
判断App处于前台还是后台的方案
通过runningProcess获取到一个当前正在运行的进程的List,我们遍历这个List中的每一个进程,判断这个进程的一个importance 属性是否是前台进程,并且包名是否与我们判断的APP的包名一样,如果这两个条件都符合,那么这个App就处于前台。
Intent的原理,作用,可以传递哪些类型的参数?
答:intent是连接Activity, Service, BroadcastReceiver, ContentProvider四大组件的信使,,可以传递八种基本数据类型以及string, Bundle类型,以及实现了Serializable或者Parcelable的类型。
Intent可以划分成显式意图和隐式意图。
显式意图:调用Intent.setComponent()或Intent.setClass()方法明确指定了组件名的Intent为显式意图,显式意图明确指定了Intent应该传递给哪个组件。
隐式意图:没有明确指定组件名的Intent为隐式意图。 Android系统会根据隐式意图中设置的动作(action)、类别(category)、数据(URI和数据类型)找到最合适的组件来处理这个意图。
如何实现屏幕分辨率的自适应?
答: 最好可以通过权重(layout_weight)的方式来分配每个组件的大小,也可以通过具体的像素(dip)来确定大小。
尽量使用Relativelayout 。
已知应用支持平台设备的分辨率,可以提供多个layout_320480 ...
drawable-hdpi,drawable-mdpi,drawable-ldpi分别代表分辨率为480800,360480,240360, 放置图片大小相差1.5倍
最后还需要在AndroidManifest.xml里添加下面一段,没有这一段自适应就不能实现:
<supports-screens
android:largeScreens="true"
android:normalScreens="true"
android:anyDensity = "true"/>
在</application>标签和</manifest> 标签之间添加上面那段代码。即可。
备注:三者的解析度不一样,就像你把电脑的分辨率调低,图片会变大一样,反之分辨率高,图片缩小
还可以通过.9.png实现图片的自适应
简述Android中的IPC机制
IPC(Inter-Process Communication,进程间通信),aidl是 Android Interface definition language的缩写,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口.编译器可以通过扩展名为aidl的文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的.
BroadcastReceiver也可以实现进程间通信
ContentProvider 提供进程间数据共享
MVP MVVM的调用关系
MVP(Passive View)的依赖关系
1、View不再负责同步的逻辑,而是由Presenter负责。Presenter中既有业务逻辑也有同步逻辑。
2、View需要提供操作界面的接口给Presenter进行调用。Presenter获取到Model变更的消息以后,通过View提供的接口更新界面。
MVVM
ViewModel是View与Model的连接器,持有可被观察的数据持有者和网络请求操作,数据变更实时渲染UI。
MVVM可以看作是一种特殊的MVP(Passive View)模式,或者说是对MVP模式的一种改良
MVVM的依赖关系和MVP依赖,只不过是把P换成了VM。
相对规范的mvvm应该这样写
1.mvvm和MVP比较大的区别是:vm和v是单向引用, 只有activity持有vm引用,vm是不持有view的引用的,所以vm的构造方法中不能传入视图相关的对象。之所以要这样,是为了防止生命周期问题导致的内存泄漏。
2.数据驱动。在常规的开发模式中,数据变化需要更新UI的时候,需要先获取UI控件的引用,然后再更新UI。 获取用户的输入和操作也需要通过UI控件的引用。在MVVM中,这些都是通过数据驱动来自动完成的, 数据变化后会自动更新UI,UI的改变也能自动反馈到数据层,数据成为主导因素。这样MVVM层在业务逻辑处理中只要关心数据,不需要直接和UI打交道,在业务处理过程中简单方便很多。
3.mvvm解决了mvp中接口繁杂、内存泄漏等疑难杂症。
4 结合jetpack相关组件,mvvm效果会很好。
横竖屏切换时候Activity的生命周期?
(1)设置 android:configChanges="orientation" 和不设置这个属性,生命周期表现为重新创建activity
(2)设置 android:configChanges="orientation|keyboardHidden",在2.3上表现为不重新创建activity,4.0如下
a)android:targetSdkVersion<="12",生命周期表现为不重新创建activity
b)android:targetSdkVersion>"12",表现为重新创建activity
(3)设置 android:configChanges="orientation|keyboardHidden|screenSize",在2.3和4.0上都表现为不重新创建
ScrollView 与 recyclerView、WebView的滑动冲突
用ScrollView 嵌套recyclerView或者WebView冲突时、可以在recyclerView或者WebView外面嵌套RelativeLayout
对于Android调用JS代码的方法有2种:
通过WebView的loadUrl()
通过WebView的evaluateJavascript()
对于JS调用Android代码的方法有3种:
通过WebView的addJavascriptInterface()进行对象映射
通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息
WebView中,主要漏洞有三类:
任意代码执行漏洞
漏洞产生原因
JS调用Android的其中一个方式是通过addJavascriptInterface接口进行对象映射:
webView.addJavascriptInterface(new JSObject(), "myObj");
// 参数1:Android的本地对象
// 参数2:JS的对象
// 通过对象映射将Android中的本地对象和JS中的对象进行关联,从而实现JS调用Android的对象和方法
所以,漏洞产生原因是:当JS拿到Android这个对象后,就可以调用这个Android对象中所有的方法,包括系统类(java.lang.Runtime 类),从而进行任意代码执行。
解决方案
Google 在Android 4.2 版本中规定对被调用的函数以 @JavascriptInterface进行注解从而避免漏洞攻击
密码明文存储漏洞:
WebView默认开启密码保存功能 :
mWebView.setSavePassword(true)`
开启后,在用户输入密码时,会弹出提示框:询问用户是否保存密码;
如果选择”是”,密码会被明文保到 /data/data/com.package.name/databases/webview.db 中,这样就有被盗取密码的危险
解决方案
关闭密码保存提醒
域控制不严格漏洞
可以在Application里面启动Activity吗?
在Application中通过以上方式跳转到Activity的话,会出现异常:原因是原有的任务栈已经销毁,因此要判断启动的activity是不是被销毁了。
解决方法:为activity开启新的栈,Intent.FLAG_ACTIVITY_NEW_TASK 设置状态,首先查找是否存在和被启动的Activity具有相同的任务栈,如果有则直接把这个栈整体移到前台,并保持栈中的状态不变,既栈中的activity顺序不变,如果没有,则新建一个栈来存放被启动的Activity。
Activity的启动模式。
在多Activity开发中,有可能是自己应用之间的Activity跳转,或者夹带其他应用的可复用Activity。可能会希望跳转到原来某个Activity实例,而不是产生大量重复的Activity。这需要为Activity配置特定的加载模式,而不是使加载模式。
在android里,有4种activity的启动模式,分别为:
standard: 标准模式,也是默认模式,一调用startActivity()方法就会产生一个新的实例。
singleTop: 如果已经有一个实例位于Activity栈的顶部时,就不产生新的实例,而只是调用Activity中的newInstance()方法。如果不位于栈顶,会产生一个新的实例。
singleTask: 单一任务。意思就是说当前的activity只有一个实例,无论在任何地方startActivity出来这个activity,它都只存在一个实例。并且,它会将在他之上的所有activity都销毁。通常这个activity都是用来作为MainActivity。
singleInstance: 它具备所有singleTask的特点,唯一不同的是,它是存在于另一个任务栈中。上面的三种模式都存在于同一个任务栈中,而这种模式则是存在于另一个任务栈中。
RxJava的链式调用过程?map操作符和flatMap操作符的区别?
map适用于一对一转换,当然也可以配合flatmap进行适用
flatmap适用于一对多,多对多的场景
获取控件宽和高的方法。
观察者模式
观察View的绘制流程,设置OnGlobalLayoutListener监听,布局完成时会调用onGlobalLayout(),在onGlobalLayout()方法里面获取空间的宽和高手动测量(自己调用measure()方法)
int measuredWidth = mTextView.getMeasuredWidth();
int measuredHeight = mTextView.getMeasuredHeight();View.post(Runnable action)
View.post()中的run方法和onWindowFocusChanged方法几乎是同时执行,都是在onLayout之后,所以都是可以得到控件的宽高的!!!
Android中你认为哪种动画最为强大?简述其实现原理。
通过不断控制 值 的变化,再不断 自动 赋给对象的属性,从而实现动画效果
属性动画,基于反射。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡, 通过插值器和估值器计算属性的变化百分比和值。
Multidex了解吗?它是用来解决什么问题的?一个工程有10W个方法,分几个dex文件?每个dex文件的方法数是多少?
Multidex用来解决单个dex文件方法数65535上限导致打包不成功的问题。一个10w方法的app打包应该有两个dex文件。其中一个方法数达到上限,另一个为100000-65535=34465。
bundle的数据结构,如何存储,既然有了Intent.putExtra,为啥还要用bundle。
bundle的内部结构其实是Map,传递的数据可以是boolean、byte、int、long、float、double、string等基本类型或它们对应的数组,也可以是对象或对象数组。当Bundle传递的是对象或对象数组时,必须实现Serializable 或Parcelable接口。
如何绘制大于父view的子view
1.clipChild用来定义他的子控件是否要在他应有的边界内进行绘制。 默认情况下,clipChild被设置为true。 也就是不允许进行扩展绘制。
- clipToPadding用来定义ViewGroup是否允许在padding中绘制。默认情况下,cliptopadding被设置为ture, 也就是把padding中的值都进行裁切了。
多点触控如何传递
在看 onDisptchTouchEvent 的时候,发现他是用了一个 mFirstTouchTarget 成员变量 来记住当前是否为第一个触控点,然后下个触摸点下来的时候 会检查 mFirstTouchTarget 是不是已经存在,如果已经存在 那么他就会调用 dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS); 来分发这次触摸事件,有趣的是dispatchTransformedTouchEvent ,他会根据 传进的第三个参数 child进行判断是否为null,如果为空那么说明他已经没有子view了。他就会直接调用 super.dispatchTouchEvent 来让他的父类方法,即View.dispatchTouchEvent 来判断是否 需要拦截,或者处理。出现这种情况的话 就会最终调用 这个viewgroup的ontouch事件,或者是onTouchListenner
AsyncTask机制
AsyncTask,异步任务,也就是说在UI线程运行的时候,可以在后台的执行一些异步的操作;AsyncTask可以很容易且正确地使用UI线程,AsyncTask允许进行后台操作,并在不显示使用工作线程或Handler机制的情况下,将结果反馈给UI线程。但是AsyncTask只能用于短时间的操作(最多几秒就应该结束的操作),如果需要长时间运行在后台,就不适合使用AsyncTask了,只能去使用Java提供的其他API来实现。
Android 线程间通信有哪几种方式
共享变量(内存)
AsyncTask
handle机制
runOnUiThread(Runnable)
view.post(Runnable)
JAVA中线程同步的方法(7种)汇总
、同步方法
即有synchronized关键字修饰的方法。 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。同步代码块
即有synchronized关键字修饰的语句块。 被该关键字修饰的语句块会自动被加上内置锁,从而实现同步wait与notify
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
notifyAll():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争
四、使用特殊域变量(volatile)实现线程同步
可见性。对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。
原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性。
Throwable、Exception、Error三者的关系,Exception和Error有什么区别,Error可以被捕获嘛
Throwable是java.lang包中一个专门用来处理异常的类。它有两个子类,即Error 和Exception,它们分别用来处理两组异常。
、Throwable类是整个异常体系类的“父级类”,当然最终追根溯源到底的父类当然要归于Object类。
一般Exception是程序在编译期间产生的异常,程序员必须通过try-catch进行捕获异常,因此也叫检查型异常。example:IOException。。。
Error指jvm导致的内部错误,类似系统崩溃等。
哪些方面取优化网络连接
第一节说到了网络请求对App和用户的影响, 那么我们怎么从哪些方面去优化网络进而减少甚至消灭这些影响呢?
简单来说, 两个方面:
减少Radio活跃时间
也就是减少网络数据获取的频次.
这就减少了radio的电量消耗, 控制电量使用.
减少获取数据包的大小
可以减少流量消耗
也可以让每次请求更快, 在网络情况不好的情况下也有良好表现, 提升用户体验.
引用
(一).强引用(StrongReference)
垃圾回收机制不会回收强引用所指向的内存,就算系统内存不足报出内存溢出(OOM)异常,导致系统崩溃
垃圾回收机制也不会去回收强引用的内容来解决内存不足的问题.
//强引用,也就是一般引用,使用new关键词新建出来的引用关系
ImageView imageview = new ImageView();
(二).软引用(SoftReference)
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;
如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。
软引用可用来实现内存敏感的高速缓存
(三).弱引用(WeakReference)
弱引用与软引用的区别在于:弱引用的对象拥有更短暂的生命周期。
在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,
不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,
因此不一定会很快发现那些只具有弱引用的对象。
(四).虚引用(PhantomReference)
“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。
如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
三级缓存原理
真如下图所示,
1.首先我们从内存中获取bitmap,
2.1.如果获取的bitmap != null,直接加载到ImageVIew
2.2.如果获取的bitmap==null,那么将继续从硬盘获取bitmap
3.1如果从硬盘获取的bitmap !=null,加载到ImageView.同时将bitmap缓存到内存缓存中
3.2如果从硬盘获取的bitmap == null,继续从网络获取
4.1从网络获取到图片,然后
4.2.加载到ImageVIew,缓存到硬盘,缓存到内存
进阶基础题
Service详解
关于AIDL使用和Binder机制详解
app启动流程
app启动流程-2
学习AIDL上
学习AIDL下
AIDL Demo
Android View的绘制流程
android launchMode理解以及应用场景
Android:聊聊我所理解的MVP
MVP应用
三级缓存 缓存原理
webView与js交互 webview优化
Service与Activity之间通信的几种方式
Java四种引用解析以及在Android的应用
内存监控,内存泄露问题 内存泄露检测有什么好方法,
描述常见的几种内存泄漏
App优化之提升你的App启动速度 优化启动速度
如何对 Android 应用进行性能加快应用启动速度
Touch事件分发机制
Android跨进程通讯的方式
Android 进程保活
非主线程中能不能直接new Handler()
Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
JAVA中线程同步的方法
Android 中实现多线程编程原理
EventBus原理