Android常见知识点

写在前面

跳槽无非就是钱少了或不爽了,无论怎么样,记住:
不要裸辞!
不要裸辞!
不要裸辞!
为什么呢?
1、裸辞就没有钱拿了,还不如骑驴找马。
2、裸辞之后如果一个月内没有找到工作,那么社保就会断了,除非你自己找渠道交了。
3、裸辞之后真的会很颓废!
当初还在上班的时候就想着,裸辞了,首先花几天时间吧简历完善一下,把知识点恶补一下,然后投简历,面试,妥妥的妥妥。
结果呢?每次裸辞之后都是:
首先躺尸一个星期;
然后用了一个星期才慢吞吞的改完简历;
然后海投,没回复,修改简历;
再次海投,面试,被虐得体无完肤,怀疑人生;
再改简历,再海投,一不小心中了。

当然海投也是有个目标范围的。

如果不是裸辞,那么现在应该还是在公司上班,在完成工作之余,就会逼着自己复习知识点了,起码不会在家堕落。在家不上班就是睡觉、看电影,樯橹灰飞烟灭,所以不要裸辞。

然并卵,我依然裸辞了。请假面试真的很烦。

技术题

Activity相关

Activity是一个单独的界面,从MVC的角度来说一般作为Controller,接收View反馈过来的触摸等事件,转交给Model处理,最后反馈给View渲染。

生命周期
  • 经测试,onPause方法在弹出Dialog的时候是不会被调用的,而在被一个透明的或者Dialog样式的Activity覆盖的时候才会被调用。
在onPause保存临时数据好还是在onStop好

onPause,假如从ActivityA启动B,如果B是透明的,则不会回调A的onStop方法。

如果判断Activity是否已经被销毁

方法一:

activity == null || activity.isDestroyed() || activity.isFinishing()

方法二:

if (Build.VERSION.SDK_INT >= 17) {
    return super.isDestroyed();
} else {
    return getSupportFragmentManager() != null && getSupportFragmentManager().isDestroyed();
}
Activity的四种启动模式
  • standard 默认模式,每启动一个新的Activity,都会创建一个新的实例。

  • singleTop 如果需要启动的Activity在栈顶,则直接使用,参数回调到onNewIntent方法中,不再新建实例。需要配合FLAG_ACTIVITY_CLEAR_TOP使用。

  • singleTask 如果需要启动的Activity在栈中,则直接使用,参数回到到onNewIntent方法中,并把此Activity上面的所有Activity清除,需要配合FLAG_ACTIVITY_CLEAR_TOP使用。

  • singleInstance 在新的任务栈中启动Activity,如果此Activity已经存在,则直接使用,并且此栈有且只有一个Activity。需要配合FLAG_ACTIVITY_NEW_TASK使用。

如何设置Activity的跳转动画

1、写好动画文件R.anim.enterR.anim.exit
2、调用overridePendingTransition设置动画

public static void start(Activity context) {
    Intent starter = new Intent(context, MainActivity.class);
    context.startActivity(starter);
    context.overridePendingTransition(R.anim.enter, R.anim.exit);
}
@Override
public void finish() {
    super.finish();
    overridePendingTransition(R.anim.enter, R.anim.exit);
}

引申:如Activity设置为singleInstance,则应该怎么设置跳转动画?

Service相关

Service是一个没有界面的安卓组件,一般用于后台处理耗时任务。

  • Service运行在主线程

  • Service的两种启动模式

1、startService 启动方与Service并没有关联,只有当Service调用stopSelf或者其它组件调用stopService的时候服务才会终止。

2、bindService 启动方绑定Service,并且可以通过Binder与之交互,当启动方销毁时,也会自动unbindService,当所有启动方都unbindService之后,Service也就自动销毁了。

生命周期
BroadcastReceiver相关

广播接收者,可以接收应用自身的广播,和其他应用的广播。也可以用于进程间通讯。

  • 不要在onReceive方法中执行耗时操作,也不要开子线程执行

为什么呢?官方文档是这样写的:

