Android面试-Android部分

本系列出于AWeiLoveAndroid的分享,在此感谢,再结合自身经验查漏补缺,完善答案。以成系统。


Android基础知识点

  • 四大组件是什么

http://blog.csdn.net/shiretan/article/details/55053857
Activity Service BroadCastReceiver ContentProvider

  • 四大组件的生命周期和简单用法

http://blog.csdn.net/zf6688/article/details/49497891

  • Activity之间的通信方式

http://blog.csdn.net/a_running_wolf/article/details/48813995
http://blog.csdn.net/a_running_wolf/article/details/48826495
Intent 静态变量 全局对象 SharePreference File Sqlite Service

  • Activity各种情况下的生命周期

http://blog.csdn.net/woshimalingyi/article/details/50961380
配置改变(例如横竖屏切换) configChanges(改变不重建) 异常退出 onSaveInstance
onRestoreInstance
A onPause后B onResume
自己的Dialog是自己的View,不影响生命周期,其它的Dialog才会影响

  • 横竖屏切换的时候,Activity 各种情况下的生命周期

http://blog.csdn.net/hzw19920329/article/details/51345971
... onSaveInstanceState->onStop... ---> onStart->onRestoreInstance

  • Activity与Fragment之间生命周期比较

http://blog.csdn.net/u012702547/article/details/50253955

image

  • Activity的生命周期&finish方法&back键&home键&dialog对话框

http://blog.csdn.net/hanhan1016/article/details/47977489

  • 两个Activity 之间跳转时必然会执行的是哪几个方法?

http://blog.csdn.net/m_xiaoer/article/details/72881082
一般情况下比如说有两个activity,分别叫A,B。
当在A 里面激活B 组件的时候, A会调用onPause()方法,然后B调用onCreate() ,onStart(), onResume()。
这个时候B覆盖了A的窗体, A会调用onStop()方法。
如果B是个透明的窗口,或者是对话框的样式, 就不会调用A的onStop()方法。
如果B已经存在于Activity栈中,B就不会调用onCreate()方法。

  • Activity的四种启动模式对比

http://blog.csdn.net/mynameishuangshuai/article/details/51491074

  • standard 每次启动一个Activity都会重写创建一个新的实例
  • singleTop 栈顶复用模式,已经位于栈顶,那么这个Activity不会被重写创建,同时它的onNewIntent方法会被调用
  • standard和singleTop启动模式都是在原任务栈中新建Activity实例,不会启动新的Task,即使你指定了taskAffinity属性。
  • singleTask 栈内复用模式,如果栈中存在这个Activity的实例就会复用这个Activity,不管它是否位于栈顶,复用时,会将它上面的Activity全部出栈,并且会回调该实例的onNewIntent方法。
    其实这个过程还存在一个任务栈的匹配,因为这个模式启动时,会在自己需要的任务栈中寻找实例,这个任务栈就是通过taskAffinity属性指定。如果这个任务栈不存在,则会创建这个任务栈。
    两个不同App中的Activity设置为相同的taskAffinity,这样虽然在不同的应用中,但是Activity会被分配到同一个Task中去。
    singleInstance-全局唯一模式,具备singleTask模式的所有特性外,单独占用一个Task栈,系统中具有全局唯一性。
  • Activity状态保存于恢复

https://www.jianshu.com/p/715333d87738

  • fragment各种情况下的生命周期

http://blog.csdn.net/jokeeeeee/article/details/46004931

  • Fragment状态保存startActivityForResult是哪个类的方法,在什么情况下使用?

http://blog.csdn.net/barryhappy/article/details/53229238
Fragment所发起的请求,都通过一个映射,把最终的requestCode变成了一个大于0xffff的值。

  • fragment之间传递数据的方式?

https://www.jianshu.com/p/f87baad32662
setData() 接口回调 EventBus

  • Activity 怎么和Service 绑定?

http://blog.csdn.net/liyuchong2537631/article/details/48440911

  • service和activity怎么进行数据交互?

http://www.jb51.net/article/94716.htm

  • Service的开启方式,Service 的生命周期

http://blog.csdn.net/jiaohanhan/article/details/71880914

  • 谈谈你对ContentProvider的理解

http://blog.csdn.net/u012858833/article/details/51629245

  • 请描述一下广播BroadcastReceiver的理解

http://blog.csdn.net/wl724120268/article/details/51607112
http://blog.csdn.net/hehe26/article/details/51674167

  • 广播的分类

http://blog.csdn.net/wl724120268/article/details/51607112
有序,普通

  • 广播使用的方式和场景

http://blog.csdn.net/yangzhaomuma/article/details/49817337
接受系统广播
进程间通讯
本地广播

  • 在manifest 和代码中如何注册和使用BroadcastReceiver?

http://blog.csdn.net/yangzhaomuma/article/details/49817337

<receiver android:name="com.example.broadcasttest_csdn.MyReceiver">  
     <intent-filter >  
           <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>  
     </intent-filter>  
</receiver>  
IntentFilter iFilter=new IntentFilter();        
iFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);  
bReceiver=new myBroadCast();  
registerReceiver(bReceiver, iFilter);  
  • 本地广播和全局广播有什么差别/BroadcastReceiver,LocalBroadcastReceiver 区别?

http://blog.csdn.net/olevin/article/details/51993682

LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
lbm.registerReceiver(new BroadcastReceiver() {  
        @Override  
        public void onReceive(Context context, Intent intent) {  
        // TODO Handle the received local broadcast  
        }  
    }, new IntentFilter(LOCAL_ACTION));  
lbm.sendBroadcast(new Intent(LOCAL_ACTION));  
  • AlertDialog,PopupWindow

http://blog.csdn.net/android_cmos/article/details/51223776
AlertDialog 非阻塞
PopupWindow 阻塞

  • Application 和 Activity 的 Context 对象的区别

https://www.cnblogs.com/ganchuanpu/p/6445251.html
生命周期不同

  • Android动画

https://www.jianshu.com/p/6dbfc62f708c

  • 如何导入外部数据库?

https://www.cnblogs.com/xiaowenji/archive/2011/01/03/1925014.html

  • LinearLayout、RelativeLayout、FrameLayout的特性及对比,并介绍使用场景。

