Android一些小知识整理,用于面试

如果你想看Android源码,强无敌,so,c++,jni,java都有

1. Android生命周期大家都知道,但你知道什么时候走onStop和onPuase,onDestory么,区别呢?

来自网络图片

Activity的活动状态与Activity在栈中的位置有密切的关系,而且,Android在系统资源不足的时候,也是从Activity栈中选择哪些Activity是可以终止的,一般来讲,Activity系统会优先选择终止处于目前是停止状态并且比较靠近Activity栈底的Activity。
也就是说onDestory并不是那么快,那为什么我应用总onStop直接onDestory呢,因为你项目越是庞大,需求的资源就越多,所以系统认为需要GC。

结合实例:
Activity的生命周期是指Activity从启动到销毁的过程。


来自网络图片

Activity有四种状态:活动状态 暂停状态 停止状态 非活动状态


来自网络图片

先看下Actvity的七个生命周期函数以及说下这几个函数都是在什么时候调用的:
来自网络图片
  • 那么说明onDestory并不是来得飞快
  • 那么说明onStop只有被全部遮挡,就调用
  • 那么说明onPause只要被遮挡,就调用(除了几个特殊)
    • 1.锁屏的时候,会依次调用onPause()和onStop()。
    • 2.Toast、Dialog、Menu,三者都不会使Activity调用onPause()
    • 3.一个非全屏的Activity在前面时,后面的Activity只调用onPause()

再补充一点:这篇文章很赞,两个activity切换生命周期你真懂么?
再扩展发下思维:不同生命时期,调用finish会发生啥

出自:深入理解Android(2)邓平凡

出自:深入理解Android(2)邓平凡

出自:深入理解Android(2)邓平凡
出自:深入理解Android(2)邓平凡
出自:深入理解Android(2)邓平凡

结合前面知识你应用很清楚认识到这个启动的流程的生命周期了。
再总结下:


出自:深入理解Android(2)邓平凡

2. Actvity启动你了解过底层么,流程大致呢,继承Actvity,自己是否一定要实现oncreate的方法?

转载:Android Application启动流程分析
凡是涉及父类源码中要调用getApplication().dispatchActivityXXX(this)时要重写super.XXX(),因为这是binder回调过程,需要通知和更新当前生命周期。当然binder还要回馈给远端System Server

3. Android官方优化工具会用么,区别呢?

转载:App优化之性能分析工具

  • 本人只会用Traceview而且很好用,分析方法调用栈以及其执行时间, 优化方法执行。绝大部分是优化时间效率
  • 控件树的优化,其实你在开发需求的时候就定死,你不可能脑残到循环嵌套那么多层,用Hierarchy Viewer查看把深度的控件树,变成广度控件树能提升。Hierarchy Viewer在ddms中其他window中,能单步反应出每个控件的效率在相对这棵树的情况,保持绿色小圆点最优,保持16ms渲染速度,3个小圆点,Measure, Layout, Draw,保持draw在10ms以下基本最优。
    你要有个概念GPU和CPU,你布局逻辑计算是CPU完成的,GPU只是贴图和栅格化,主线程拿不到CPU片断你也会掉帧。
    什么是掉帧,源码是SurfaceFlinger真正绘制,发送Vsync通过Choreographer不停的loop向主线程,16ms一次,其中就被阻塞,如果当次在16ms没有绘制完,系统发出的Vsync没有得到回收,该帧被丢弃,等待下一个Vsync才开始绘制,导致了可能在16ms*2内显示同一个画面,这就是卡顿的原因。
    推荐个很牛的博客,底层分析
    来自网络图片
  • 还有内存和oom,这个本人使用LeackCanary和Memory Monitor去分析了,大量的GC,内存波动,你就要想这个需求是否正确了,LeackCanary会报很多GC不能回收的错误,debug时候开启它,尽量在开发时候就解决,到后期优化,你要跳楼的。LeackCanary生成内存分析报文hrof文件,在as中直接查看,如果你想忽略其中报错,加入LeackCanary白名单代码map,或者
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
   @Override
   public void handleMessage(Message msg) {
       super.handleMessage(msg);
   }
};

