1 . Activity 系列问题
1.1 绘制Activity生命周期流程图
1.2 介绍下不同场景下Activity生命周期的变化过程
• 启动Activity: onCreate()—>onStart()—>onResume(),Activity进入运行状态。
• Activity退居后台: 当前Activity转到新的Activity界面或按Home键回到主屏: onPause()—>onStop(),进入停滞状态。
• Activity返回前台: onRestart()—>onStart()—>onResume(),再次回到运行状态。
• Activity退居后台,且系统内存不足, 系统会杀死这个后台状态的Activity,若再次回到这个Activity,则会走onCreate()–>onStart()—>onResume()
• 锁定屏与解锁屏幕 只会调用onPause(),而不会调用onStop方法,开屏后则调用onResume()
1.3 内存不足时系统会杀掉后台的Activity,若需要进行一些临时状态的保存,在哪个方法进行?
Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,它们不同于 onCreate()、onPause()等生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按Home键)由系统销毁一个Activity,onSaveInstanceState() 会被调用。但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。除非该activity是被用户主动销毁的,通常onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。
1.4 onSaveInstanceState()被执行的场景有哪些:
系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,因此系统都会调用onSaveInstanceState(),让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则
1. 当用户按下HOME键时
2. 长按HOME键,选择运行其他的程序时
3. 锁屏时
4. 从activity A中启动一个新的activity时
5. 屏幕方向切换时
1.5 介绍Activity的几中启动模式,并简单说说自己的理解或者使用场景
2 . Service系列问题
2.1 注册Service需要注意什么
Service还是运行在主线程当中的,所以如果需要执行一些复杂的逻辑操作,最好在服务的内部手动创建子线程进行处理,否则会出现UI线程被阻塞的问题
2.2 Service与Activity怎么实现通信
方法一:
1. 添加一个继承Binder的内部类,并添加相应的逻辑方法
2. 重写Service的onBind方法,返回我们刚刚定义的那个内部类实例
3. Activity中创建一个ServiceConnection的匿名内部类,并且重写里面的onServiceConnected方法和onServiceDisconnected方法,这两个方法分别会在活动与服务成功绑定以及解除绑定的时候调用,在onServiceConnected方法中,我们可以得到一个刚才那个service的binder对象,通过对这个binder对象进行向下转型,得到我们那个自定义的Binder实例,有了这个实例,做可以调用这个实例里面的具体方法进行需要的操作了
方法二 通过BroadCast(广播)的形式 当我们的进度发生变化的时候我们发送一条广播,然后在Activity的注册广播接收器,接收到广播之后更新视图
2.3 介绍源码中binder机制
2.4 IntentService与Service的区别
IntentService是Service的子类,是一个异步的,会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题
• 会创建独立的worker线程来处理所有的Intent请求;
• 会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;
• 所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;
• 为Service的onBind()提供默认实现,返回null;
• 为Service的onStartCommand提供默认实现,将请求Intent添加到队列中;
• IntentService不会阻塞UI线程,而普通Serveice会导致ANR异常
• Intentservice若未执行完成上一次的任务,将不会新开一个线程,是等待之前的任务完成后,再执行新的任务,等任务完成后再次调用stopSelf()
3. Handle系列问题
3.1 介绍Handle的机制
• Handler通过调用sendmessage方法把消息放在消息队列MessageQueue中,Looper负责把消息从消息队列中取出来,重新再交给Handler进行处理,三者形成一个循环
• 通过构建一个消息队列,把所有的Message进行统一的管理,当Message不用了,并不作为垃圾回收,而是放入消息队列中,供下次handler创建消息时候使用,提高了消息对象的复用,减少系统垃圾回收的次数
• 每一个线程,都会单独对应的一个looper,这个looper通过ThreadLocal来创建,保证每个线程只创建一个looper,looper初始化后就会调用looper.loop创建一个MessageQueue,这个方法在UI线程初始化的时候就会完成,我们不需要手动创建
3.2 谈谈对HandlerThread的理解
4. ListView系列问题
4.1 ListView卡顿的原因与性能优化,越多越好
1. 重用converView: 通过复用converview来减少不必要的view的创建,另外Infalte操作会把xml文件实例化成相应的View实例,属于IO操作,是耗时操作。
2. 减少findViewById()操作: 将xml文件中的元素封装成viewholder静态类,通过converview的setTag和getTag方法将view与相应的holder对象绑定在一起,避免不必要的findviewbyid操作
3. 避免在 getView 方法中做耗时的操作: 例如加载本地 Image 需要载入内存以及解析 Bitmap ,都是比较耗时的操作,如果用户快速滑动listview,会因为getview逻辑过于复杂耗时而造成滑动卡顿现象。用户滑动时候不要加载图片,待滑动完成再加载,可以使用这个第三方库glide
4. Item的布局层次结构尽量简单,避免布局太深或者不必要的重绘
5. 尽量能保证 Adapter 的 hasStableIds() 返回 true 这样在 notifyDataSetChanged() 的时候,如果item内容并没有变化,ListView 将不会重新绘制这个 View,达到优化的目的
6. 在一些场景中,ScollView内会包含多个ListView,可以把listview的高度写死固定下来。 由于ScollView在快速滑动过程中需要大量计算每一个listview的高度,阻塞了UI线程导致卡顿现象出现,如果我们每一个item的高度都是均匀的,可以通过计算把listview的高度确定下来,避免卡顿现象出现
7. 使用 RecycleView 代替listview: 每个item内容的变动,listview都需要去调用notifyDataSetChanged来更新全部的item,太浪费性能了。RecycleView可以实现当个item的局部刷新,并且引入了增加和删除的动态效果,在性能上和定制上都有很大的改善
8. ListView 中元素避免半透明: 半透明绘制需要大量乘法计算,在滑动时不停重绘会造成大量的计算,在比较差的机子上会比较卡。 在设计上能不半透明就不不半透明。实在要弄就把在滑动的时候把半透明设置成不透明,滑动完再重新设置成半透明。
9. 尽量开启硬件加速: 硬件加速提升巨大,避免使用一些不支持的函数导致含泪关闭某个地方的硬件加速。当然这一条不只是对 ListView。
4.2 怎么实现一个部分更新的 ListView?
4.3 怎么实现ListView多种布局?
4.4 ListView与数据库绑定的实现
5. JNI系列问题
5.1 如何使用JNI
1. JAVA中声明native 方法如private native String printJNI(String inputStr);
2. 使用javah工具生成.h头文件这时候头文件中就会自动生成对应的函数JNIEXPORT jstring JNICALL Java_com_wenming_HelloWorld_printJNI
3. 实现JNI原生函数源文件,新建HelloWorld.c文件,对刚才自动生成的函数进行具体的逻辑书写,例如返回一个java叫做HelloWorld的字符串等
4. 编译生成动态链接so文件**
5. Java中调用Sysytem.load方法把刚才的so库加载进来,就可以调用native方法了
5.2 如何通过JNI传递String对象
Java的String和C++的string是不能对等起来的,所以当我们拿到.h文件下面的jstring对象,会做一次转换我们把jstring转换为C下面的char*类型, 获取值
constchar* str;
str = env->GetStringUTFChars(prompt,false);
赋予值
char* tmpstr =”return string succeeded”;
jstring rtstr = env->NewStringUTF(tmpstr);
6. OOM系列问题
6.1 什么OOM?
OOM全称是Out Of Merrory,Android系统的每一个应用程序都设置一个硬性的Dalvik Heap Size最大限制阈值,如果申请的内存资源超过这个限制,系统就会抛出OOM错误
6.2 内存泄漏有哪些场景以及解决方法
• 类的静态变量持有大数据对象 静态变量长期维持到大数据对象的引用,阻止垃圾回收。
• 非静态内部类存在静态实例 非静态内部类会维持一个到外部类实例的引用,如果非静态内部类的实例是静态的,就会间接长期维持着外部类的引用,阻止被回收掉。
• 资源对象未关闭 资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们, 以便它们的缓冲及时回收内存。它们的缓冲不仅存在于java虚拟机内,还存在于java虚拟机外。 如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄露。 解决办法: 比如SQLiteCursor(在析构函数finalize(),如果我们没有关闭它,它自己会调close()关闭), 如果我们没有关闭它,系统在回收它时也会关闭它,但是这样的效率太低了。 因此对于资源性对象在不使用的时候,应该调用它的close()函数,将其关闭掉,然后才置为null. 在我们的程序退出时一定要确保我们的资源性对象已经关闭。 程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小, 对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险,记得try catch后,在finally方法中关闭连接
• Handler内存泄漏 Handler作为内部类存在于Activity中,但是Handler生命周期与Activity生命周期往往并不是相同的,比如当Handler对象有Message在排队,则无法释放,进而导致本该释放的Acitivity也没有办法进行回收。 解决办法:
• 声明handler为static类,这样内部类就不再持有外部类的引用了,就不会阻塞Activity的释放
• 如果内部类实在需要用到外部类的对象,可在其内部声明一个弱引用引用外部类。
• public class MainActivity extends Activity {
• private CustomHandler mHandler;
•
• @Override
• protected void onCreate(Bundle savedInstanceState) {
• super.onCreate(savedInstanceState);
• mHandler = new CustomHandler(this);
• }
•
• static class CustomHandlerextends Handler {
• // 内部声明一个弱引用,引用外部类
• private WeakReference activityWeakReference;
• public MyHandler(MyActivity activity) {
• activityWeakReference= new WeakReference(activity);
• }
• // … …
• }
• }
• 在Activity onStop或者onDestroy的时候,取消掉该Handler对象的Message和Runnable
• Override
• public void onDestroy() {
• // If null, all callbacks and messages will be removed.
• mHandler.removeCallbacksAndMessages(null);
• }
• 一些不良代码习惯 有些代码并不造成内存泄露,但是他们的资源没有得到重用,频繁的申请内存和销毁内存,消耗CPU资源的同时,也引起内存抖动 解决方案 如果需要频繁的申请内存对象和和释放对象,可以考虑使用对象池来增加对象的复用。 例如ListView便是采用这种思想,通过复用converview来避免频繁的GC
6.2 如何避免 OOM 问题的出现
1. 使用更加轻量的数据结构 例如,我们可以考虑使用ArrayMap/SparseArray而不是HashMap等传统数据结构。通常的HashMap的实现方式更加消耗内存,因为它需要一个额外的实例对象来记录Mapping操作。另外,SparseArray更加高效,在于他们避免了对key与value的自动装箱(autoboxing),并且避免了装箱后的解箱。
2. 避免在Android里面使用Enum Android官方培训课程提到过“Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.”,具体原理请参考《Android性能优化典范(三)》,所以请避免在Android里面使用到枚举。
3. 减小Bitmap对象的内存占用 Bitmap是一个极容易消耗内存的大胖子,减小创建出来的Bitmap的内存占用可谓是重中之重,,通常来说有以下2个措施: inSampleSize:缩放比例,在把图片载入内存之前,我们需要先计算出一个合适的缩放比例,避免不必要的大图载入。 decode format:解码格式,选择ARGB_6666/RBG_545/ARGB_4444/ALPHA_6,存在很大差异
4.Bitmap对象的复用 缩小Bitmap的同时,也需要提高BitMap对象的复用率,避免频繁创建BitMap对象,复用的方法有以下2个措施 LRUCache : “最近最少使用算法”在Android中有极其普遍的应用。ListView与GridView等显示大量图片的控件里,就是使用LRU的机制来缓存处理好的Bitmap,把近期最少使用的数据从缓存中移除,保留使用最频繁的数据, inBitMap高级特性:利用inBitmap的高级特性提高Android系统在Bitmap分配与释放执行效率。使用inBitmap属性可以告知Bitmap解码器去尝试使用已经存在的内存区域,新解码的Bitmap会尝试去使用之前那张Bitmap在Heap中所占据的pixel data内存区域,而不是去问内存重新申请一块区域来存放Bitmap。利用这种特性,即使是上千张的图片,也只会仅仅只需要占用屏幕所能够显示的图片数量的内存大小
4. 使用更小的图片 在涉及给到资源图片时,我们需要特别留意这张图片是否存在可以压缩的空间,是否可以使用更小的图片。尽量使用更小的图片不仅可以减少内存的使用,还能避免出现大量的InflationException。假设有一张很大的图片被XML文件直接引用,很有可能在初始化视图时会因为内存不足而发生InflationException,这个问题的根本原因其实是发生了OOM。
5.StringBuilder 在有些时候,代码中会需要使用到大量的字符串拼接的操作,这种时候有必要考虑使用StringBuilder来替代频繁的“+”。
4.避免在onDraw方法里面执行对象的创建 类似onDraw等频繁调用的方法,一定需要注意避免在这里做创建对象的操作,因为他会迅速增加内存的使用,而且很容易引起频繁的gc,甚至是内存抖动。
5. 避免对象的内存泄露 android中内存泄漏的场景以及解决办法,参考上一问
7. ANR 系列问题
7.1 什么ANR
ANR全称Application Not Responding,意思就是程序未响应。如果一个应用无法响应用户的输入,系统就会弹出一个ANR对话框,用户可以自行选择继续等待亦或者是停止当前程序。一旦出现下面两种情况,则弹出ANR对话框
• 应用在5秒内未响应用户的输入事件(如按键或者触摸)
• BroadcastReceiver未在10秒内完成相关的处理
7.2 ANR是怎么引起的?
• 主线程中存在耗时的计算-
• 主线程被IO操作(从4.0之后网络IO不允许在主线程中)阻塞。-
• 主线程中错误的操作,比如Thread.wait或者Thread.sleep等
7.3 如何避免ANR问题的出现
基本思路就是把一些耗时操作放到子线程中处理
• 使用AsyncTask处理耗时IO操作。
• 降低子线程优先级使用Thread或者HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同。
• 使用Handler处理子线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程。
• Activity的onCreate和onResume回调中尽量避免耗时的代码
• BroadcastReceiver中onReceive代码也要尽量减少耗时操作建议使用IntentService处理。IntentService是一个异步的,会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题
8. Asynctask问题
8.1 AsynTask为什么要设计为只能够一次任务?
最核心的还是线程安全问题,多个子线程同时运行,会产生状态不一致的问题。所以要务必保证只能够执行一次
8.2 AsynTask造成的内存泄露的问题怎么解决,比如非静态内部类AsynTask会隐式地持有外部类的引用,如果其生命周期大于外部activity的生命周期,就会出现内存泄漏
• 注意要复写AsynTask的onCancel方法,把里面的socket,file等,该关掉的要及时关掉
• 在 Activity 的onDestory()方法中调用Asyntask.cancal方法
• Asyntask内部使用弱引用的方式来持有Activity
8.3 若Activity已经销毁,此时AsynTask执行完并且返回结果,会报异常吗?
当一个App旋转时,整个Activity会被销毁和重建。当Activity重启时,AsyncTask中对该Activity的引用是无效的,因此onPostExecute()就不会起作用,若AsynTask正在执行,折会报 view not attached to window manager 异常
同样也是生命周期的问题,在 Activity 的onDestory()方法中调用Asyntask.cancal方法,让二者的生命周期同步
8.4 Activity销毁但Task如果没有销毁掉,当Activity重启时这个AsyncTask该如何解决?
还是屏幕旋转这个例子,在重建Activity的时候,会回掉Activity.onRetainNonConfigurationInstance()重新传递一个新的对象给AsyncTask,完成引用的更新
9. Android触摸分发机制
9.1 介绍触摸事件的分发机制
(1) 事件从Activity.dispatchTouchEvent()开始传递,只要没有被停止或拦截,从最上层的View(ViewGroup)开始一直往下(子View)传递。子View可以通过onTouchEvent()对事件进行处理。
(2) 事件由父View(ViewGroup)传递给子View,ViewGroup可以通过onInterceptTouchEvent()对事件做拦截,停止其往下传递。
(3) 如果事件从上往下传递过程中一直没有被停止,且最底层子View没有消费事件,事件会反向往上传递,这时父View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到Activity的onTouchEvent()函数。
(4) 如果View没有对ACTION_DOWN进行消费,之后的其他事件不会传递过来。
(5) OnTouchListener优先于onTouchEvent()对事件进行消费。
上面的消费即表示相应函数返回值为true。
9.2 View中 setOnTouchListener的onTouch,onTouchEvent,onClick的执行顺序
追溯到View的dispatchTouchEvent源码查看,有这么一段代码
public boolean dispatchTouchEvent(MotionEvent event) {
if (!onFilterTouchEventForSecurity(event)) {
return false;
}
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
当以下三个条件任意一个不成立时,
• mOnTouchListener不为null
• view是enable的状态
• mOnTouchListener.onTouch(this, event)返回true,
函数会执行到onTouchEvent。在这里我们可以看到,首先执行的是mOnTouchListener.onTouch的方法,然后是onTouchEvent方法
继续追溯源码,到onTouchEvent()观察,发现在处理ACTION_UP事件里有这么一段代码
if (!post(mPerformClick)) {
performClick();
}
此时可知,onClick方法也在最后得到了执行
所以三者的顺序是:
1. setOnTouchListener() 的onTouch
2. onTouchEvent()
3. onClick()
10. Dalvik虚拟机系列问题
10.1 什么是Dalvik虚拟机?
Dalvik虚拟机是Android平台的核心。它可以支持.dex格式的程序的运行,.dex格式是专为Dalvik设计的一种压缩格式,可以减少整体文件尺寸,提高I/O操作的速度,适合内存和处理器速度有限的系统。
10.2 Dalvik虚拟机的作用是什么?
Dalvik虚拟机主要是完成对象生命周期管理,内存回收,堆栈管理,线程管理,安全和异常管理等等重要功能。
10.3 Dalvik虚拟机与JVM有什么区别
• Dalvik 基于寄存器,而 JVM 基于栈。基于寄存器的虚拟机对于更大的程序来说,在它们编译的时候,花费的时间更短。
• Dalvik执行.dex格式的字节码,而JVM执行.class格式的字节码。
10.4 每个应用程序对应多少个Dalvik虚拟机
• 每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行 ,而所有的Android应用的线程都对应一个Linux线程
11. 注册广播接收器有哪几种方式,有什么区别
• 静态注册:在AndroidManifest.xml文件中进行注册,当App退出后,Receiver仍然可以接收到广播并且进行相应的处理
• 动态注册:在代码中动态注册,当App退出后,也就没办法再接受广播了
12. 显示Intent与隐式Intent的区别
对明确指出了目标组件名称的Intent,我们称之为“显式Intent”。 对于没有明确指出目标组件名称的Intent,则称之为“隐式 Intent”。
对于隐式意图,在定义Activity时,指定一个intent-filter,当一个隐式意图对象被一个意图过滤器进行匹配时,将有三个方面会被参考到:
• 动作(Action)
• 类别(Category [‘kætɪg(ə)rɪ] )
• 数据(Data )
13. Android中的动画有哪些,区别是什么
• 逐帧动画(Drawable Animation): 加载一系列Drawable资源来创建动画,简单来说就是播放一系列的图片来实现动画效果,可以自定义每张图片的持续时间
• 补间动画(Tween Animation): Tween可以对View对象实现一系列简单的动画效果,比如位移,缩放,旋转,透明度等等。但是它并不会改变View属性的值,只是改变了View的绘制的位置,比如,一个按钮在动画过后,不在原来的位置,但是触发点击事件的仍然是原来的坐标。
• 属性动画(Property Animation): 动画的对象除了传统的View对象,还可以是Object对象,动画结束后,Object对象的属性值被实实在在的改变了
- 不使用动画,怎么实现一个动态的 View?
- Postvalidata与Validata有什么区别?
- 如何自定义ViewGroup?
17. View的绘制流程
measure()方法,layout(),draw()三个方法主要存放了一些标识符,来判断每个View是否需要再重新测量,布局或者绘制,主要的绘制过程还是在onMeasure,onLayout,onDraw这个三个方法中
1.onMesarue() 为整个View树计算实际的大小,即设置实际的高(对应属性:mMeasuredHeight)和宽(对应属性: mMeasureWidth),每个View的控件的实际宽高都是由父视图和本身视图决定的。
2.onLayout() 为将整个根据子视图的大小以及布局参数将View树放到合适的位置上。 - onDraw() 开始绘制图像,绘制的流程如下
- 首先绘制该View的背景
- 调用onDraw()方法绘制视图本身 (每个View都需要重载该方法,ViewGroup不需要实现该方法)
- 如果该View是ViewGroup,调用dispatchDraw ()方法绘制子视图
- 绘制滚动条
18. 数据持久化的四种方式有哪些?
1. 文件存储: 通过java.io.FileInputStream和java.io.FileOutputStream这两个类来实现对文件的读写,java.io.File类则用来构造一个具体指向某个文件或者文件夹的对象。
2. SharedPreferences: SharedPreferences是一种轻量级的数据存储机制,他将一些简单的数据类型的数据,包括boolean类型,int类型,float类型,long类型以及String类型的数据,以键值对的形式存储在应用程序的私有Preferences目录(/data/data/<包名>/shared_prefs/)中,这种Preferences机制广泛应用于存储应用程序中的配置信息。
3. SQLite数据库: 当应用程序需要处理的数据量比较大时,为了更加合理地存储、管理、查询数据,我们往往使用关系数据库来存储数据。Android系统的很多用户数据,如联系人信息,通话记录,短信息等,都是存储在SQLite数据库当中的,所以利用操作SQLite数据库的API可以同样方便的访问和修改这些数据。
4. ContentProvider: 主要用于在不同的应用程序之间实现数据共享的功能,不同于sharepreference和文件存储中的两种全局可读写操作模式,内容提供其可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会有泄漏的风险
19. fragement里面可以再嵌套fragment?
20. Socket编程的步骤
21. Activity中如何动态的添加Fragment
22. Scrollview怎么判断是否滑倒底部
23. 什么是 MVC 模式?MVC 模式的好处是什么?
24. 应用常驻后台,避免被第三方杀掉的方法,讲讲你用过的奇淫巧技?
1. Service设置成START_STICKY kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样
2. 通过 startForeground将进程设置为前台进程, 做前台服务,优先级和前台应用一个级别,除非在系统内存非常缺,否则此进程不会被 kill
3. 双进程Service: 让2个进程互相保护**,其中一个Service被清理后,另外没被清理的进程可以立即重启进程
4. QQ黑科技: 在应用退到后台后,另起一个只有 1 像素的页面停留在桌面上,让自己保持前台状态,保护自己不被后台清理工具杀死
5. 在已经root的设备下,修改相应的权限文件,将App伪装成系统级的应用 Android4.0系列的一个漏洞,已经确认可行
1. 用C编写守护进程(即子进程) : Android系统中当前进程(Process)fork出来的子进程,被系统认为是两个不同的进程。当父进程被杀死的时候,子进程仍然可以存活,并不受影响。鉴于目前提到的在Android->- Service层做双守护都会失败,我们可以fork出c进程,多进程守护。死循环在那检查是否还存在,具体的思路如下(Android5.0以上的版本不可行)
2. 用C编写守护进程(即子进程),守护进程做的事情就是循环检查目标进程是否存在,不存在则启动它。
3. 在NDK环境中将1中编写的C代码编译打包成可执行文件(BUILD_EXECUTABLE)。主进程启动时将守护进程放入私有目录下,赋予可执行权限,启动它即可。
4. 联系厂商,加入白名单
25.Context与ApplicationContext的区别,分别用在什么情况下
Application的Context是一个全局静态变量,SDK的说明是只有当你引用这个context的生命周期超过了当前activity的生命周期,而和整个应用的生命周期挂钩时,才去使用这个application的context。
在android中context可以作很多操作,但是最主要的功能是加载和访问资源。在android中有两种context,一种是 application context,一种是activity context,通常我们在各种类和方法间传递的是activity context。
context.getExternalCacheDir() 、 context.getCacheDir()
相同点:
1、相同点:都可以做app缓存目录。
2、app卸载后,两个目录下的数据都会被清空。
不同点:
1、目录的路径不同。前者的目录存在外部SD卡上的。后者的目录存在app的内部存储上。
2、前者的路径在手机里可以直接看到。后者的路径需要root以后,用Root Explorer 文件管理器才能看到。
26. 如何评价Android系统?以及优缺点
优点:(1)开放性、开源、免费、可定制。
开放的平台吸引者越来越多的开发者,开源的代码库、免费的开发软件、社区、第三方开源共享,在带来巨大的竞争的同时也使得android在开放的平台中显得日益成熟;
(2)运营商对网络的束缚减少
(3)更加丰富的硬件选择
(4)软件开发中的不受限制
(5)无缝结合的google应用
缺点:(1)安全和隐私问题
由于android的开放性与互联网的紧密联系,也使得用户在上网中
留下足迹,打开过哪些网页,浏览过哪些信息,同时保存过哪些信息等等,这些足迹可以说都已经
暴露了出去,因此当你打开网页时会发现有为你推荐,猜你喜欢等功能,同时还有一些广告的弹出,
用户的信息不能得到保证;还有各种app引发的安全问题.
(2)每一款android手机依然有着运营商的介入
(3)山寨化严重
(4)过分依赖开发商缺少标准配置
- 同一个应用程序的不同Activity可以运行在不同的进程中么?如果可以,举例说明;
- Java中的线程同步有哪几种方式,举例说明;
- dp, dip, dpi, px, sp是什么意思以及他们的换算公式?layout-sw400dp, layout-h400dp分别代表什么意思;
- 如何让两个TextView在一个RelativeLayout水平居中显示;
- 如何画出一个印章的图案
- 如何实现一个字体的描边与阴影效果
- 设计一个从网络请求数据,图片,并加载到列表的系统,画出客户端架构并简单的分析下;
- 设计一个文件的断点续传系统;
- 设计一个图片缓存加载机制
数据结构与算法部分: - 给最外层的rootview,把这个根视图下的全部button背景设置成红色,手写代码,不许用递归
- 给一串字符串比如abbbcccd,输出a1b3c3d1,手写代码(注意有个别字符可能会出现十次以上的情况)
- 一个序列,它的形式是12349678,9是最高峰,经历了一个上升又下降的过程,找出里面的最大值的位置,要求效率尽可能高
- 二叉查找树的删除操作,手写代码
- 反转链表,手写代码
- 二分查找,手写代码
- 有海量条 url,其中不重复的有300万条,现在希望挑选出重复出现次数最高的 url,要求效率尽可能的高
- 一篇英语文章,去掉字符只留下k个,如何去掉才能使这k个字符字典序最小
- 弗洛伊德算法和 Dijkstra算法的区别?复杂度是多少?讲讲 Dijkstra算法的具体过程
- 反转字符串,要求手写代码,优化速度、优化空间
- 给出两个无向图,找出这2个无向图中相同的环路。手写代码
- 单例模式,手写代码
- 生产者与消费者,手写代码
- 二叉树镜像,手写代码
- 最长不重复子串(最长重复子串),手写代码
操作系统部分: - 分别从操作系统的内存角度与进程线程角度解释分析堆,栈二者的区别
- 什么是事务?
- OSI七层模型有哪些,各层次的作用
- TCP的三次握手过程,四次挥手过程,为什么需要三次?
- 说说操作系统中进程的通信方式
- 浏览器输入地址之后,之后的过程
- 谈谈 HTTP 中Get 和 Post 方法的区别?