http://blog.csdn.net/hejjunlin/article/details/51159419

  • RelativeLayout需要横向纵向分别进行一次排序测量,相比LinearLayout的measure耗时要多些。如果LinearLayout中有weight属性,则也需要进行两次measure,但即便如此,应该仍然会比RelativeLayout的情况好一点。
  • View的measure方法里对绘制过程做了一个优化,就是没啥变化时不重新measure,但是RelativeLayout是两次,可能有一次没完成,子View高度不等于ReleativeLayout导致View的这个优化不起作用。所以如果可以,尽量使用padding代替margin。
  • LinearLayout里嵌套LinearLayout会加一倍measure。所以尽量少嵌套LinearLayout
  • ReleativeLayout能更好的减少层级,层级越少效率越高,虽然单个是LinearLayout要高些,但是复杂的布局应当以减少层级为准
  • 谈谈对接口与回调的理解

回调接口,回调方法,关注结果而不关注过程

  • 介绍下SurfaceView

使用详解

  • RecycleView的使用

http://blog.csdn.net/lmj623565791/article/details/45059587

  • 序列化的作用,以及Android两种序列化的区别

http://blog.csdn.net/wangchunlei123/article/details/51345130

  • Serializable serialVersionUID transient
    序列化和反序列化过程需要大量的I/O操作
    适用于 序列化到本地或者通过网络传输
  • Parcelable 相比于Seriablizable具有更好的性能
    public int describeContents(){}
    public void writeToParcel(Parcel out,int flags){}
    public static final Parcelable.Creator<User> CREATOR = {
    createFromParcel(Parcel in){}
    newArray(int size){}
    }
    适用于内存序列化
  • 差值器

http://blog.csdn.net/pzm1993/article/details/77926373
负责控制动画变化的速率
继承TimeInterpolator 重写float getInterpolation(float input); 方法

  • 估值器

http://blog.csdn.net/wuyuxing24/article/details/51591853
用来确定在动画过程中每时每刻动画的具体值
实现TypeEvaluator 重写public T evaluate(float fraction, T startValue, T endValue);
默认提供了如下几种估值器 ArgbEvaluator, FloatArrayEvaluator, FloatEvaluator, IntArrayEvaluator, IntEvaluator, PointFEvaluator, RectEvaluator。

  • Android中数据存储方式

http://blog.csdn.net/amazing7/article/details/51437435
SharedPreferences
File (内部存储openFileOutput() openFileInput( ))+外部存储
Sqlite
ContentProvider
Net

Android源码相关分析

  • Android动画框架实现原理

http://blog.csdn.net/harrain/article/details/53726960
View---invalidate()---mParent.invalidateChild() 递归绘制
ParentView 来不断调整 ChildView 的画布坐标系来实现的

Animation 定义了一些动画属性
Transformation 持有一个矩阵 一个alpha
在具体的Animation的applyTransformation()方法中去改变值
View的draw中去应用实现动画效果
位移: t.getMatrix().setTranslate(dx, dy);
缩放: t.getMatrix().setScale(sx, sy);
旋转: t.getMatrix().setRotate(degrees);
渐变:t.setAlpha(alpha + ((mToAlpha - alpha) * interpolatedTime));

*Android属性动画原理/源码解析

http://blog.csdn.net/u013378580/article/details/51917884
上面文章不是最新的源码分析,但原理差不多

  • 初始化
    ValueAnimator.ofInt(int... values)---PropertyValuesHolder.ofInt("", values)---mKeyframes = KeyframeSet.ofInt(values);---Keyframe.ofInt()
    ValueAnimator 外部api
    PropertyValuesHolder 存储属性(mPropertyName)和贞(mKeyframes)
    KeyframeSet 贞信息集合mFirstKeyframe,mLastKeyframe,
          mKeyframes,mInterpolator, mEvaluator
    Keyframe 一帧的信息
  • start()
    addAnimationCallback(0)---Choreographer.postFrameCallback//新版本在此开启动画
    startAnimation()---initAnimation();+setCurrentPlayTime()---animateValue().进行初始化设置
  • Android各个版本API的区别

?

  • requestlayout,onlayout,onDraw,DrawChild, invalidate区别与联系

http://blog.csdn.net/zoky_ze/article/details/54892971

  • requestLayout()方法 :会导致调用measure()过程 和 layout()过程 。 说明:只是对View树重新布局layout过程包括measure()和layout()过程,不会调用draw()过程,但不会重新绘制 任何视图包括该调用者本身。
  • onLayout()方法(如果该View是ViewGroup对象,需要实现该方法,对每个子视图进行布局)
  • 调用onDraw()方法绘制视图本身 (每个View都需要重载该方法,ViewGroup不需要实现该方法)
  • drawChild()去重新回调每个子视图的draw()方法
  • View调运invalidate方法的实质是层层上传到父级,直到传递到ViewRootImpl后触发了scheduleTraversals方法,然后整个View树开始重新按照View绘制流程进行重绘任务。
  • invalidate和postInvalidate的区别及使用
//postInvalidate 通过Handler会这样执行
case MSG_INVALIDATE:
              ((View) msg.obj).invalidate();

invalidate()得在UI线程中被调动
postInvalidate可以在非主线程中调用

invalidate的源码流程
invalidate---parent.invalidateChild(this, damage);---do {parent.invalidateChildInParent(location, dirty);}while---ViewRootImpl.invalidateChildInParent()---invalidateRectOnScreen(Rect dirty)---scheduleTraversals();---mTraversalRunnable.run(){performTraversals();}

  • Activity-Window-View三者的差别
  • 结论
    Activity在onCreate时调用attach方法,在attach方法中会创建window对象(mWindow = new PhoneWindow(this, window, activityConfigCallback);)。window对象创建时并没有创建 DocerView 对象。用户在Activity中调用setContentView,然后调用window的setContentView,这时会检查DecorView是否存在,如果不存在则创建DecorView对象,然后把用户自己的 View 添加到 DecorView 中。
  • Context源码分析

http://blog.csdn.net/qq_23547831/article/details/46481725

Context集成结构

  • Activity中ContextImpl实例化源码分析,其它类似
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    //省略...
    //创建Activity所数的ContextImpl对象,这里面最终是new的ContextImpl
     ContextImpl appContext = createBaseContextForActivity(r);
   //创建Activity示例
    activity = mInstrumentation.newActivity(
                   cl, component.getClassName(), r.intent);
   //context持有activity实例,这是内存泄露的核心原理
   appContext.setOuterContext(activity);
}
//Activity的attach方法
final void attach(...) {
      //Activity包装了ContextImpl实例 
      attachBaseContext(context);
     //省略...
}
  • 各个context.getResources()得到Resource是一个对象,因为ContextImpl中有如下代码
    //单利创建资源对象
    return ResourcesManager.getInstance().getResources(****);
    
  • apk打包流程/项目构建流程