关于LeackCanary抓取回收dump文件过程,不详细介绍,网上一大把。
大致:Application ====》install()====》LeackCanary:RefWatcher这货去监听了Context的生命周期回调
AndroidWatchExextor线程处理收集信息 =====》Dump文件 ====》回调DumpService中Listener去刷新界面和通知栏
1.RefWactcher.watch()会监控对象来创建一个keyedweadkRerence弱引用对象。
2.在AndroidWatchExextor后台线程来检查弱引用的对象被请出没有,如果没有,GC一次,然后再看
3.如果没有干掉说明,内存泄露,系统导出hprof文件
所有的强引用是链接在GC树上的,只有瞬时的对象和临时对象会自动回收不在链接树。
GC ROOT 你没有懂?看这个,我第一次就瞬间懂了

4. Android生命周期长短比较?

getApplicationContext()(全局appliction的上下文) > getApplication()(全局appliction对象) > this(context)

关于上面错误感谢评论区:lockeez童鞋指针,错误我先留这了,大家利用评论区,学习总结下。
每个Application对应于子进程创建次数,都会调用onCreate(),Application和Service一样没有onResume

5. JobServices?

在android7.0以后谷歌官方推荐用JobServices做调度作业,起到优化作用。
在以下场景很适用:
1.最小延时 2.是否空闲
3.是否有网络 4.最晚执行
5.是否充电。
满足之一,需要调用权限。

6. AsyncTaskLoader和AsyncTask?

区别于AsyncTask一般做数据查询,在Activity配置没有改变,只更新数据源,loader用来开启异步任务加载数据库或者Uri数据,只支持不耗时操作。

7. Android进程优先级你真了解完全了?

命令查看进程
补充优先级和拉活知识
据说手Q,保持活就是前台一个像素activity
再补充一句,adb shell 默认端口你了解过么,5037!
adb shell dumpsys activity top 获取最上层的Activity

8. 非UI线程能更新UI?

非UI线程能更新UI,只要它有自己的ViewRoot。因为,报错是报,你的view不在原来的线程。
转载:Android子线程真的不能更新UI么

9. Activity启动模式小知识

  • 1.不同TaskAffiny和不同进程都能StartActivityForResult回调,这个过程谷歌官方说是安全的,就调用相机,一定会有回掉,但数据有没有不能保证。但!,很重要一点,除了singleTop或者singleInstance特殊,activityA 通过startActivityForResult()方法来启动另一个ActivtyB,那么系统将直接返回Activity.Result_Canceled而不会继续等待。这是由于FrameWork曾对2者做的限制,不同Task之间,默认是不能传递数据的,如果你需要,那就Intent。
  • 2.getApplicationContext()能不能startActivity()?可以的。
    在ContextImpl.startActivity方法中,那我们去看下其源码,如下:
    @Override
    public void startActivity(Intent intent, Bundle options) {
        warnIfCallingFromSystemProcess();
        // 就是下面这个检测干的好事!!!
        if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
            throw new AndroidRuntimeException(
                    "Calling startActivity() from outside of an Activity "
                    + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                    + " Is this really what you want?");
        }
        mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null,
                (Activity) null, intent, -1, options);
    }

通过上面的源码我们发现了问题的根本原因,要fix这个问题也很简单,添加如下代码intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);即可。

  • 3.onActivityResult特性:
/**
     * Called when an activity you launched exits, giving you the requestCode
     * you started it with, the resultCode it returned, and any additional
     * data from it.  The <var>resultCode</var> will be
     * {@link #RESULT_CANCELED} if the activity explicitly returned that,
     * didn't return any result, or crashed during its operation.
     *
     * <p>You will receive this call immediately before onResume() when your
     * activity is re-starting.
     *
     * <p>This method is never invoked if your activity sets
     * {@link android.R.styleable#AndroidManifestActivity_noHistory noHistory} to
     * <code>true</code>.
     *
     * @param requestCode The integer request code originally supplied to
     *                    startActivityForResult(), allowing you to identify who this
     *                    result came from.
     * @param resultCode The integer result code returned by the child activity
     *                   through its setResult().
     * @param data An Intent, which can return result data to the caller
     *               (various data can be attached to Intent "extras").
     *
     * @see #startActivityForResult
     * @see #createPendingResult
     * @see #setResult(int)
     */
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    }

也就是说,如果你给requestCode并且大于0,那么就会有数据返回,这和底层binder通信有关,非oneway的形式。如果返回没有结果,或者崩溃了在传递过程中,resultCode将等于RESULT_CANCELED。这个过程是onResume之前的。如果你的activity在AndroidManifest设置了noHistory为true,将不会有回调。

10. Bitmap用完一定要bitmap.recycle()么?