However, once your code returns from onReceive(), the BroadcastReceiver is no longer active. The receiver's host process becomes only as important as the other app components that are running in it. If that process hosts only a manifest-declared receiver (a common case for apps that the user has never or not recently interacted with), then upon returning from onReceive(), the system considers its process to be a low-priority process and may kill it to make resources available for other more important processes.

大概意思是onReceive()执行完毕之后,它所在的进程就会变成低优先级进程,极易被系统杀死。

分两种情况分析一下:
一、收到广播的时候,应用正在运行:
此时如果没有在Manifest中设置了独立进程,则onReceive()就直接在主进程主线程执行,这里很明显不能执行耗时操作。
二、收到广播的时候,应用没有启动:
这时候系统会启动一个进程去执行onReceive(),(如果Manifest中没有设置进程名,则进程名为包名),(插一句,所有进程都会创建一个Application实例),当onReceive执行完毕之后,此进程就变成低优先级了,随时有可能被系统杀死,如果你在onReceive里面启动了线程执行耗时任务,那很有可能子线程没执行完毕,进程就被杀死了,进程没了,线程自然就挂了。

那么确实要执行耗时操作呢,怎么办?
方法一:goAsync()

@Override
public void onReceive(final Context context, final Intent intent) {
    final PendingResult async = goAsync();
    new AsyncTask<String, Integer, String>() {
        @Override
        protected String doInBackground(String... params) {
            // 这里执行一系列耗时操作
            async.finish();
            return "";
        }
    }.execute();
}

方法二:schedule a JobService from the receiver using the JobScheduler

ContentProvider相关

主要用于应用间(进程间)数据共享的组件。

Fragment相关
生命周期
自定义View流程

绘制从根视图ViewRootperformTraversals()ViewRoot的实现类为ViewRootImplperformTraversals()内部会依次调用performMeasure()performLayout()performDraw()

三种实现方法
1、继承现有的组件,如TextView等,进行拓展。
2、继承ViewGroup,自定义布局。
3、继承View,在onDraw()中描绘。

onMeasure()

  • MeasureSpec是一个32位的整形数,高2位代表测量模式,分别为UNSPECIFIEDEXACTLYAT_MOST
  • 调用方法setMeasureDimension()设定View的宽高。

onLayout()

  • 如果继承自ViewGroup,则必须实现此方法。

onDraw()

  • 如果继承自ViewGroup,默认不会调用onDraw(),需要设置setWillNotDraw(false)

其它

  • 状态保存,onSaveInstanceStateonRestoreInstanceState
  • ActivityonSaveInstanceState方法会循环调用设置了ID的View的onSaveInstanceState
LayoutInflater.inflate中的参数attachToRoot有什么用?
public View inflate(int resource, ViewGroup root, boolean attachToRoot)

attachToRoot从字面理解就是是否绑定到root上面去了。
1、attachToRoot=true:则返回的view为root的子view;
2、attachToRoot=false:则返回的view是个单独的view,传入的root只是提供一些参数给view使用而已。

public View inflate(int resource, ViewGroup root) {
    return inflate(resource, root, root != null);
}

那么这里不传入attachToRoot呢?那就看root是否为空了,如果传入root不为空,则默认绑定到root,作为root的子view返回。

Touch事件分发
说说Android的动画机制
  • 逐帧动画(Drawable Animation)

也就是所谓的Frame动画。指通过指定每一帧的图片和播放时间,有序的进行播放而形成动画效果。
可以通过插入器Interpolator控制动画的变化速度。

  • 视图动画(View Animation)

也就是所谓补间动画。指通过指定View的初始状态、变化时间、方式,通过一系列的算法去进行图形变换,从而形成动画效果,主要有AlphaAnimationTranslateAnimationScaleAnimationRotateAnimation四种。
注意:只是在视图层实现了动画效果,并没有真正改变View的属性。

  • 属性动画(Property Animation)

属性动画,通过不断的改变View的属性,不断的重绘而形成动画效果。相比于视图动画,View的属性是真正改变了。
注意:Android 3.0(API 11)以上才支持。
最常用的类有ObjectAnimator