http://blog.csdn.net/qq_23547831/article/details/50634435

打包流程

threadPoolExecutor threadPoolExecutor = new >ThreadPoolExecutor(
               CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
               sPoolWorkQueue, sThreadFactory); 
private static InternalHandler sHandler;
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
           notifyAll();
        }
       Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
  • IntentService源码

http://blog.csdn.net/qq_23547831/article/details/50958757
本质是一个机遇HandlerThread的Handler通过发送消息将执行的任务放到HandlerThread中去执行

  • Zygote进程启动流程

http://blog.csdn.net/qq_23547831/article/details/51104873

  • android系统中各种进程的启动方式:
    init进程 –> Zygote进程 –> SystemServer进程 –>各种应用进程
public static void main(String argv[]) {
        //创建孵化服务
        ZygoteServer zygoteServer = new ZygoteServer();
        //....
        try {
            //...
            //设置DDMS可用
            RuntimeInit.enableDdms();
            // 启动分析孵化进程并初始化
            SamplingProfilerIntegration.start();
            boolean startSystemServer = false;
            String socketName = "zygote";
           String abiList = null;
            boolean enableLazyPreload = false;
            //主要是解析main方法的参数获取是否需要启动SystemService进程,
            //获取abi列表,获取scoket连接名称
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
               } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }
            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }
            //为Zygote进程注册socket,这里注意SystemService与Zygote的通讯是通过Socket
            zygoteServer.registerServerSocket(socketName);
            if (!enableLazyPreload) {
                //...
                //初始化Zygote中需要的class类,系统资源,OpenGL,系统libraries,文字资源,webview;
                preload(bootTimingsTraceLog);
                //...
            } else {
                Zygote.resetNicePriority();
            }
            //....
            //通过Zygote fork出SystemServer进程
            if (startSystemServer) {
                startSystemServer(abiList, socketName, zygoteServer);
            }
            zygoteServer.runSelectLoop(abiList);
            //关闭Socket连接
            zygoteServer.closeServerSocket();
        } catch (Zygote.MethodAndArgsCaller caller) {
            caller.run();
        } catch (Throwable ex) {
            zygoteServer.closeServerSocket();
            throw ex;
        }
   }
  • SystemServer进程启动流程