不需要,你调用也没有错,自动Android 3.0之后,由于Bitmap放到java heap上,其内存有GC管理,之前版本是在系统Native上的。

11.Android中为什么主线程不会因为Looper.loop()里的死循环卡死?

  • 也就是说,Android本身主线程是带阻塞的,然而又为什么不会卡界面其他响应呢,因为是Android系统操作会绘制是事件驱动行的,每次做个操作或者完成绘制,改变状态是一个事件Post到主线程的,然后继续运行,休眠。
  • 再补充一点为什么ActivityThread本身是一个普通类,不是Runnable和Thread怎么实现线程机制和界面刷新的。在ActivityThread::main()===>attach()中完成了looper创建和ViewRootImpl创建(这就上面第8点的疑惑)
  • 其中会引入一个IdleHandler问题,什么叫空闲线程Handler,它就是在你这线程cpu空虚的时候干点脏活,如释放资源,打印log
    内容太多,简单描述就是,干完以后就休眠MessageQueue
  • 这篇介绍了额外的内容,关于C++底层监控

补充内容:为什么Android的Handler采用管道而不使用Binder?,Binder底层和Handler底层实现是一样的,管道操作文件描述符的句柄,使用epoll往其中内存地址空间写数据。只是Binder比管道更加繁重,有Binder驱动完成跨进程,找到对应端口。而管道只支持线程通信,因为他操作的地址是固定的,一端写入一端写出,跨进程是需要拷贝数据到目标进程的。反过来可以,看链接描述。

这张图能很好说明,跨进程机制

12.Activity4种启动模式都知道了?那么有2个同是singleInstance并且taskAffinity相同会这样呢?

没有任何关系,启动后打印TaskId还是不同的idx。

        <activity
            android:name="com.example.aaa.a1"
            android:label="@string/app_name"
            android:taskAffinity="c.aaaa"
            android:launchMode="singleInstance">
        </activity>

        <activity
            android:name="com.example.aaa.a2"
            android:label="@string/app_name"
            android:taskAffinity="c.aaaa"
            android:launchMode="singleInstance">
        </activity>

13.bind启动的service,当调用者finish掉后,会真的调用onUnbind么?

会,亲测demo

    @Override
    Activity :: protected void onCreate(Bundle savedInstanceState) {
        Intent intent = new Intent(this, a.class);
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                AppActivity.this.finish();
            }
        });

    @Override
    Service :: public boolean onUnbind(Intent intent) {
        Toast.makeText(this, "exit", Toast.LENGTH_SHORT).show();
        return super.onUnbind(intent);
    }

你可能不知道IntentService和Service真正区别。让一次性简单记住,IntentService是只能塞进去去完成任务,做完就unbind了,所以你就认为一次性的。Service复杂点,能查询也能做,IntentService只能做,不能记住状态去查询。

14你知道ViewRootImpl何时调用第一次performTraversals()?

出自 我简短了大部分,用来回答我问题,其他懂的,可以不看。
handleResumeActivity在收到AMS代理远程对象的Scaule后开始。
performLaunchActivity函数完成了两件事:

  • 1 Activity窗口对象的创建,通过attach函数来完成;
  • 2 Activity视图对象的创建,通过setContentView函数来完成;

这些准备工作完成后,就可以显示该Activity了,应用程序进程通过调用handleResumeActivity函数来启动Activity的显示过程。

看addView()

frameworks\base\core\java\android\app\ ActivityThread.java

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {  
    unscheduleGcIdler();  
    ActivityClientRecord r;  
    try {  
        ①r = performResumeActivity(token, clearHide);  
    } catch (Exception e) {  
        ...  
    }  
    if (r != null) {  
        final Activity a = r.activity;  
        ...  
        if (r.window == null && !a.mFinished && willBeVisible) {  
            //获得为当前Activity创建的窗口PhoneWindow对象  
            r.window = r.activity.getWindow();  
            //获取为窗口创建的视图DecorView对象  
            View decor = r.window.getDecorView();  
            decor.setVisibility(View.INVISIBLE);  
            //在attach函数中就为当前Activity创建了WindowManager对象  
            ViewManager wm = a.getWindowManager();  
            //得到该视图对象的布局参数  
            ②WindowManager.LayoutParams l = r.window.getAttributes();  
            //将视图对象保存到Activity的成员变量mDecor中  
            a.mDecor = decor;  
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;  
            if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {  
                l.idleScreenAvailable = true;  
            } else {  
                l.idleScreenAvailable = false;  
            }  
            l.softInputMode |= forwardBit;  
            if (a.mVisibleFromClient) {  
                a.mWindowAdded = true;  
                //将创建的视图对象DecorView添加到Activity的窗口管理器中  
                ③wm.addView(decor, l);  
            }  
        } else if (!willBeVisible) {  
            ...  
        }  
        ...  
        if (!r.onlyLocalRequest) {  
            r.nextIdle = mNewActivities;  
            mNewActivities = r;  
            Looper.myQueue().addIdleHandler(new Idler());  
        }  
        ...  
    } else {  
        ...  
    }  
}  

