【学习记录】关于源码不懂的地方

1、ThreadLocal为什么不直接使用WeakHashMap

Entry是一个以弱引用为keyK-V结构;ThreadLocal内部持有的数据结构是一个数组;getEntry获取index的方式也是通过位运算代替取余

		//1
		private Entry[] table;
		//2
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
		//3
		private Entry getEntry(ThreadLocal<?> key) {
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            if (e != null && e.get() == key)
                return e;
            else
                return getEntryAfterMiss(key, i, e);
        }

StackOverflow有回答说是单纯因为ThreadLocal出来得早,Doug Lee后来发现这套结构通用性强,才写了HashMap(存疑)


2、HashMap构造函数为什么将长度赋给阈值

    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " 
                                            + initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        //这里
        this.threshold = tableSizeFor(initialCapacity);
    }
  • 猜测
    其实应该是this.threshold = tableSizeFor(initialCapacity) * this.loadFactor;才对,但是table的初始化在第一次put的时候,threshold又会被重新赋值。猜想是与resize里面的第二个判断if (oldThr > 0) { newCap = oldThr; }有关。

3、ViewRootImpl # setView为什么先调用requestLayout后调用addToDisplay

		// Schedule the first layout -before- adding to the window
        // manager, to make sure we do the relayout before receiving
        // any other events from the system.
		requestLayout();
        try {
        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
              	getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
                mTempInsets);
       setFrame(mTmpFrame);

待验证:猜测可能像view.post一样,当前处于一个Runnable的执行过程中,在request通过Choreographer去post一个Runnable后,最快也要这个Runnable执行完,再加上这次IPC不是oneway的?所以会阻塞等待服务端返回结果才继续执行。(但又解释不通它的注释)


4、BroadcastReceiver发送流程(已解决

performReceiveLocked为什么要分两种情况

    if (app != null) {
            if (app.thread != null) {
                try {
                    //第一种?
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.getReportedProcState());
                } catch (RemoteException ex) {
                    
                }
            }
        } else {
            //第二种?
            receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
        }

因为scheduleRegisteredReceiver是动态广播的发送,它最终调用到ActivityThreadscheduleRegisteredReceiver;而performReceiver是静态广播的发送流程,它最终调用到ActivityThreadhandleReceiver。它们之间有一个最大的区别是Context的创建,动态是从ReceiverDIspatcher里面获取的,静态是通过context.getReceiverRestrictedContext()创建一个以ApplicationmBaseContext


5、bindService流程

在最后阶段,标记2里面为什么要通过Handler而不是直接调用

罗升阳老师的《Android系统源代码情景分析》里面提到有两个原因:

  • 1、当前线程需要尽快返回Binder线程池
  • 2、onServiceConnected可能有ui操作,需要回到主线程

但我去看了一下IServiceConnection.aidl,它是被标注成oneway的,这样不是就不会阻塞到系统服务了吗?

       private static class InnerConnection extends IServiceConnection.Stub {
            @UnsupportedAppUsage
            final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

            InnerConnection(LoadedApk.ServiceDispatcher sd) {
                mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
            }

            public void connected(ComponentName name, IBinder service, boolean dead)
                    throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                	//标记1
                    sd.connected(name, service, dead);
                }
            }
        }


		//---------------------------------------------------------------//


		static final class ServiceDispatcher {
        ...
        
            public void connected(ComponentName name, IBinder service, boolean dead) {
	            if (mActivityExecutor != null) {
	                mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
	            } else if (mActivityThread != null) {
	            	//标记2
	                mActivityThread.post(new RunConnection(name, service, 0, dead));
	            } else {
	                doConnected(name, service, dead);
	            }
	        }
	    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值