http://blog.csdn.net/qq_23547831/article/details/51105171

  1. 首先会初始化一些系统变量,加载类库,创建Context对象,创建SystemServiceManager对象等之后才开始启动系统服务;
  2. SertemServer进程在尝试启动服务之前会首先尝试与Zygote建立socket通讯,只有通讯成功之后才会开始尝试启动服务;
  3. SystemServer进程将系统服务分为三类:boot服务,core服务和other服务,并逐步启动
  4. 创建的系统服务过程中主要通过SystemServiceManager对象来管理,通过调用服务对象的构造方法和onStart方法初始化服务的相关变量;服务对象都有自己的异步消息对象,并运行在单独的线程中;
  5. mActivityManagerService.systemReady(() -> startHomeActivityLocked 启动了Lanucher
  • Launcher启动流程

http://blog.csdn.net/qq_23547831/article/details/51112031

  • Zygote进程 –> SystemServer进程 –> startOtherService方法 –> ActivityManagerService的systemReady方法 –> startHomeActivityLocked方法 –> ActivityStackSupervisor的startHomeActivity方法 –> 执行Activity的启动逻辑,执行scheduleResumeTopActivities()方法。。。。
  • 因为是隐士的启动Activity,所以启动的Activity就是在AndroidManifest.xml中配置catogery的值为:CATEGORY_HOME = "android.intent.category.HOME";
  • LauncherActivity中是以ListView来显示我们的应用图标列表的,并且为每个Item保存了应用的包名和启动Activity类名,这样点击某一项应用图标的时候就可以根据应用包名和启动Activity名称启动我们的App了。
  • 应用进程启动流程

http://blog.csdn.net/qq_23547831/article/details/51119333
启动四大组件之一便可启动应用进程
LauncherActivity---onListItemClick---startActivity(intent);-- mInstrumentation.execStartActivity()---ActivityManager.getService()
.startActivity()这里是AIDL机制,将与服务进程中的ActivityManagerService通讯---ActivityManagerService.startActivityAsUser()方法---ActivityStarter.startActivityMayWait()---startActivityLocked()---postStartActivityProcessing()启动进程---启动中的关键processClass=“android.app.ActivityThread”,也就是最终到ActivityThread的Main方法中

  • Manifest解析

http://blog.csdn.net/qq_23547831/article/details/51203482

  • android系统启动之后会解析固定目录下的apk文件,并执行解析,持久化apk信息,重新安装等操作;
  • 解析Manifest流程:Zygote进程 –> SystemServer进程 –> PackgeManagerService服务 –> scanDirLI方法 –> scanPackageLI方法 –> PackageParser.parserPackage方法;
  • 解析完成Manifest之后会将apk的Manifest信息保存在Settings对象中并持久化,然后执行重新安装的操作;
  • apk安装流程

http://blog.csdn.net/qq_23547831/article/details/51210682
platform_packages_apps_packageinstaller源码,关注 清单配置文件,InstallStart(这是个Activity)负责引导而已,最终启动的PackageInstallerActivity 出来确认弹框---点击确定打开InstallInstalling(也是个Activity)

  • 代码中执行intent.setDataAndType(Uri.parse(“file://” + path),”application/vnd.android.package-archive”);可以调起InstallStart判断好后再调起PackageInstallerActivity;
  • PackageInstallerActivity主要用于执行解析apk文件,解析manifest,解析签名等操作;
  • InstallInstalling主要用于执行安装apk逻辑,用于初始化安装界面,用于初始化用户UI。并调用PackageInstaller执行安装逻辑;
  • InstallInstalling内注册有观察者,当安装完成之后接收广播,更新UI。显示apk安装完成界面;
  • Activity的回调原理/activity的启动流程

http://blog.csdn.net/qq_23547831/article/details/51224992

  • 应用进程---服务进程--孵化进程的复杂通讯
  • 先之前的onPause---再新的create,start,resume,resume后通知服务进程对之前栈顶的Activity执行onStop,在onStop后saveState
  • Activity的销毁流程

http://blog.csdn.net/qq_23547831/article/details/51232309
onPause(a) onRestart(b) onStart(b) onResume(b) onStop(a) onDestory(a)
CS架构的应用

  • Application的创建流程

http://blog.csdn.net/qq_23547831/article/details/51252082

  • ActivityThread.main方法–> ActivityManagerService.bindApplication方法 –> ActivityThread.handleBindApplication –> 创建Instrumentation,创建Application;
  • 每个应用进程对应一个Instrumentation,对应一个Application;
  • Instrumentation与Application都是通过java反射机制创建;
  • Application创建过程中会同时创建一个ContextImpl对象,并建立关联;
  • 布局加载流程

http://blog.csdn.net/qq_23547831/article/details/51284556

  • 在启动时activity的attach方法创建Window对象 new PhoneWindow();一个activity对应一个window
  • 在重写onCreate时必须调用super.onCreate,因为这里面进行了一些初始化操作,特别是activity.mCalled = true;否则会跑出did not call through to super.onCreate()的异常信息。
  • setContentView实现是在PhoneWindow中。其流程是先generateDecor创建DecorView(extends FrameLayout),然后generateLayout在里面加载系统的布局并添加DecorView中,然后调用getDecorView().findViewById(id)取出布局中id为com.android.internal.R.id.content的View给mContentParent,然后通过mLayoutInflater.inflate(layoutResID, mContentParent);将setContentView中的布局加载并添加到mContentParent中。
  • View的绘制流程源码解析
  • ActivityThread在handleLaunchActivity中执行performLaunchActivity,attach时进行Window及WindowManager的创建,然后创建了DecorView加载了布局文件,然后执行handleResumeActivity方法
  • 在handleResumeActivity在performResumeActivity后进行一些设置和初始化后调用r.activity.makeVisible();
  • makeVisible()中wm.addView(mDecor, getWindow().getAttributes());其中wm为WindowManagerImpl。
  • WindowManagerImpl 的addView委托给单利的WindowManagerGlobal进行addView
  • WindowManagerGlobal持有三个集合mViews,mRoots,mParams。在其addView中会创建ViewRootImpl root,最终调用root.setView(view, wparams, panelParentView);将mDecorView与ViewRootImpl进行关联,而ViewRootImpl的主要作用就是绘制View
  • root.setView中会执行requestLayout();
  • requestLayout();中先检查当前是否为主线程,然后调用scheduleTraversals()
  • scheduleTraversals中会启动mTraversalRunnable任务对象
  • mTraversalRunnable中的run方法调用doTraversal(),doTraversal中调用performTraversals();这里也就是绘制的入口了
  • performTraversals中以DecorView为跟,执行如下操作
    1. performMeasure---measure---onMeasure
    2. performLayout---layout ---onLayout
    3. performDraw--draw--drawSoftware--mView.draw---onDraw/dispatchDraw
  • draw六部
    1. Draw the background
    2. If necessary, save the canvas' layers to prepare for fading
    3. Draw view's content
    4. Draw children
    5. If necessary, draw the fading edges and restore layers
    6. Draw decorations (scrollbars for instance)
  • Dialog,Popwindow,Toast的显示源码分析
  • Dialog
    http://blog.csdn.net/qq_23547831/article/details/51289456
    http://blog.csdn.net/qq_23547831/article/details/51303072
    1. Dialog和Activity的显示逻辑是相似的都是内部管理这一个Window对象,用WIndow对象实现界面的加载与显示逻辑;
    2. Dialog.show方法展示窗口,初始化Dialog的布局文件,Window对象等,然后执行mWindowManager.addView方法,开始执行绘制View的操作,并最终将Dialog显示出来;
    3. 通过调用WindowManager.removeViewImmediate方法,开始执行Window窗口的取消绘制流程;
    4. Window窗口的取消绘制流程,通过清空bitma撤销draw的执行效果,通过置空View撤销meature和layout的执行效果;
  • Popwindow
    http://blog.csdn.net/qq_23547831/article/details/51322574
    1. PopupWindow的界面加载绘制流程也是通过Window对象实现的;
    2. PopupWindow内部保存的mWindowManager对象通过ContextImpl中获取,并且取得的是WindowManagerImpl对象;
    3. PopupWindow通过为传入的View添加一层包裹的布局,并重写该布局的点击事件,实现点击PopupWindow之外的区域PopupWindow消失的效果;
  • Toast
    http://blog.csdn.net/qq_23547831/article/details/51374627
    1. Toast的show方法首先会初始化一个Toast对象,然后将内部对象TN与duration传递给NotificationManagerService,并在NotificationManagerService端维护一个Toast对象列表。
    2. NotificationManagerService接收到Toast的show请求之后,保存Toast对象并回调Toast.TN的show方法具体实现Toast窗口的显示逻辑。
    3. NotificationManagerService端在执行show方法执行会发送一个异步消息用于销毁Toast窗口,这个异步消息会在duration时间段之后发出,这样,在设置Toast显示的时间就会被传递到NotificationManagerService端,并在这段时间之后发送异步消息销毁Toast窗口。
    4. Toast窗口的显示与销毁机制与Activity、Dialog、PopupWIndow都是类似的,都是通过WIndow对象实现的。
  • 谈谈对Volley的理解

郭霖-Volley专栏

Volley原理图

/**
* 创建请求队列
*/
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
  //...
  if (stack == null) {  
        if (Build.VERSION.SDK_INT >= 9) {  
            stack = new HurlStack();  //本质是HttpUrlConnection
        } else {  
            stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));  //本质是HttpClient
        }  
    }  
    //...
     //创建请求Work对象
    Network network = new BasicNetwork(stack);  
    //创建请求队列
    RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);  
    //启动队列中的线程
    queue.start();  
    return queue;  
}
public void start() {  
    stop();  // 停止所有正在运行的
    // 创建缓存线程
    mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);  
    //启动缓存线程
    mCacheDispatcher.start();  
    // 创建网络线程,默认4个
    for (int i = 0; i < mDispatchers.length; i++) {  
        NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,  
                mCache, mDelivery);  
        mDispatchers[i] = networkDispatcher; 
        //启动网络线程 
        networkDispatcher.start();  
    }  
} 
public <T> Request<T> add(Request<T> request) {  
    //...
    //若果不需要缓存加入网络队列
    if (!request.shouldCache()) {  
        mNetworkQueue.add(request);  
        return request;  
    }  
    //加入缓存请求队列
    mCacheQueue.add(request);  
}