在前面的performLaunchActivity函数中完成Activity的创建后,会将当前当前创建的Activity在应用程序进程端的描述符ActivityClientRecord以键值对的形式保存到ActivityThread的成员变量mActivities中:mActivities.put(r.token, r),r.token就是Activity的身份证,即是IApplicationToken.Proxy代理对象,也用于与AMS通信。上面的函数首先通过performResumeActivity从mActivities变量中取出Activity的应用程序端描述符ActivityClientRecord,然后取出前面为Activity创建的视图对象DecorView和窗口管理器WindowManager,最后将视图对象添加到窗口管理器中。

来自网络图片

我们知道Activity引用的其实是轻量级的窗口管理器LocalWindowManager

frameworks\base\core\java\android\view\ Window.java

public final void addView(View view, ViewGroup.LayoutParams params) {  
    WindowManager.LayoutParams wp = (WindowManager.LayoutParams)params;  
    CharSequence curTitle = wp.getTitle();  
    //应用程序窗口  
    if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&  
        wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {  
        if (wp.token == null) {  
            View decor = peekDecorView();  
            if (decor != null) {  
                // LayoutParams 的token设置为W本地Binder对象  
                wp.token = decor.getWindowToken();  
            }  
        }  
        if (curTitle == null || curTitle.length() == 0) {  
            //根据窗口类型设置不同的标题  
            …  
            if (mAppName != null) {  
                title += ":" + mAppName;  
            }  
            wp.setTitle(title);  
        }  
    } else {//系统窗口  
        if (wp.token == null) {  
            wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;  
        }  
        if ((curTitle == null || curTitle.length() == 0)  
                && mAppName != null) {  
            wp.setTitle(mAppName);  
        }  
    }  
    if (wp.packageName == null) {  
        wp.packageName = mContext.getPackageName();  
    }  
    if (mHardwareAccelerated) {  
        wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;  
    }  
    super.addView(view, params);  
}  

看setView()

frameworks\base\core\java\android\view\WindowManagerImpl.java