Dialog的cancel()和dismiss()有什么区别?
  • cancel()内部调用了dismiss()
  • cancel()会触发setOnCancelListenersetOnDismissListener的回调
  • dismiss()会触发setOnDismissListener的回调

P.S. 我不明白cancel存在的意义。
另外,DialogFragment是没有cancel的。

监听网络变化

ping

内存管理机制

内存大致分为三个区:栈区、堆区、方法区。

栈区

  • 每个线程一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用
  • 每个栈中的数据(原始类型和对象引用)都是私有的
  • 栈分为3个部分:基础类型变量区、执行环境上下文、操作指令区
  • 数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会自动消失

堆区

  • 存储的是对象,每个对象都包含一个与之对应的class
  • JVM只有一个堆区被所有线程共享,堆中不存放基本数据类型和对象的引用,只存放对象本身
  • 对象由垃圾回收器负责回收,生命周期不确定

方法区

  • 静态区,跟堆一样,被所有的线程共享
  • 方法区中包含的都是整个程序中永远唯一的元素,如class,静态变量等
大概说说垃圾回收机制

JAVA不允许手动释放内存,只能通过垃圾回收程序不定期对那些不再被引用的对象进行回收。

那么怎么判断哪些对象需要回收?

1、引用计数法
就是给对象添加一个引用计数器,引用对象时+1,引用失效时-1。但是这种方法解决不了对象相互引用的情况。

2、可达性分析法
通过一系列“GCRoots”对象作为起点进行搜索,当GCRoots和一个对象之间没有可达路径,则认为此对象不可用,但是不可用不一定会成为可回收对象。

Android中四种线程池的区别
Android中的进程优先级
  • 前台进程

  • 可见进程

  • 服务进程

  • 后台进程

  • 空进程

进程间通讯
  • 文件共享(Linux支持文件并发写,注意同步)

  • Messenger

  • AIDL

编写AIDL文件,定义接口。
编译生成JAVA文件。
定义进程级Service,onBind中返回Interface.Stub()。
onServiceConnected中Interface aidl = Interface.Stub.asInterface(service);

  • ContentProvider

  • Socket

RelativeLayout和LinearLayout有什么区别
面向对象编程的三大特性
  • 封装 把同一类事物的共性,包括属性和方法,归到同一个类中,并且隐藏起来,之对外提供特定的方法。

  • 继承 描述一类事物属于另一类事物,比如狗属于动物。在JAVA中只有单继承,没有多继承。JAVA8之后接口支持多继承了。

  • 多态 指一个行为的多种表现形态。比如人要工作,画家的工作是画画,而我们的工作是写代码。

热修复大概原理

把已修复的class文件打包成dex文件,网络传输到用户手机中,利用类加载器把这些类加载到类队列的前面即可。

HTTP协议

【未完待续】

情商题

说说你三五年的规划

如果公司录用我,不管是三年还是五年,首先我都会先把公司的任务做好,然后不断深入研究Android的相关技术,特别是Android源码,了解Android底层原理,以便更好的优化性能,避免一些不必要的奇葩问题,还有就是研究一些新的框架的原理,学习别人的思维。最后就是学习周边语言,比如后台,前端等等。

以上的所有问题的答案都是自己根据经验和百度总结出来的,尽可能的简洁,不一定正确,如有错误,望留言指出。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 127,658评论 18 546
  • pdf下载地址:Java面试宝典 第一章内容介绍 20 第二章JavaSE基础 21 一、Java面向对象 21 ...
    王震阳阅读 77,413评论 25 510
  • 文/初明 与心灵沟通,在心灵之外感应,露珠的思念寻找神话的家园。 心灵进入露珠,一南一北的温度相违,铸就一只蟋蟀叹...
    吉林省初明阅读 263评论 1 7
  • 最近喜欢思维锻炼。比如数学。 我一直想找到事物的本原,潜伏虚微之深,但难以触摸那永恒的光亮。 数形结合,转化思想。...
    荡云雪阅读 31评论 0 0
  • 大周末早上起来,就看到微博自动推送了两条消息,一是“《电影产业促进法》规定,劣迹艺人改正可复出,你们怎么看?”二是...
    百毛巾阅读 315评论 2 3