public class CacheDispatcher extends Thread { 
    public void run(){
      while(true){
          Cache.Entry entry = mCache.get(request.getCacheKey());  
                if (entry == null) {  
                    request.addMarker("cache-miss");  
                    // 缓存中没有近网络
                    mNetworkQueue.put(request);  
                    continue;  
                }  
           if (entry.isExpired()) {  
                    request.addMarker("cache-hit-expired");  
                    request.setCacheEntry(entry);  
                    //缓存过期近网络
                    mNetworkQueue.put(request);  
                    continue;  
                }  
            //有缓存,解析的结果,响应
            Response<?> response = request.parseNetworkResponse(  
                        new NetworkResponse(entry.data, entry.responseHeaders)); 
            mDelivery.postResponse(request, response);  
      }
    }
}
public class NetworkDispatcher extends Thread {  
    ……  
    @Override  
    public void run() {  
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
        Request<?> request;  
        while (true) {  
              //请求
              NetworkResponse networkResponse = mNetwork.performRequest(request);
              //解析
              Response<?> response = request.parseNetworkResponse(networkResponse);
            //响应
            mDelivery.postResponse(request, response);  
        }
    }
}
//切到主线程响应,ResponseDeliveryRunnable在主线程
//new Queue时ExecutorDelivery(new Handler(Looper.getMainLooper())也就是通过主线程Handler响应
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));  
  • android性能优化
  • apk瘦身
    1. 图片压缩
    2. Analyze - -> Run Inspection by Name --> 输入 unused resource 删除无用的资源文件
    3. minifyEnabled混淆代码,shrinkResources去除无用资源
    4. 使用Svg格式的图片
    5. AndResGuard(微信开源的打包工具)
    6. 大项目使用插件化技术
  • 数据库优化
    1. execSql省去了拼接sql语句的步骤,要比SqliteDatabase提供的insert,query,update,delete等函数效率高.但是有sql注入漏洞
    2. ContentValues和SQLiteStatement结合事务的方式进行操作。
  • 布局优化
    1. RelativeLayout > LinearLayout 因为前者减少View树层级,不过要注意只有或者一层时LinearLayout更好,因为RelativeLayout的onMeasure会执行两次测量而LinearLayout执行一次
    2. <include>:重用,但可能会有多余的嵌套
    3. <merge> </merge>:多用于替换FrameLayout,作为include不足的辅助,比如LinearLayout中用include时,里面也是LinearLayout时可用merge替代
    4. <ViewStub/> 这是个没有大小的轻量级View,指定layout属性,本质是View先GONE(因为gone的不加载)一般用来一开始不显示,再某些情况下才显示的View,例如无网络时。主要作用是减少加载布局时的浪费。
    5. ConstraintLayout使用。比RelativeLayout在层级的控制上更加灵活多功能。
    6. FlexboxLayout使用。FlexboxLayout是更高级的LinearLayout
    7. 使用hierarchyviewer工具分析布局问题
  • OOM优化-5R思想
    1. Reckon 计算(知道用了多少内存)
    2. Reduce 减少 (能用byte就别用long)
      a. 更加轻量的数据结构 ArrayMap SpareMap > HashMap
      b. android少用Enum,因为一个枚举值就是一个对象,耗内存。利用@interface+@IntDef/@StringDef替代enum
      c. Bitmap对象: 一张图内存=w * h * byte * desinty比^2
      d. 字符串拼接不用String
    3. Reuse 重用
      a. 列表ItemView复用
      b. 合理使用线程池
      c. LRU操控Bitmap
      d. onDraw中减少new 对象操作。draw中频繁new 容易内存抖动
    4. Recycle 回收
      a. bitmap回收
      b. 流的关闭,资源的释放如自定义View中TypeArray.recycle(),webview.destory()
      c. 灵活使用软 弱 引用
      d. 仿内存泄露(短不被长所引用,如静态context,静态view,单利持有context,activity中的异步内部类等)
    5. Review 检查
      a. LeakCanary
      b. studio 的 android profiler
  • ANR
    1. 条件:KeyDispatchTimeout >5s; BroadcastQueue Timeout > 10s; ContentProvider Timeout; Service Timeout > 20s
    2. 注意: UI线程中不做耗时工作。子线程执行耗时工作,子线程Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同。
    3. 分析: /data/anr/目录下生成trace.txt文件
  • 自定义View优化
    1. 降低刷新频率
      a. draw中少new或者不new对象
      b. 灵活运用invalidate(int l, int t, int r, int b),进行局部刷新
      c. 避免不必要的requestLayout
    2. 合理使用硬件加速:硬件加速适用于动画
      GPUs非常擅长某些任务,例如测量,翻转,和平移位图类的图片。特别地,他们不擅长其他的任务,例如画直线和曲线。为了利用GPU加速度类,你应该增加GPU擅长的操作数量,和减少GPU不擅长的操作数量。
    3. 状态的存储与恢复(onSaveInstanceState()+ onRestoreInstanceState)
  • 低版本SDK如何实现高版本api?
  1. 用@TargeApi($API_LEVEL) 使可以编译通过, 不建议使用@SuppressLint("NewApi");
  2. 编码中结合向下的兼容包,做好版本的判断,不同的版本使用不同的方式。
  • 描述一次网络请求的流程

http://blog.csdn.net/seu_calvin/article/details/53304406
DNS解析--建立TCP连接--发送请求--响应请求--解析请求结果

  • HttpUrlConnection 和 okhttp关系

从Android 4.4起, 其HttpURLConnection的内部实现已经变为OkHttp

  • Bitmap对象的理解

https://www.jianshu.com/p/3950665e93e6

  • final类 无修饰符构造器
  • 创建Bitmap = Bitmap.createBitmap() / BitmapFactory.decode()
  • 颜色Bitmap.Config 8--8888--4444--565(能满足且比8888少一半占用空间) 影响一个像素的占用的字节
  • 压缩Bitmap.CompressFormat JPEG(有损)-PNG(无损)-WEBP(有损,小但是耗时)
  • Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height,Matrix m, boolean filter)可裁剪,缩放,选装等
  • BitmapFactory.Options 压缩,优化减少OOM的概率
    inBitmap 复用
    inJustDecodeBounds true后false 减少一次想内存的加载得宽高
    inSampleSize 压缩计算
    inPurgeable 4.1后 用时加载,不用时回收
  • looper架构