private void addView(View view, ViewGroup.LayoutParams params,  
        CompatibilityInfoHolder cih, boolean nest) {  
    ...  
    final WindowManager.LayoutParams wparams= (WindowManager.LayoutParams)params;  
    ViewRootImpl root;  
    View panelParentView = null;  
    synchronized (this) {  
        ...  
        //从mViews中查找当前添加的View  
        int index = findViewLocked(view, false);  
        //如果已经存在,直接返回  
        if (index >= 0) {  
            ...  
            return;  
        }  
        //尚未添加当前View  
        if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&  
                wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {  
            final int count = mViews != null ? mViews.length : 0;  
            for (int i=0; i<count; i++) {  
                if (mRoots[i].mWindow.asBinder() == wparams.token) {  
                    panelParentView = mViews[i];  
                }  
            }  
        }  
        //为Activity创建一个ViewRootImpl对象  
        ①root = new ViewRootImpl(view.getContext());  
        ...  
        //设置视图组件的布局参数  
        view.setLayoutParams(wparams);  
        if (mViews == null) {  
            index = 1;  
            mViews = new View[1];  
            mRoots = new ViewRootImpl[1];  
            mParams = new WindowManager.LayoutParams[1];  
        } else {  
            //动态增加mViews数组长度  
            index = mViews.length + 1;  
            Object[] old = mViews;  
            mViews = new View[index];  
            System.arraycopy(old, 0, mViews, 0, index-1);  
            //动态增加mRoots数组长度  
            old = mRoots;  
            mRoots = new ViewRootImpl[index];  
            System.arraycopy(old, 0, mRoots, 0, index-1);  
            //动态增加mParams数组长度  
            old = mParams;  
            mParams = new WindowManager.LayoutParams[index];  
            System.arraycopy(old, 0, mParams, 0, index-1);  
        }  
        index--;  
        ②mViews[index] = view;  
        mRoots[index] = root;  
        mParams[index] = wparams;  
    }  
    try {  
        ③root.setView(view, wparams, panelParentView);   
    } catch (RuntimeException e) {  
        ...  
    }  
}  

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {  
    synchronized (this) {  
        if (mView == null) {  
            //将DecorView保存到ViewRootImpl的成员变量mView中  
            mView = view;  
            mFallbackEventHandler.setView(view);  
            mWindowAttributes.copyFrom(attrs);  
            attrs = mWindowAttributes;  
            mClientWindowLayoutFlags = attrs.flags;  
            setAccessibilityFocus(null, null);  
            //DecorView实现了RootViewSurfaceTaker接口  
            if (view instanceof RootViewSurfaceTaker) {  
                mSurfaceHolderCallback =  
                        ((RootViewSurfaceTaker)view).willYouTakeTheSurface();  
                if (mSurfaceHolderCallback != null) {  
                    mSurfaceHolder = new TakenSurfaceHolder();  
                    mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);  
                }  
            }  
            ...  
            //同时将DecorView保存到mAttachInfo中  
            mAttachInfo.mRootView = view;  
            mAttachInfo.mScalingRequired = mTranslator != null;  
            mAttachInfo.mApplicationScale = mTranslator == null ? 1.0f : mTranslator.applicationScale;  
            if (panelParentView != null) {  
                mAttachInfo.mPanelParentWindowToken  
                        = panelParentView.getApplicationWindowToken();  
            }  
            ...  
            //在添加窗口前进行UI布局  
            ①requestLayout();  
            if ((mWindowAttributes.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {  
                mInputChannel = new InputChannel();  
            }  
            try {  
                mOrigWindowType = mWindowAttributes.type;  
                mAttachInfo.mRecomputeGlobalAttributes = true;  
                collectViewAttributes();  
                //将窗口添加到WMS服务中,mWindow为W本地Binder对象,通过Binder传输到WMS服务端后,变为IWindow代理对象  
                ②res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,  
                        getHostVisibility(), mAttachInfo.mContentInsets,  
                        mInputChannel);  
            } catch (RemoteException e) {  
                ...  
            }  
            ...  
            //建立窗口消息通道  
            if (view instanceof RootViewSurfaceTaker) {  
                mInputQueueCallback =  
                    ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();  
            }  
            if (mInputChannel != null) {  
                if (mInputQueueCallback != null) {  
                    mInputQueue = new InputQueue(mInputChannel);  
                    mInputQueueCallback.onInputQueueCreated(mInputQueue);  
                } else {  
                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());  
                }  
            }  
            ...  
        }  
    }  
}  

public void requestLayout() {  
    //检查当前线程是否是UI线程  
    checkThread();  
    //标识当前正在请求UI布局  
    mLayoutRequested = true;  
    scheduleTraversals();  
} 

void scheduleTraversals() {  
    if (!mTraversalScheduled) {  
        mTraversalScheduled = true;  
        //暂停UI线程消息队列对同步消息的处理  
        mTraversalBarrier = mHandler.getLooper().postSyncBarrier();  
        //向Choreographer注册一个类型为CALLBACK_TRAVERSAL的回调,用于处理UI绘制  
        mChoreographer.postCallback(  
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);  
        //向Choreographer注册一个类型为CALLBACK_INPUT的回调,用于处理输入事件  
        scheduleConsumeBatchedInput();  
    }  
}  

final TraversalRunnable mTraversalRunnable = new TraversalRunnable();  
final class TraversalRunnable implements Runnable {  
        @Override  
        public void run() {  
            doTraversal();  
        }  
}  

void doTraversal() {  
    if (mTraversalScheduled) {  
        mTraversalScheduled = false;  
        mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);  
        if (mProfile) {  
            Debug.startMethodTracing("ViewAncestor");  
        }  
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");  
        try {  
            performTraversals();  
        } finally {  
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);  
        }  
        if (mProfile) {  
            Debug.stopMethodTracing();  
            mProfile = false;  
        }  
    }  
} 

