Android技术总结2
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android技术总结2相关的知识,希望对你有一定的参考价值。
android技术总结2
Java部分 Java虚拟机
jvm分区,GC(基本上后续所有地方面试都问了,基础中的基础)
虚拟机栈 线程私有 描述Java方法执行的内存模型 每个方法在执行的同时
都会创建一个栈帧 用于存储局部变量表、操作数栈、动态链接、方法出口等信息
每一个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中入栈道出栈的过程。
局部变量表存放了编译期可知的各种基本数据类型 对象引用 returnAddress类型
本地方法栈 为虚拟机使用到的Native方法服务
堆 线程共享 存放对象实例 可细分为新生代 老年代 更细致一点的有Eden空间
From Survivor空间 ToSurvivor空间
方法区 线程共享 存储已被虚拟机加载的类信息 常量 静态变量 即时编译器编译后的代码等数据 运行时常量池 存放编译期生成的各种字面量和符号引用
程序计数器 线程私有 较小内存空间 当前线程所执行的的字节码的行号指示器2、volatile和Synchronized区别3、原子性、可见性的概念4、进程与线程的区别5、线程池的概念、好处、常见的线程池举例6、Callable和Runnable的区别7、HashMap的内部原理8、ConcurrentHashMap原理
1. 九种基本数据类型的大小,以及他们的封装类
boolean 无明确指定 Boolean
char 16bits Character
byte 8bits Byte
short 16bits Short
int 32bits Integer
long 64bits Long
float 32bits Float
double 64bits Double
void Void
2. switch能否用string做参数?
参数必须是int或char那样的整数值 字符串或浮点数不可以
3. equals与==的区别。
4. Object有哪些公用方法?
equals()
getClass()
hashCode()
notify()
5. Java的四种引用,强弱软虚,用到的场景。
强引用 程序代码中普遍存在 类似Object obj = new Object() 这类引用 只要强引用还存在 垃圾回收器永远不会回收掉软引用 描述一些还有用但非必须的对象 SoftReference弱引用 描述非必须对象 强度比软引用更弱 垃圾回收器工作时 无论当前内存是否足够 都会回收掉 WeakReference虚引用 最弱的一种引用关系 设置虚引用的唯一目的就是能在这个对象被收集器回收时收到一个系统通知
6. Hashcode的作用。
Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的字段等)映射成一个数值,这个数值称作为散列值
http://www.cnblogs.com/dolphin0520/p/3681042.html
7. ArrayList、LinkedList、Vector的区别。
ArrayList 随机访问元素较快 插入和移除较慢
LinkedList 随机访问元素较慢 插入和移除较快
Vector 过时 Java1.0/1.1的容器
8. String、StringBuffer与StringBuilder的区别。
String 对象不可变
StringBuffer 线程安全
StringBuilder JavaSE5引入
9. Map、Set、List、Queue、Stack的特点与用法。
Map 一组成对的键值对对象
Set 不保存重复的元素
Queue 先进先出的容器
Stack 后进先出
10. HashMap和Hashtable的区别。
HashMap Map基于散列表的实现 取代了Hashtable 插入和查询键值对的开销是固定的
11. HashMap和ConcurrentHashMap的区别,HashMap的底层源码。
ConcurrentHashMap 一种线程安全的Map 它不涉及同步加锁
12. TreeMap、HashMap、LindedHashMap的区别。
TreeMap 基于红黑树的实现 查看键或键值对时 他们会被排序
HashMap Map基于散列表的实现
LindedHashMap 使用链表维护内部次序
13. Collection包结构,与Collections的区别。
14. try catch finally,try里有return,finally还执行么?
finally子句总是会执行
15. Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况。
16. Java面向对象的三个特征与含义。
封装
继承
多态
17. Override和Overload的含义去区别。
Override 重写就是子类重写了父类的方法
Overload 重载 同一个类中,允许存在同名函数,但它们的参数个数或者参数类型不同
18. interface与abstract类的区别。
1 接口可以多重继承,抽象类不可以
2 接口定义方法,不给实现 而抽象类可以实现部分方法
3 接口中基本数据类型的数据成员,都默认为static和final 抽象类则不是
19. static class 与non static class的区别。
20. java多态的实现原理。
21. 实现多线程的两种方法:Thread与Runable。
22. 线程同步的方法:sychronized、lock、reentrantLock等。
23. 锁的等级:方法锁、对象锁、类锁。
24. 写出生产者消费者模式。
25. ThreadLocal的设计理念与作用。 线程本地变量 为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量
26. ThreadPool用法与优势。
27. Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。
28. wait()和sleep()的区别。
29. foreach与正常for循环效率对比。
30. Java IO与NIO。
31. 反射的作用于原理。
32. 泛型常用特点,List<String>能否转为List<Object>。
33. 解析XML的几种方式的原理与特点:DOM、SAX、PULL。
34. Java与C++对比。
35. Java1.7与1.8新特性。
36. 设计模式:单例、工厂、适配器、责任链、观察者等等。
37. JNI的使用。
Java里有很多很杂的东西,有时候需要你阅读源码,大多数可能书里面讲的不是太清楚,需要你在网上寻找答案。
推荐书籍:《java核心技术卷I》《Thinking in java》《java并发编程》《effictive java》《大话设计模式》
JVM
1. 内存模型以及分区,需要详细到每个区放什么。
//运行时数据区域
方法区 Method Area
各个线程共享的内存区域
存储已被虚拟机加载的类信息 常量 静态变量 即时编译器编译后的代码
虚拟机栈 VM Stack
线程私有 Java方法执行的内存模型 每个方法执行的同时会创建一个栈帧 用于存储局部变量表 操作数栈 动态链接 方法出口等信息
每一个方法从调用到执行完成的过程 对应一个栈帧在虚拟机栈中入栈到出栈的过程 局部变量表存放了编译器可知的各种基本数据类型(boolean byte char short int float long double)
对象引用 returnAddress类型
本地方法栈 Native Method Stack
为虚拟机使用的native方法服务
堆 Heap
Java虚拟机所管理内存最大的一块
所有线程共享的一块内存区域 虚拟机启动时创建 存
放所有对象实例及数组 垃圾收集器管理的主要区域 也被称为GC堆
程序计算器 Program Counter Register
当前线程所执行的字节码的行号指示器 线程私有内存
///
运行时产量池
方法区的一部分 用于存放编译期生成的各种字面量和符号引用
直接内存
不是虚拟机运行时数据区的一部分 NIO
2. 堆里面的分区:Eden,survival from to,老年代,各自的特点。
3. 对象创建方法,对象的内存分配,对象的访问定位。
4. GC的两种判定方法:引用计数与引用链。
引用计数算法
给对象添加一个引用计数器 每当有一个地方引用到它时 计数器就加1 引用失效时 计数器就减1 任何时刻计数器为0的对象不可能再被使用
但是很难解决对象之间的相互循环引用的问题
可达性分析算法
通过一系列的GC Roots的对象作为起始点 从这些节点开始向下搜索 所走过的路径称为引用链
当一个对象到GC Roots没有任何引用链相连 则证明此对象不可用
5. GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方,如果让你优化收集方法,有什么思路?
标记清除算法
首先标记处所有需要回收的对象 在标记完成后统一回收
两点不足 一是标记和清除两个过程的效率都不高 二是标记清除后会产生大量不连续的内存碎片
复制算法
将可用内存按容量划分为大小相等的两块 每次只使用其中的一块 当这一块的内存用完了 将还存活着的对象复制到另外一块上面 然后把已经使用内存空间一次清理掉
好处是不用考虑内存碎片 代价是内存缩小为原来的一半
标记整理算法
适合老年代 首先标记处所有需要回收的对象 让所有存活对象都向一端移动 然后直接清理掉端边界以外的内存
分代收集算法
6. GC收集器有哪些?CMS收集器与G1收集器的特点。
Serial收集器
ParNew收集器
Parallel Scavenge收集器
Serial Old收集器
Parallel Old收集器
CMS收集器
一种以获取最短回收停顿时间为目标的收集器 基于标记清除算法实现
优点 并发收集 低停顿 缺点 对CPU资源非常敏感 无法处理浮动垃圾 大量空间碎片产生
G1收集器
面向服务端应用的垃圾收集器 特点 并行和并发 分代收集 空间整合 可预测的停顿
7. Minor GC与Full GC分别在什么时候发生?
8. 几种常用的内存调试工具:jmap、jstack、jconsole。
jmap
内存映像工具
jstack
堆栈跟踪工具
jconsole
监视与管理控制台
9. 类加载的五个过程:加载、验证、准备、解析、初始化。
加载 1 通过一个类的全限定名来获取定义此类的二进制字节流 2 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构 3 在内存中生成一个代表这个类的java.lang.Class对象 作为方法区这个类的各种数据的访问入口验证 确保Class文件的字节流包含的信息符合当前虚拟机的要求 文件格式验证 元数据验证 字节码验证 符合引用验证准备 正式为类变量分配内存并设置类变量初始值得阶段解析 将常量池内的符号引用替换为直接引用 类或接口解析 字段解析 类方法解析 接口方法解析初始化
10. 双亲委派模型:Bootstrap ClassLoader、Extension ClassLoader、ApplicationClassLoader。
Bootstrap ClassLoader 启动类加载器 将JAVA_HOME/lib中类库加载到虚拟机内存中Extension ClassLoader 扩展类加载器 将JAVA_HOME/lib/ext中类库加载ApplicationClassLoader 加载用户路径上指定类库
11. 分派:静态分派与动态分派。
JVM过去过来就问了这么些问题,没怎么变,内存模型和GC算法这块问得比较多,可以在网上多找几篇博客来看看。
推荐书籍:《深入理解java虚拟机》
Android部分 Android Framework
Android的存储方式2、Handler、Lopper、MessageQueue3、AsyncTask 为什么java已经有线程池的实现了,还要继续使用AsyncTask,AsyncTask相对于java自带的线程池的好处4、onTouch事件的处理机制5、说一下MVC以及其在Android中的应用6、说一下OOM以及你怎么解决的7、了解Android的Framework么8、说一下一个Android APP从点击打开开始,是怎样展示在用户面前的(Zygote、Ams、Wms等)
1、viewpager里面只能嵌套view吗 可不可以嵌套Activity
2、假如viewpager里面的每一页都有有很大数据量的内容,那么在快速的左右滑动时,如果出现了内存被回收的情况,如何处理 假如出现了OOM,怎么处理
3、同上情况,使用Fragment,又当如何?与viewpager有什么区别
4、ExpandableListView的Adapter怎么写
5、在ListView的每个item中如果可能出现的view都不一样,如何处理?动态获取view种类数量的话是不是就不能使用viewHolder进行优化?固定显示view如果不存在该种view就不显示的方法是否太耗内存
6、ListView的Adapter的getView具体是什么机制?
7、Activity之间传递大量的数据用什么方法
Binder
Bundle不够大
Socket 在同一应用中没必要使用
共享内存
static变量——同一应用中static变量如何控制,会不会并发出问题,如果Activity由于内存不足被 kill掉,再重启的时候static变量的值还可靠吗:设置专门的访问类,进行读写控制,以及Activity重启后的初始化工作。
8、SQLite在使用时 假如ActivityA是用于修改SQLite,ActivityBCDEF。。。是用来展示SQLite的内容,如何在修改SQLite的同时使得 BCDEF...都立刻获得最新的数据?SQLite有没有类似于ContentObserver的这么一种监视类可以监听到SQLite内容的改变?如 果广播通知所有类,那么广播可以携带多大的数据?
9、假设把一个ActivityB向右滑动可以回到上一个ActivityA,B渐渐透明,A渐渐清晰,要怎么编写页面?说说你对android:theme的理解,说说你对alpha值的理解
10、ListView在数据量很大图片很多的情况下怎么优化?假如一个图片,轻轻的向上滑动一丢丢,那么需要重绘吗?(什么鬼。。。)
11、详细展开说一下所有LaunchMode的应用场景
假如A-》B-》C,想让C后退直接到A,使用什么样的intentflag?
假如A-》B-》C,C使用singleTask,C后退,后退到什么地方呢?
12、在全屏显示高清大图的时候,网速慢的情况下如何显示?渐进式显示是怎么做到的?如果想显示下载进度圈圈,该如何实现?
13、AsyncTask在4.x以后有什么改变?怎样改回并发执行好多个?如果一个AsyncTask结束取得结果之前 Activity就因为内存原因被Destroy掉了,那会有什么情况发生?会内存泄露吗?会空指针吗?需要在Activity彻底死掉之前把 AsyncTaskcancel掉吗?如果没有cancel掉,然后Activity重启了,那这个Asynctask又当如何呢?
14、AsyncTask内部实现机理 与Thread+Handler有什么不同
15、说一下HandlerThread
16、你的APP里,是每个Activity都有一个Handler呢还是所有Activity共享一个Handler
17、基于事件监听、基于事件回调 假如一个touch事件发生,那是监听器先收到还是onTouch函数先收到
18、假如你要记录ListView滚动到的位置,要记录什么信息,view怎样获得坐标信息
19、说一下canvas
20、dialog和popupwindow的应用场景 如果popupwindow在没有dismiss的时候Activity finish了,会出现什么情况?
21、了解过什么三方库?为什么不用三方库?
22、你觉得安卓的未来在哪里?你自己为什么都用ios了(╯‵□′)╯︵┻━┻
23、Service和推送通知,通知有没有可能出现有推送但是通知栏收不到通知?service被kill掉会如何?如何保证service不被kill掉
24、了不了解Scrollview scrollview和ListView有什么相似点 有什么不同 那如果这两个是继承关系 那应该是谁继承谁?
25、dp sp px各自的应用场景是什么 换算关系是什么 使用sp的时候如果调整系统字体,显示字体会跟着调整吗?
26、gallery为什么被废弃?为什么Google推荐使用viewpager代替gallery呢?有什么改进?
27、handler.postAtTime不是延时post么 那handler怎么延时处理Message
Android
1. Activity与Fragment的生命周期。
Activity生命周期
打开应用 onCreate()->onStart()->onResume
按BACK键 onPause()->onStop()->onDestory()
按HOME键 onPause()->onStop()
再次启动 onRestart()->onStart()->onResume()
Fragment的生命周期
切换到该Fragment onAttach() onCreate() onCreateView() onActivityCreated() onStart() onResume()
屏幕灭掉 onPause() onSaveInstanceState() onStop()
屏幕解锁 onStart() onResume()
切换到其他Fragment onPause() onStop() onDestroyView()
切换回本身的Fragment onCreateView() onActivityCreated() onStart() onResume()
回到桌面 onPause() onSaveInstanceState() onStop()
回到应用 onStart() onResume()
退出应用 onPause() onStop() onDestroyView() onDestroy() onDetach()
2. Acitivty的四种启动模式与特点。
当应用运行起来后就会开启一条线程,线程中会运行一个任务栈,当Activity实例创建后就会放入任务栈中 Activity启动模式的设置在AndroidManifest.xml文件中,通过配置Activity的属性android:launchMode=""设置
Standard模式(默认) 只要你创建了Activity实例,一旦激活该Activity,则会向任务栈中加入新创建的实例,退出Activity则会在任务栈中销毁该实例
SingleTop模式 考虑当前要激活的Activity实例在任务栈中是否正处于栈顶,如果处于栈顶则无需重新创建新的实例,会重用已存在的实例,否则会在任务栈中创建新的实例
SingleTask模式 如果任务栈中存在该模式的Activity实例,则把栈中该实例以上的Activity实例全部移除,调用该实例的newInstance()方法重用该Activity,使该实例处於栈顶位置,否则就重新创建一个新的Activity实例
SingleInstance模式 当该模式Activity实例在任务栈中创建后,只要该实例还在任务栈中,即只要激活的是该类型的Activity,都会通过调用实例的newInstance()方法重用该Activity,
此时使用的都是同一个Activity实例,它都会处于任务栈的栈顶。 此模式一般用于加载较慢的,比较耗性能且不需要每次都重新创建的Activity
3. Activity缓存方法。
onSaveInstanceState() 和 onRestoreInstanceState()不属于Activity的生命周期,只有意外销毁一个Activity时才被调用,
如内存不足,按下了HOME键(注:按下BACK键则是主动销毁一个Activity,这两个方法不会被调用)。当需要改变屏幕方向时,也可以用这两个方法来暂存一些数据。
下面百度地图应用中的例子,就用到了这两种方法,用来保存和恢复地图的视图。
@Override
protected void onSaveInstanceState(Bundle outState) {
cPoint = mapView.getMapCenter(); //得到当前MapView的中心点。
outState.putInt("lat", cPoint.getLatitudeE6()); //暂存在outState中
outState.putInt("lon", cPoint.getLongitudeE6());
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
int lat = savedInstanceState.getInt("lat"); //从保存的数据中恢复
int lon = savedInstanceState.getInt("lon");
cPoint = new GeoPoint(lat, lon);
super.onRestoreInstanceState(savedInstanceState);
}
4. Service的生命周期,两种启动方法,有什么区别。
startService 访问者退出 Service仍然允许 onCreate onStartCommand onDestroy
bindService 访问者退出 Service终止onCreate onBind onUnbind onDestroy
5. 怎么保证service不被杀死。
1 onStartCommand方法,返回START_STICKY
2 提升service优先级 android:priority = "1000"
3 提升service进程优先级
4 onDestroy方法里重启service
6. 广播的两种注册方法,有什么区别。
1.在AndroidManifest.xml文件中注册。
好处:一旦应用程序被安装到手机里,BroadCast Receiver就开始生效。 无论应用程序进程是否运行,运用程序是否在开启状态下都可以接受到广播事件
<receiver android:name=".receiver.SMSReceiver" >
<intent-filter android:priority="1000" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter> </receiver>
2.通过代码的方式注册广播 好处:一旦运用程序停止,广播也跟着停止
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
filter.setPriority(1000);
LockScreenReceiver myReceiver = new LockScreenReceiver();
registerReceiver(myReceiver, filter);
7. Intent的使用方法,可以传递哪些数据类型。
putExtra()
基本数据类型 boolean byte char short int long float double
String CharSequence Parcelable Serializable Bundle 数组 集合
8. ContentProvider使用方法。
增删改查
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://media/internal/images");
//添加一条记录
ContentValues values = new ContentValues();
values.put("name", "linjiqin");
values.put("age", 25);
resolver.insert(uri, values);
//获取person表中所有记录
Cursor cursor = resolver.query(uri, null, null, null, null);
while(cursor.moveToNext()){
}
//把id为1的记录的name字段值更改新为zhangsan
ContentValues updateValues = new ContentValues();
updateValues.put("name", "zhangsan");
Uri updateIdUri = ContentUris.withAppendedId(uri, 2);
resolver.update(updateIdUri, updateValues, null, null);
//删除id为2的记录
Uri deleteIdUri = ContentUris.withAppendedId(uri, 2);
resolver.delete(deleteIdUri, null, null);
9. Thread、AsycTask、IntentService的使用场景与特点。
Thread
方式1
class MyThread extends Thread {
@Override
public void run() {
// 处理具体的逻辑
}
}
new MyThread().start();
方式2
class MyThread implements Runnable {
@Override
public void run() {
// 处理具体的逻辑
}
}
MyThread myThread = new MyThread();
new Thread(myThread).start();
Handler+Thread更新
public class MainActivity extends Activity implements OnClickListener {
public static final int UPDATE_TEXT = 1;
private TextView text;
private Button changeText;
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_TEXT:
// 在这里可以进行UI操作
text.setText("Nice to meet you");
break;
default:
break;
}
}
};
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.change_text:
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = UPDATE_TEXT;
handler.sendMessage(message); // 将Message对象发送出去
}
}).start();
break;
default:
break;
}
}
}
Message 是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据 Message 的what 字段,除此之外还可以使用arg1 和arg2 字段来携带一些整型数据, 使用obj 字段携带一个Object 对象Handler 处理者 主要是用于发送和处理消息的 发送消息一般是使用Handler 的sendMessage()方法, 而发出的消息经过一系列地辗转处理后,最终会传递到Handler 的handleMessage()方法中MessageQueue 消息队列 存放所有通过Handler 发送的消息。这部分消息会一直存在于消息队列中,等待被处理。 每个线程中只会有一个MessageQueue对象Looper 每个线程中的MessageQueue 的管家,调用Looper 的loop()方法后,就会 进入到一个无限循环当中,然后每当发现MessageQueue 中存在一条消息,就会将它取 出,并传递到Handler 的handleMessage()方法中。每个线程中也只会有一个Looper 对象
AsyncTask 从子线程切换到主线程 基于异步消息处理机制的封装
AsyncTask 是一个抽象类,所以如果我们想使用它,就必须要创建一个子类去继承它。 在继承时我们可以为AsyncTask 类指定三个泛型参数,这三个参数的用途如下Params 在执行AsyncTask 时需要传入的参数,可用于在后台任务中使用Progress 后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位Result 当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型
需要去重写的方法有以下四个onPreExecute() 后台任务开始执行之前调用,用于进行一些界面上的初始化操作doInBackground(Params...) 这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务 不可以进行UI 操作onProgressUpdate(Progress...) 后台任务中调用了publishProgress(Progress...)方法后,这个方法就会很快被调用 可以对UI 进行操作onPostExecute(Result) 当后台任务执行完毕并通过return 语句进行返回时,这个方法就很快会被调用
class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
@Override
protected void onPreExecute() {
progressDialog.show(); // 显示进度对话框
}
@Override
protected Boolean doInBackground(Void... params) {
try {
while (true) {
int downloadPercent = doDownload(); // 这是一个虚构的方法
publishProgress(downloadPercent);
if (downloadPercent >= 100) {
break;
}
}
} catch (Exception e) {
return false;
}
return true;
}
@Override
protected void onProgressUpdate(Integer... values) {
// 在这里更新下载进度
progressDialog.setMessage("Downloaded " + values[0] + "%");
}
@Override
protected void onPostExecute(Boolean result) {
progressDialog.dismiss(); // 关闭进度对话框
// 在这里提示下载结果
if (result) {
Toast.makeText(context, "Download succeeded",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, " Download failed",
Toast.LENGTH_SHORT).show();
}
}
}
new DownloadTask().execute();
10. 五种布局: FrameLayout 、 LinearLayout 、 AbsoluteLayout 、 RelativeLayout 、 TableLayout 各自特点及绘制效率对比。
11. Android的数据存储形式。
SharedPreference文件SQLiteContentProvider
12. Sqlite的基本操作。
13. Android中的MVC模式。
MVC是三个单词的缩写,分别为: 模型(Model),视图(View)和控制Controller Model层实现系统中的业务逻辑。 View层用于与用户的交互。 Controller层是Model与View之间沟通的桥梁, 它可以分派用户的请求并选择恰当的视图以用于显示,同时它也可以解释用户的输入并将它们映射为模型层可执行的操作GridView显示 GridView就是MVC中的View负责显示 获取设备上安装的应用信息所有对应的方法,这就是对应的Model BaseAdapter,是Model和View中的桥梁,就是 Controller
14. Merge、ViewStub的作用。
<include />标签能够重用布局文件<merge /> 删减多余的层级<ViewStub /> 当你需要时才会加载 加载布局时 ((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE); 或者 View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
15. Json有什么优劣势。
JSON的优点: A.数据格式比较简单,易于读写,格式都是压缩的,占用带宽小; B.易于解析,客户端javascript可以简单的通过eval()进行JSON数据的读取; C.支持多种语言,包括ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, php, Python, Ruby等服务器端语言,便于服务器端的解析; D.在PHP世界,已经有PHP-JSON和JSON-PHP出现了,偏于PHP序列化后的程序直接调用,PHP服务器端的对象、数组等能直接生成JSON格式,便于客户端的访问提取; E.因为JSON格式能直接为服务器端代码使用,大大简化了服务器端和客户端的代码开发量,且完成任务不变,并且易于维护。JSON的缺点 A.没有XML格式这么推广的深入人心和喜用广泛,没有XML那么通用性; B.JSON格式目前在Web Service中推广还属于初级阶段。 C 可读性不太好
16. 动画有哪两类,各有什么特点?
一类是Tween动画,就是对场景里的对象不断的进行图像变化来产生动画效果(旋转、平移、放缩和渐变)alpha 渐变scale 大小translate 移动rotate 旋转
二类就是Frame动画,即顺序的播放事先做好的图像,与gif图片原理类似http://www.cnblogs.com/bastard/archive/2012/06/29/2570405.html
17. Handler、Loop消息队列模型,各部分的作用。
http://www.cnblogs.com/bastard/archive/2012/06/08/2541944.html
18. 怎样退出终止App。
public void exit(){
for (Activity activity : activities) {
if (activity!=null) {
activity.finish();
}
}
System.exit(0);
}
19. Asset目录与res目录的区别。
1 assets目录下的资源文件不会在R.java自动生成ID 所以读取assets目录下的文件必须指定文件的路径
2 assets目录能获取子目录下的资源
Bitmap bgImg = getImageFromAssetFile( "background.png" );
/**
* 从assets中读取图片
*/
private Bitmap getImageFromAssetsFile(String fileName)
{
Bitmap image = null;
AssetManager am = getResources().getAssets();
try
{
InputStream is = am.open(fileName);
image = BitmapFactory.decodeStream(is);
is.close();
}
catch (IOException e)
{
e.printStackTrace();
}
return image;
}
20. Android怎么加速启动Activity。
硬件加速android:hardwareAccelerated="true"
21. Android内存优化方法:ListView优化,及时关闭资源,图片缓存等等。
22. Android中弱引用与软引用的应用场景。
软引用 描述一些还有用但非必须的对象 SoftReference
弱引用 描述非必须对象 强度比软引用更弱 垃圾回收器工作时 无论当前内存是否足够 都会回收掉 WeakReference
23. Bitmap的四中属性,与每种属性队形的大小。
图片压缩质量参数枚举变量public static final Bitmap.Config ALPHA_8public static final Bitmap.Config ARGB_4444public static final Bitmap.Config ARGB_8888public static final Bitmap.Config RGB_565
ARGB指的是一种色彩模式,里面A代表Alpha,R表示red,G表示green,B表示blue,其实所有的可见色都是红绿蓝组成的,所以红绿蓝又称为三原色,每个原色都存储着所表示颜色的信息值
所以就ALPHA_8就是Alpha由8位组成ARGB_4444就是由4个4位组成即16位,ARGB_8888就是由4个8位组成即32位,RGB_565就是R为5位,G为6位,B为5位共16位
由此可见:ALPHA_8 代表8位Alpha位图ARGB_4444 代表16位ARGB位图ARGB_8888 代表32位ARGB位图RGB_565 代表8位RGB位图
24. View与View Group分类。自定义View过程:onMeasure()、onLayout()、onDraw()。
25. Touch事件分发机制。
http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html
事件分发 dispatchTouchEvent Touch 事件发生时 Activity 的 dispatchTouchEvent(MotionEvent ev) 方法会以隧道方式 (从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递) 将事件传递给最外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法, 并由该 View 的 dispatchTouchEvent(MotionEvent ev) 方法对事件进行分发。dispatchTouchEvent 的事件分发逻辑如下: 如果 return true,事件会分发给当前 View 并由 dispatchTouchEvent 方法进行消费,同时事件会停止向下传递; 如果 return false,事件分发分为两种情况:
如果当前 View 获取的事件直接来自 Activity,则会将事件返回给 Activity 的 onTouchEvent 进行消费; 如果当前 View 获取的事件来自外层父控件,则会将事件返回给父 View 的 onTouchEvent 进行消费。 如果返回系统默认的 super.dispatchTouchEvent(ev),事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。
事件拦截 onInterceptTouchEvent 在外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系统默认的 super.dispatchTouchEvent(ev) 情况下, 事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent 的事件拦截逻辑如下: 如果 onInterceptTouchEvent 返回 true,则表示将事件进行拦截,并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理; 如果 onInterceptTouchEvent 返回 false,则表示将事件放行,当前 View 上的事件会被传递到子 View 上, 再由子 View 的 dispatchTouchEvent 来开始这个事件的分发; 如果 onInterceptTouchEvent 返回 super.onInterceptTouchEvent(ev),事件默认会被拦截, 并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理。
事件响应 onTouchEvent 在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true 或返回 super.onInterceptTouchEvent(ev) 的情况下 onTouchEvent 会被调用。onTouchEvent 的事件响应逻辑如下: 如果事件传递到当前 View 的 onTouchEvent 方法,而该方法返回了 false,那么这个事件会从当前 View 向上传递, 并且都是由上层 View 的 onTouchEvent 来接收,如果传递到上面的 onTouchEvent 也返回 false,这个事件就会“消失”,而且接收不到下一次事件。 如果返回了 true 则会接收并消费该事件。 如果返回 super.onTouchEvent(ev) 默认处理事件的逻辑和返回 false 时相同。
26. Android长连接,怎么处理心跳机制。
27. Zygote的启动过程。
28. Android IPC:Binder原理。
29. 你用过什么框架,是否看过源码,是否知道底层原理。
30. Android5.0、6.0新特性。
Android的话,多是一些项目中的实践,使用多了,自然就知道了,还有就是多逛逛一些名人的博客,书上能讲到的东西不多。另外android底层的东西,有时间的话可以多了解一下,加分项。
Android的话,多是一些项目中的实践,使用多了,自然就知道了,还有就是多逛逛一些名人的博客,书上能讲到的东西不多。另外android底层的东西,有时间的话可以多了解一下,加分项。
推荐书籍:《疯狂android讲义》《深入理解android》
网络部分
TCP UDP HTTP
TCP、UDP的区别2、TCP的三次握手、四次挥手3、HTTP的特点4、HTTP与HTTPS的区别
1. OSI与TCP/IP各层的结构与功能,都有哪些协议。
2. TCP与UDP的区别。
3. TCP报文结构。
4. TCP的三次握手与四次挥手过程,各个状态名称与含义,TIMEWAIT的作用。
5. TCP拥塞控制。
6. TCP滑动窗口与回退N针协议。
7. Http的报文结构。
8. Http的状态码含义。
9. Http request的几种类型。
10. Http1.1和Http1.0的区别
11. Http怎么处理长连接。
12. Cookie与Session的作用于原理。
13. 电脑上访问一个网页,整个过程是怎么样的:DNS、HTTP、TCP、OSPF、IP、ARP。
14. Ping的整个过程。ICMP报文是什么。
15. C/S模式下使用socket通信,几个关键函数。
16. IP地址分类。
17. 路由器与交换机区别。
网络其实大体分为两块,一个TCP协议,一个HTTP协议,只要把这两块以及相关协议搞清楚,一般问题不大。
推荐书籍:《TCP/IP协议族》
操作系统
1. 进程和线程的区别。
2. 死锁的必要条件,怎么处理死锁。
3. Window内存管理方式:段存储,页存储,段页存储。
4. 进程的几种状态。
5. IPC几种通信方式。
6. 什么是虚拟内存。
7. 虚拟地址、逻辑地址、线性地址、物理地址的区别。
因为是做android的这一块问得比较少一点,还有可能上我简历上没有写操作系统的原因。
推荐书籍:《深入理解现代操作系统》
算法
1. 链表与数组。
2. 队列和栈,出栈与入栈。
3. 链表的删除、插入、反向。
4. 字符串操作。
5. Hash表的hash函数,冲突解决方法有哪些。
6. 各种排序:冒泡、选择、插入、希尔、归并、快排、堆排、桶排、基数的原理、平均时间复杂度、最坏时间复杂度、空间复杂度、是否稳定。
7. 快排的partition函数与归并的Merge函数。
8. 对冒泡与快排的改进。
9. 二分查找,与变种二分查找。
10. 二叉树、B+树、AVL树、红黑树、哈夫曼树。
11. 二叉树的前中后续遍历:递归与非递归写法,层序遍历算法。
12. 图的BFS与DFS算法,最小生成树prim算法与最短路径Dijkstra算法。
13. KMP算法。
14. 排列组合问题。
15. 动态规划、贪心算法、分治算法。(一般不会问到)
16. 大数据处理:类似10亿条数据找出最大的1000个数.........等等
算法的话其实是个重点,因为最后都是要你写代码,所以算法还是需要花不少时间准备,这里有太多算法题,写不全,我的建议是没事多在OJ上刷刷题(牛客网、leetcode等),剑指offer上的算法要能理解并自己写出来,编程之美也推荐看一看。
推荐书籍:《大话数据结构》《剑指offer》《编程之美》
public class MyClass {
public static void main(String[] args){
System.out.println("hello");
int[] a = {62,14,59,88,16,33,24,97};
System.out.print("before");
printArray(a);
radixSort(a);
System.out.print("after");
printArray(a);
}
//插入排序
public static void insertSort(int[] a) {
//将a[]按升序排列
int N = a.length; //数组长度
for (int i = 1; i < N; i++) {
//将a[i]插入到a[i-1] a[i-2] a[i-3]...之中
for (int j = i; (j>0)&&(a[j]<a[j-1]); j--) {
//a[j]与a[j-1]交换
exch(a, j, j-1);
}
System.out.print("-----"+i+"-----");
printArray(a);
}
}
//二分法插入排序
public static void binaryInsertSort(int[] array) {
for (int i = 1; i < array.length; i++) {
int temp = array[i];
int right = i - 1;
int left = 0;
int mid;
// 定位
while (left <= right) {
mid = (left + right) / 2;
if (array[mid] > temp) {
right = mid - 1;
} else if (array[mid] < temp) {
left = mid + 1;
}
}
// 移动数组
for (int j = i; j > left; j--) {
array[j] = array[j - 1];
}
// 在找到的位置插入
array[left] = temp;
System.out.print("-----"+i+"-----");
printArray(array);
}
}
//希尔排序
public static void shellSort(int[] a){
//将a[]按升序排列
int N = a.length; //数组长度
int h = 1;
while (h < N/3){
h = 3*h + 1; //1,4,13,40,
}
while(h >= 1){
//将数组变为h有序
for (int i = h; i <N; i++) {
//将a[i]插入到a[i-h],a[i-2*h],a[i-3*h]...之中
for (int j=i; (j>=h)&&(a[j]<a[j-h]); j-=h) {
//a[j]与a[j-h]交换
exch(a, j, j-h);
}
System.out.print("-----"+i+"-----");
printArray(a);
}
h = h/3;
System.out.print("-----"+h+"-----");
printArray(a);
}
}
//选择排序
public static void selectSort(int[] a) {
//将a[]按升序排列
int N = a.length; //数组长度
for (int i = 0; i < N; i++) {
//将a[i]与a[i+1..N]中最小的元素交换
//找出最小元素索引
int min = i;
for (int j = i+1; j < N; j++) {
if (a[j] < a[min]){
min = j;
}
}
//a[i]与a[min]交换
exch(a, i, min);
System.out.print("-----"+i+"-----");
printArray(a);
}
}
//堆排序
public static void heapSort(int[] a){
int N = a.length; //数组长度
for(int i=0;i<N-1;i++){
//建堆
buildMaxHeap(a,N-1-i);
//交换堆顶和最后一个元素
exch(a,0,N-1-i);
System.out.print("-----"+i+"-----");
printArray(a);
}
}
//对data数组从0到lastIndex建大顶堆
public static void buildMaxHeap(int[] data, int lastIndex){
//从lastIndex处节点(最后一个节点)的父节点开始
for(int i=(lastIndex-1)/2;i>=0;i--){
//k保存正在判断的节点
int k=i;
//如果当前k节点的子节点存在
while(k*2+1<=lastIndex){
//k节点的左子节点的索引
int biggerIndex=2*k+1;
//如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在
if(biggerIndex<lastIndex){
//若果右子节点的值较大
if(data[biggerIndex]<data[biggerIndex+1]){
//biggerIndex总是记录较大子节点的索引
biggerIndex++;
}
}
//如果k节点的值小于其较大的子节点的值
if(data[k]<data[biggerIndex]){
//交换他们
exch(data,k,biggerIndex);
//将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值
k=biggerIndex;
}else{
break;
}
}
}
}
//冒泡排序
public static void bubbleSort(int[] a){
//将a[]按升序排列
int N = a.length; //数组长度
for (int i = 0; i < N - 1; i++) {
for (int j = i + 1; j < N; j++) {
if (a[i] > a[j]){
//前面比后面数大则交换
exch(a, i, j);
}
}
}
}
//快速排序
public static void quickSort(int[] a, int low, int high) {
if(low < high) {
int middle = getMiddle(a,low,high); //将numbers数组进行一分为二
System.out.print("-----"+middle+"-----");
printArray(a);
quickSort(a, low, middle-1); //对低字段表进行递归排序
quickSort(a, middle+1, high); //对高字段表进行递归排序
}
}
/**
* 查找出中轴(默认是最低位low)的在numbers数组排序后所在位置
*
* @param numbers 带查找数组
* @param low 开始位置
* @param high 结束位置
* @return 中轴所在位置
*/
public static int getMiddle(int[] numbers, int low, int high) {
int temp = numbers[low]; //数组的第一个作为中轴
while (low < high) {
while (low < high && numbers[high] > temp) {
high--;
}
numbers[low] = numbers[high];//比中轴小的记录移到低端
while (low < high && numbers[low] < temp) {
low++;
}
numbers[high] = numbers[low]; //比中轴大的记录移到高端
}
numbers[low] = temp; //中轴记录到尾
return low; // 返回中轴的位置
}
//归并排序
public static void mergeSort(int[] a, int low, int high){
int mid = (low + high) / 2;
if (low < high) {
// 左边
mergeSort(a, low, mid);
// 右边
mergeSort(a, mid + 1, high);
// 左右归并
merge(a, low, mid, high);
}
}
/**
* 将数组中low到high位置的数进行排序
* @param nums 待排序数组
* @param low 待排的开始位置
* @param mid 待排中间位置
* @param high 待排结束位置
*/
public static void merge(int[] nums, int low, int mid, int high) {
int[] temp = new int[high - low + 1];
int i = low;// 左指针
int j = mid + 1;// 右指针
int k = 0;
// 把较小的数先移到新数组中
while (i <= mid && j <= high) {
if (nums[i] < nums[j]) {
temp[k++] = nums[i++];
} else {
temp[k++] = nums[j++];
}
}
// 把左边剩余的数移入数组
while (i <= mid) {
temp[k++] = nums[i++];
}
// 把右边边剩余的数移入数组
while (j <= high) {
temp[k++] = nums[j++];
}
// 把新数组中的数覆盖nums数组
for (int k2 = 0; k2 < temp.length; k2++) {
nums[k2 + low] = temp[k2];
}
}
//基数排序
public static void radixSort(int[] a) {
int BASE = 10; // 整数基数
int len = a.length;
int[] buffer = new int[len];
int maxValue = a[0], exp = 1;
// 找出a数组中最大的数
for (int i = 1; i < len; i++) {
if (a[i] > maxValue) {
maxValue = a[i];
}
}
while (maxValue / exp > 0) {
int[] bucket = new int[BASE];
//{0 0 0 0 0 0 0 0 0 0}
for (int i = 0; i < bucket.length; i++) {
bucket[i] = 0;
}
printArray(bucket);
//从数的低位开始进行桶排序 {0 0 1 1 2 0 1 1 1 1}
for (int i = 0; i < len; i++) {
bucket[(a[i] / exp) % BASE]++;
}
printArray(bucket);
// 按照当前位给a排序,确定各个数对应的大概位置buket[(a[i] / exp) % BASE]的值
// 即为新位置的下标
for (int i = 1; i < BASE; i++) {
bucket[i] += bucket[i - 1];
}
// 按当前位进行排序存入到新数组
for (int i = len - 1; i >= 0; i--) {
int index = (a[i] / exp) % BASE;
buffer[--bucket[(a[i] / exp) % BASE]] = a[i];
}
for (int i = 0; i < len; i++) {
a[i] = buffer[i];
}
exp *= BASE;
}
}
//桶排序 适用于固定范围大小内数据的排序
public static void bucketSort(int[] a, int BUCKETSIZE) {
int bucket[] = new int[BUCKETSIZE]; //长度120位的数组
printArray(bucket);
//对应的位有值时加1
for (int i = 0; i < a.length; ++i) {
if (i <= BUCKETSIZE && i >= 0) {
bucket[a[i]]++;
}
}
printArray(bucket);
//把相关的值重新赋值回数组 [0..14..16..]
int index = 0;
for (int i = 0; i < bucket.length; i++) {
while (bucket[i] > 0) {
a[index++] = i;
bucket[i]--;
}
}
}
//交换两个数组元素
public static void exch(int[] a, int i, int j){
int t = a[i];
a[i] = a[j];
a[j] = t;
}
//打印数组元素
public static void printArray(int[] a){
for (int i = 0; i < a.length; i++) {
System.out.print(" "+a[i]);
}
System.out.print("\\n");
}
//不使用中间变量交换两个数组元素
public static void exchNotemp(int[] a, int i, int j){
a[i] = a[i] + a[j];
a[j] = a[i] - a[j];
a[i] = a[i] - a[j];
}
}
著名开源库
OpenCV FFmpeg JavaCV
以上是关于Android技术总结2的主要内容,如果未能解决你的问题,请参考以下文章