https://www.jianshu.com/p/8656bebc27cb

消息机制运行图

  • ActivityThread,AMS,WMS的工作原理

  • 自定义View如何考虑机型适配

  • 自定义View的事件

  • AstncTask+HttpClient 与 AsyncHttpClient有什么区别?

  • LaunchMode应用场景

  • singleTop适合接收通知启动的内容显示页面。
  • singleTask适合作为程序入口点。
  • singleInstance适合需要与程序分离开的页面。
  • 请介绍下ContentProvider 是如何实现数据共享的?

http://blog.csdn.net/luoshengyang/article/details/6967204

  • 说说Activity、Intent、Service 是什么关系

Activity 跳转到 Activity,Activity 启动 Service,Service 打开 Activity
都需要 Intent 表明跳转 的意图,以及传递参数,Intent 是这些组件间信号传递的承载者。

  • SP是进程同步的吗?有什么方法做到同步?

https://www.jianshu.com/p/c15a63301592
在一个进程中,sharedPreference的commit apply都是原子操作。一般不会发生并发冲突。
在API Level>=11即Android 3.0可以通过Context.MODE_MULTI_PROCESS属性来实现SharedPreferences多进程共享。但是实际中然并卵,不靠谱。
解决方案还是建议换种进程间通讯方式

  • 谈谈多线程在Android中的使用
  1. Activity.runOnUiThread(Runnable)
  2. View.post(Runnable) ;View.postDelay(Runnable , long)
  3. Handler
  4. AsyncTask
  5. IntentService
  6. Thread
  • 进程和 Application 的生命周期
  • 前台进程 可见进程 服务进程 后台进程 空进程
  • onCreate onTerminate onLowMemory onConfigurationChanged
  • 封装View的时候怎么知道view的大小

onMearsure onSizeChanged

  • SurfaceView原理

http://blog.csdn.net/luoshengyang/article/details/8661317

  • RecycleView原理

https://blog.csdn.net/qq_23012315/article/details/50807224

  • RecyclerView的measure及layout过程委托给了RecyclerView.LayoutManager
  • 填充ItemView的算法为:向父容器增加子控件,测量子控件大小,布局子控件,布局锚点向当前布局方向平移子控件大小,重复上诉步骤至RecyclerView可绘制空间消耗完毕或子控件已全部填充。
  • ItemView的大小是包含这个位置偏移量的
  • 滑动过程=Scroller + Fling ,但是它们的实现最终其实是一样的
  • Recycler的作用就是重用ItemView,对于不同状态的ItemView存储在了不同的集合中,比如有scrapped、cached、exCached、recycled,当然这些集合并不是都定义在同一个类里。
  • RecyclerView.RecycledViewPool可以实现在不同的RecyclerView之间共享ItemView
  • 4种针对数据集的操作,分别是ADD、REMOVE、UPDATE、MOVE
  • AndroidManifest的作用与理解

http://www.cnblogs.com/liyuanjinglyj/p/manifest.html
https://blog.csdn.net/u012486840/article/details/52468931

  • <manifest>
    1. android:sharedUserId/android:sharedUserLabel : 共享用户id,能够用其它进程数据,甚至在其它进程运行
    2. android:installLocation 安装位置,【auto】 先内后外,【internalOnly】只内,【preferExternal】先外后内
  • <uses-permission>——应用程序的权限申请
  • <permission>节点——自定义应用程序的访问权限,用来限制对本应用程序或其他应用程序的特殊组件或功能访问。
  • <instrumentation>节点——应用的监控器,用于监控应用程序与系统交互,它会在应用程序组件实例化之前被实例化。这个节点在多数情况下用于单元测试。在studio中不怎么用了
  • <application>
    1. android:backupAgent: 自定义BackupAgent,备份代理,dmgr工具,BackupManager(备份管理器),BackupAgentHelper(SharedPreferencesBackupHelper和 FileBackupHelper)
    2. android:allowClearUserData:用户是否能选择自行清除数据
    3. android:allowTaskReparenting:是否允许activity更换从属的任务
    4. android:hasCode:APP是否包含任何的代码,自身不会含有任何的代码
    5. android:presistent:否应该在任何时候都保持运行状态,系统应用程序才是有意义的
    6. android:process:进程名,同名同sharedUserId才有意义
    7. android:taskAffinity:Activity任务栈名
  • <Activity>
    1. android:alwaysRetainTaskState:是否保留状态不变, 比如切换回home
    2. ...
  • intent-filter
    1. android:priority:优先级
    2. 里面有 action category data(meta-data)
  • <activity-alias> 是为activity创建快捷方式的,可用于动态更换桌面图标
  • < Provider >
    1. android:authorities:标识这个ContentProvider,调用者可以根据这个标识来找到它
  • <supports-screens> 在android1.6以后的新特性,支持多屏幕机制
  • uses-configuration 与uses-feature:这两者都是在描述应用所需要的硬件和软件特性,以便防止应用在没有这些特性的设备上安装。

常见的一些原理性问题

  • Handler机制和底层实现

https://www.jianshu.com/p/7147cf9b1181

  • HandlerThread和IntentService的差别

https://www.jianshu.com/p/8e701624cfbb

  • 关于Handler,在任何地方new Handler 都是什么线程下?

主线程 new Handler 因为ActivityThread中的Looper.prepareMainLooper();+Looper.loop();所以会在主线程执行
在子线程中 new Handler 如果没有执行Looper.preare()则会抛出Can't create handler inside thread that has not called Looper.prepare()异常,如果调用了,则在子线程

  • ThreadLocal原理,实现及如何保证Local属性?

https://blog.csdn.net/androidzhaoxiaogang/article/details/6788489

  1. 概述:当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
  2. ThreadLocal【ThreadLocalMap【Entry数组】】,Thread中持有一个ThreadLocalMap。
  3. 1.8中 Thread中有一个ThreadLocalMap,ThreadLocal中set代码如下:
    public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            //map中的key是当前Thread所对应的ThreadLocalMap本身
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
    
    ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
                table = new Entry[INITIAL_CAPACITY];//持有一个Entry数组
                int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);//数组的索引为key的HasCode的原子运算,nextHashCode.getAndAdd(HASH_INCREMENT),其中nextHashCodeAtomicInteger
                table[i] = new Entry(firstKey, firstValue);
                size = 1;
                setThreshold(INITIAL_CAPACITY);
    

}

  • 请描述一下View事件传递分发机制