ViewRootImpl的setView函数向WMS服务添加一个窗口对象过程:

  • 1 requestLayout()在应用程序进程中进行窗口UI布局;
  • 2 WindowSession.add()向WMS服务注册一个窗口对象;
  • 3 注册应用程序进程端的消息接收通道;
    这就是为什么你在OnReume一开始调用View的高宽拿不到,postRunnale以后能拿到,因为doTraversal()在Post栈顶,等它跑完就能拿到数值了。
    补充硬件加速原理

对View补充一些知识






出自Android开发艺术探索-4.3.1章

15 Android在应用层有3种信号你知道么?

public static final int SIGNAL_QUIT = 3; // 追踪日志
public static final int SIGNAL_KILL = 9; // Process::killProcess()应用比较多
public static final int SIGNAL_USR1 = 10; // 用于强制执行GC

理解杀进程的实现原理

16 Intent和PendingIntent?

Android中pendingIntent的深入理解

  • Intent是立即使用的,而PendingIntent可以等到事件发生后触发,PendingIntent可以cancel
  • Intent在程序结束后即终止,而PendingIntent在程序结束后依然有效
  • PendingIntent自带Context,而Intent需要在某个Context内运行
  • Intent在原task中运行,PendingIntent在新的task中运行

PendingIntent还要注意其中flag,因为他是有内核收集器,像Map一样

public final class PendingIntent implements Parcelable {
       /** @hide */
       @IntDef(flag = true, //======================flag值=============================
            value = {
                    FLAG_ONE_SHOT,
                    FLAG_NO_CREATE,
                    FLAG_CANCEL_CURRENT,
                    FLAG_UPDATE_CURRENT,

                    Intent.FILL_IN_ACTION,
                    Intent.FILL_IN_DATA,
                    Intent.FILL_IN_CATEGORIES,
                    Intent.FILL_IN_COMPONENT,
                    Intent.FILL_IN_PACKAGE,
                    Intent.FILL_IN_SOURCE_BOUNDS,
                    Intent.FILL_IN_SELECTOR,
                    Intent.FILL_IN_CLIP_DATA
            })

    public static PendingIntent getActivity(Context context, int requestCode,
            Intent intent, @Flags int flags) {
        return getActivity(context, requestCode, intent, flags, null);
    }

    public static PendingIntent getActivity(Context context, int requestCode,
            @NonNull Intent intent, @Flags int flags, @Nullable Bundle options) {
        String packageName = context.getPackageName();
        String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                context.getContentResolver()) : null;
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(context);
            IIntentSender target =
                ActivityManagerNative.getDefault().getIntentSender(
                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
                    null, null, requestCode, new Intent[] { intent },
                    resolvedType != null ? new String[] { resolvedType } : null,
                    flags, options, UserHandle.myUserId());
            return target != null ? new PendingIntent(target) : null;
        } catch (RemoteException e) {
        }
        return null;
    }
}

远程对象,在system server进程中 AMS.getIntentSender。

public IIntentSender getIntentSender(int type,
        String packageName, IBinder token, String resultWho,
        int requestCode, Intent[] intents, String[] resolvedTypes,
        int flags, Bundle options, int userId) {
    //重新拷贝一次intent对象内容
    if (intents != null) {
        for (int i=0; i<intents.length; i++) {
            Intent intent = intents[i];
            if (intent != null) {
                intents[i] = new Intent(intent);
            }
        }
    }

    ...
       synchronized(this) {
        int callingUid = Binder.getCallingUid();
        int origUserId = userId;
        userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
                type == ActivityManager.INTENT_SENDER_BROADCAST,
                ALLOW_NON_FULL, "getIntentSender", null);
        if (origUserId == UserHandle.USER_CURRENT) {
            userId = UserHandle.USER_CURRENT;
        }
        return getIntentSenderLocked(type, packageName, callingUid, userId,
              token, resultWho, requestCode, intents, resolvedTypes, flags, options);
    }
}

IIntentSender getIntentSenderLocked(int type, String packageName,
        int callingUid, int userId, IBinder token, String resultWho,
        int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
        Bundle options) {
    ActivityRecord activity = null;
    ...
    //创建Key对象
    PendingIntentRecord.Key key = new PendingIntentRecord.Key(
            type, packageName, activity, resultWho,
            requestCode, intents, resolvedTypes, flags, options, userId);
    WeakReference<PendingIntentRecord> ref;
    ref = mIntentSenderRecords.get(key);//=======================关于flag使用========================
    PendingIntentRecord rec = ref != null ? ref.get() : null;
    if (rec != null) {
        if (!cancelCurrent) {
            if (updateCurrent) {
                if (rec.key.requestIntent != null) {
                    rec.key.requestIntent.replaceExtras(intents != null ?
                            intents[intents.length - 1] : null);
                }
                if (intents != null) {
                    intents[intents.length-1] = rec.key.requestIntent;
                    rec.key.allIntents = intents;
                    rec.key.allResolvedTypes = resolvedTypes;
                } else {
                    rec.key.allIntents = null;
                    rec.key.allResolvedTypes = null;
                }
            }
            return rec;
        }
        rec.canceled = true;
        mIntentSenderRecords.remove(key);
    }
    if (noCreate) {
        return rec;
    }
    //创建PendingIntentRecord对象
    rec = new PendingIntentRecord(this, key, callingUid);
    mIntentSenderRecords.put(key, rec.ref);
    ...
    return rec;
}

17 BroadcastReceiver?

BroadcastReceiver分为两类:

  • 静态广播接收者:通过AndroidManifest.xml的标签来申明的BroadcastReceiver。
  • 动态广播接收者:通过AMS.registerReceiver()方式注册的BroadcastReceiver,动态注册更为灵活,可在不需要时通过unregisterReceiver()取消注册。

前面你都知道,下面这3个你知道么。
从广播发送方式可分为三类:

  • 普通广播:通过Context.sendBroadcast()发送,可并行处理
  • 有序广播:通过Context.sendOrderedBroadcast()发送,串行处理
  • Sticky广播:通过Context.sendStickyBroadcast()发送

区别。很多误区在有序广播,并不是发送一条条有序,而是接受一条条有顺序,排序更android:priority有关。

18 java对象和java序列化原理?

序列化的原理
对象模型
其实就是一堆字节码,linux也是有文件节点挂载起来的,说白了也是一堆字节码。通信就全靠序列号来标识。

19 说说Android应用的persistent属性?

Android应用的persistent属性观看这个博客需要先看Android系统启动流程,才能大部分有概念。一般普通应用不要使用,没有权限限制这货。
知道这货能干嘛呢?如果我要你启动系统相机你怎么玩,不要弹出Intent匹配对话框?

    public static void launchSystemCamera(Activity activity, File file, int requestCode) {
        try{
            //获取相机包名
            Intent infoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            List<ResolveInfo> infos = activity.getPackageManager().queryIntentActivities(infoIntent, 0);
            if(infos != null && infos.size() > 0) {
                for(ResolveInfo info:infos) {
                    int flags = info.activityInfo.applicationInfo.flags;
                    if ((flags & ApplicationInfo.FLAG_SYSTEM) != 0) { //系统相机
                        String packageName = info.activityInfo.packageName;
                        String className = info.activityInfo.name;
                        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
                        ComponentName cn = new ComponentName(packageName, className);
                        intent.setComponent(cn);
                        intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
                        intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(file));
                        activity.startActivityForResult(intent,requestCode);
                        return;
                    }
                }
            }
        } catch(Exception e) {
            e.printStackTrace();
        }

    }

20 为啥从应用层面来说,没有杀不死的进程?

Android进程绝杀技--forceStop看完这篇依赖相杀,大家估计都有个概念了。需要了解AMS下的AMS死亡监听
关于自创Native进程,不知怎么杀...

21 是时候熟悉一个JNI调用系统服务代码了,Camera?

Android Camera 系统架构源码分析
总结下:底层大致数据处理时会阻塞,然后自己不处理,姿势把数据流放给上层,在上层开始Camera的时候你会设置一堆监听,然后底层会通过binder远程调用监听。
DisplayClient用来负责显示,CamClient则是一个大统一,把Camera的操作都归集于此。CamClient又把自己的功能分成几个 Client去负责,其中PreviewClient负责预览录制,RecordClient负责录制。
CameraClient和DisplayClient是两个功能的操作者,而CamAdapter则是整个Camera的管理者,负责与底层沟通,读取Buf,并负责分配Buf给各个功能操作者,并包括管理着Camer各种属性和算法,如3A,是否自动对焦等

22 共享内存MMP 总结:



出自深入理解ANDROID 卷1.pdf

23 容易被多进程命名误导":"在xml的含义



出自Android开发艺术探索,2.2.1章
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,230评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,261评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,089评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,542评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,542评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,544评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,922评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,578评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,816评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,576评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,658评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,359评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,920评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,859评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,381评论 2 342

推荐阅读更多精彩内容