https://blog.csdn.net/carson_ho/article/details/54136311

Activity 事件分发机制

ViewGroup 事件分发机制

View 事件分发机制

事件分发流程

  • View刷新机制

https://www.jianshu.com/p/0d00cb85fdf3

  • View绘制流程

https://blog.csdn.net/yanbober/article/details/46128379/
起点:Activity.handleLaunchActivity中performLaunchActivity后handleResumeActivity中performResumeActivity后activity.makeVisible()中WindowManagerImp.addView中WindowManagerGlobal.addView中ViewRootImpl.setView中requestLayout()中scheduleTraversals中mTraversalRunnable.run中doTraversal中performTraversals();

  • 自定义ViewGroup不走onDraw的原理

https://blog.csdn.net/hb8676086/article/details/52059993

if (!dirtyOpaque) onDraw(canvas); 
final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) == DIRTY_OPAQUE &&(mAttachInfo== null||!mAttachInfo.mIgnoreDirtyState);
protected void computeOpaqueFlags() {
        // Opaque if://不透明的条件
        //   - Has a background  有 background
        //   - Background is opaque 背景是不透明
        //   - Doesn't have scrollbars or scrollbars overlay 没有滚动条或滚动条覆盖
}
//原因 LinearLayout构造方法中调用了setWillNotDraw(true),增加了WILL_NOT_DRAW标志
//解决方案
// 指定background
// 构造器setWillNotDraw(false)
  • 自定义View如何提供获取View属性的接口?

回调

  • Android代码中实现WAP方式联网

https://blog.csdn.net/seu_calvin/article/details/53305034

  • AsyncTask机制

https://www.jianshu.com/p/817a34a5f200

  • AsyncTask原理及不足
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();//队列
/**
*  CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//核心线程数 2~4
* MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
* KEEP_ALIVE_SECONDS = 30;
*/
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;//线程池
public AsyncTask(@Nullable Handler handler) {}//Handler

默认串行,一个一个执行。并行需手动executeOnExecutor
没有生命周期关联,容易已发内存泄露,可能会导致结果丢失

  • 如何取消AsyncTask?
// 对任务的处理,立即终止,还是先完成当前的
public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
    }
  • 为什么不能在子线程更新UI?

ViewRootImple中requestLayout方法

@Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }
  • ANR产生的原因是什么?

activity > 5s
BroadcastReceiver > 10s
Service > 20s

  • oom是什么?

https://blog.csdn.net/caster_saber/article/details/52494984

  • Oom 是否可以try catch?为什么?

如果OOM的原因不是try语句中的对象(比如内存泄漏),那么在catch语句中会继续抛出OOM

  • 内存泄漏

https://www.jianshu.com/p/bf159a9c391a

Leakcanary源码分析
https://blog.csdn.net/cloud_huan/article/details/53081120

  • LeakCanay的入口是在application的onCreate()方法中声明的,其实用的就是Application的ActivityLifecycleCallbacks回调接口监听所有activity的onDestory()的,在这个方法进行RefWatcher.watch对这个对象进行监控。
  • 具体是这样做的,封装成带key的弱引用对象,然后GC看弱引用对象有没有回收,没有回收的话就怀疑是泄漏了,需要二次确认。然后生成HPROF文件,分析这个快照文件有没有存在带这个key值的泄漏对象,如果没有,那么没有泄漏,否则找出最短路径,打印给我们,我们就能够找到这个泄漏对象了。
  • LruCache

https://blog.csdn.net/maosidiaoxian/article/details/51393753

  • LRU 最近最少使用,ABCBDCACA 最近最少使用的是B,第一个距离最后的A最远
  • 数据结构,双向循环列表
    1. this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
    2. accessOrder是指定它的排序方式,当它为false时,只按插入的顺序排序,即新放入的顺序会在链表的尾部;而当它为true时,更新或访问某个节点的数据时,这个对应的结点也会被放到尾部。
    3. public Entry<K, V> eldest(),它返回的是最老的结点,当accessOrder为true时,也就是最近最少使用的结点。


      image
  • ContentProvider的权限管理(解答:读写分离,权限控制)

https://blog.csdn.net/anddlecn/article/details/51733690
https://blog.csdn.net/hb8676086/article/details/50164947

//A声明
<provider  
    android:name=".PeopleContentProvider"  
    android:authorities="com.harvic.provider.PeopleContentProvider"  
    android:exported="true"  
    android:permission="com.harvic.contentProviderBlog"  
    android:readPermission="com.harvic.contentProviderBlog.read"  
    android:writePermission="com.harvic.cotentProviderBlog.write"/>  
//A定义,同级处定义
<permission  
    android:name="com.harvic.contentProviderBlog.read"  
    android:label="provider pomission"  
    android:protectionLevel="normal" /> 
....
//B使用者要声明有 A定义的权限
<uses-permission android:name="com.harvic.contentProviderBlog.read"/>

  • Uri、UriMatcher、ContentUris详解

https://blog.csdn.net/feng88724/article/details/6331396

//Uri 通用资源标志符
//content ---scheme 
//com.example.testcp.FirstContentProvider -- android:authorities 主机
// users ---path 路径
Uri uri = Uri.parse("content://com.example.testcp.FirstContentProvider/users")

// UriMatcher 匹配Uri
//初始化
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);  
//注册需要的Uri:
matcher.addURI("com.yfz.Lesson", "people", PEOPLE);  
matcher.addURI("com.yfz.Lesson", "person/#", PEOPLE_ID);  
//匹配
Uri uri = Uri.parse("content://" + "com.yfz.Lesson" + "/people");  
//match方法匹配后会返回一个匹配码Code,即在使用注册方法addURI时传入的第三个参数。
int match = matcher.match(uri);  
       switch (match)  
       {  
           case PEOPLE:  
               return "vnd.android.cursor.dir/people";  
           case PEOPLE_ID:  
               return "vnd.android.cursor.item/people";  
           default:  
               return null;  
       }

// ContentUris 操作Uri
Uri uri = Uri.parse("content://com.yfz.Lesson/people") 
//添加id:操作后结果为:content://com.yfz.Lesson/people/10
Uri resultUri = ContentUris.withAppendedId(uri, 10);
//获取id  下面结果为personid = 10
Uri uri = Uri.parse("content://com.yfz.Lesson/people/10")  
long personid = ContentUris.parseId(uri); 
  • 如何通过广播拦截和abort一条短信?
ublic class SmsReceiver extends BroadcastReceiver {
        // 当接收到短信时被触发
        @Override
        public void onReceive(Context context, Intent intent) {
            // 如果是接收到短信
            if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
                // 取消广播(这行代码将会让系统收不到短信)
                abortBroadcast();
                StringBuilder sb = new StringBuilder();
                // 接收由SMS传过来的数据
                Bundle bundle = intent.getExtras();
                // 判断是否有数据
                if (bundle != null) {
                    // 通过pdus可以获得接收到的所有短信消息
                    Object[] pdus = (Object[]) bundle.get("pdus");
                    // 构建短信对象array,并依据收到的对象长度来创建array的大小
                    SmsMessage[] messages = new SmsMessage[pdus.length];
                    for (int i = 0; i < pdus.length; i++) {
                        messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
                    }
                    // 将送来的短信合并自定义信息于StringBuilder当中
                    for (SmsMessage message : messages) {
                        sb.append("短信来源:");
                        // 获得接收短信的电话号码
                        sb.append(message.getDisplayOriginatingAddress());
                        sb.append("\n------短信内容------\n");
                        // 获得短信的内容
                        sb.append(message.getDisplayMessageBody());
                    }
                }
                Toast.makeText(context, sb.toString(), 5000).show();
            }
        }
    }
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<receiver android:name=".SmsReceiver" >

            <intent-filter android:priority="800" >

                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
</receiver>
  • 广播是否可以请求网络?
    // 4.0后网络都要子线程,而广播在主线程

  • 广播引起anr的时间限制是多少?
    //10s

  • 计算一个view的嵌套层级

int i = 0;
    private void getParents(ViewParent view){

        if (view.getParent() == null) {
            Log.v("tag", "最终==="+i);
            return;
        }
        i++;
        ViewParent parent = view.getParent();
        Log.v("tag", "i===="+i);
        Log.v("tag", "parent===="+parent.toString());

        getParents(parent);
    }
  • Activity栈

https://blog.csdn.net/csdn_of_coder/article/details/76343031

  • Android线程有没有上限?

开线程无上限,就是开的越多,程序耗内存越大/逻辑越混乱,很容易挂掉

  • 线程池有没有上限?

自由指定

  • ListView重用的是什么?

https://blog.csdn.net/xiaogutou1/article/details/47136099
活动视图池,废弃视图池,临时视图池,删除视图池

  • Android为什么引入Parcelable?
  • 一、对象为什么需要序列化
    1.永久性保存对象,保存对象的字节序列到本地文件。
    2.通过序列化对象在网络中传递对象。
    3.通过序列化对象在进程间传递对象。
  • 二、当对象需要被序列化时如何选择所使用的接口
    1.在使用内存的时候Parcelable比Serializable的性能高。Serializable中有大量io操作。
    2.Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC(内存回收)。
    3.Parcelable不能使用在将对象存储在磁盘上这种情况,因为在外界的变化下Parcelable不能很好的保证数据的持续性。
  • 有没有尝试简化Parcelable的使用?

kotlin使用Parcelize注解简化Parcelable的书写

@Parcelize
data class Student(val id: String, val name: String, val grade: String) : Parcelable

开发中常见的一些问题

  • ListView图片加载错乱的原理和解决方案

https://blog.csdn.net/a394268045/article/details/50726560

  • 混合开发有了解吗?

?

  • 知道哪些混合开发的方式?说出它们的优缺点和各自使用场景?(解答:比如:RN,weex,H5,小程序,WPA等。做Android的了解一些前端js等还是很有好处的);

  • 屏幕适配的处理技巧都有哪些?

https://www.jianshu.com/p/ec5a1a30694b

  • 服务器只提供数据接收接口,在多线程或多进程条件下,如何保证数据的有序到达?

?
类似AsyncTask的思路,一个线程池中同一时间只能执行一个线程,基于一个队列,在上一个线程没有return前,不执行其它线程

  • 动态布局的理解

http://www.jb51.net/article/77875.htm
代码的方式创建布局组件

  • 怎么去除重复代码?

粒度最小化

  • 画出 Android 的大体架构图
image
  • Recycleview和ListView的区别

https://blog.csdn.net/qq_28851933/article/details/54889921

  • 动态权限适配方案,权限组的概念

https://www.cnblogs.com/dubo-/p/6018262.html

  • Android系统为什么会设计ContentProvider?

https://blog.csdn.net/wuxinliulei/article/details/9995729

  • 下拉状态栏是不是影响activity的生命周期

Android下拉通知栏不会影响Activity的生命周期方法

  • 如果在onStop的时候做了网络请求,onResume的时候怎么恢复?
  • 没onDestory就不会断。onResume中也就无需恢复。再说也不建议在onStop中进行网络请求。太耗时不行。如果用线程,则在onDestory中不取消线程就就不会终端,但会导致内存泄露。如果是在主线程中现在直接就不允许。
  • Bitmap 使用时候注意什么?

先预加载,压缩,用完回收,列表中进行缓存复用

  • onSaveInstanceState机制

https://blog.csdn.net/qq_23547831/article/details/51464535

  • onSaveInstanceState方法是Activity的生命周期方法,主要用于在Activity销毁时保存一些信息。
    *当Activity只执行onPause方法时(Activity a打开一个透明Activity b)这时候如果App设置的targetVersion大于android3.0则不会执行onSaveInstanceState方法。
  • 当Activity执行onStop方法时,通过分析源码我们知道调用onSaveInstanceState的方法直接传值为true,所以都会执行onSaveInstanceState方法。
  • Bitmap的recycler()

  • Android中开启摄像头的主要步骤

获得摄像头Feature和写文件的权限
启动Intent进行拍照
在onActivityResult回调函数里面,对图片进行处理

  • ViewPager使用细节,如何设置成每次只初始化当前的Fragment,其他的不初始化?

https://www.jianshu.com/p/2b5a177ea67d

  • 点击事件被拦截,但是想传到下面的View,如何操作?

view..getParent().requestDisallowInterceptTouchEvent(true);

  • 微信主页面的实现方式

ViewPager+Fragment+ViewGroup

  • 微信上消息小红点的原理

MsgView

推荐阅读更多精彩内容