美文网首页
MTK Camera学习第三篇(设置相关)

MTK Camera学习第三篇(设置相关)

作者: 奥利奥真好吃 | 来源:发表于2018-06-12 10:54 被阅读0次

    关于设置这块儿大概分为两部分来说,一是视图UI,二是数据处理。第一篇所说的UI只是整体的一个概述,而setting的UI部分相对复杂,因此这里单独来说一下。首先看一下总的布局文件setting_container.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <com.android.camera.ui.RotateLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:camera="http://schemas.android.com/apk/res/com.mediatek.camera"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:splitMotionEvents="false" >
        <com.android.camera.ui.MaxLinearLayout
            android:id="@+id/container"
            style="@style/SettingContainer"
            camera:maxHeight="@dimen/setting_container_height_max"
            android:splitMotionEvents="false">
            <TabHost android:id="@+id/tab_title"
                style="@style/SettingTabTitle">
                <TabWidget 
                    android:id="@android:id/tabs"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@drawable/bg_pressed" 
                    android:splitMotionEvents="false">
                </TabWidget>
                <FrameLayout
                    android:id="@android:id/tabcontent"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:visibility="gone"
                    android:splitMotionEvents="false">
                </FrameLayout>
            </TabHost>
            <android.support.v4.view.ViewPager
                android:id="@+id/pager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
        </com.android.camera.ui.MaxLinearLayout>
    </com.android.camera.ui.RotateLayout>
    

    MaxLinearLayout重写了LinearLayout,主要是对传统的LinearLayout进行一个最大宽高的限制。内层是我们常见的TabHost+ViewPager的一个页面切换效果。UI显示如下:


    TabHost_ViewPager.png

    代码怎样处理呢?回到我们说过的SettingManager:

        private void initializeSettings() {
            if (mSettingLayout == null && mSettingController.getPreferenceGroup() != null) {
                mSettingLayout = (ViewGroup) getContext().inflate(R.layout.setting_container,
                        SETTING_PAGE_LAYER);
                mTabHost = (TabHost) mSettingLayout.findViewById(R.id.tab_title);
                mTabHost.setup();
    
                // For tablet
                int settingKeys[] = SettingConstants.SETTING_GROUP_COMMON_FOR_TAB;
                if (FeatureSwitcher.isSubSettingEnabled()) {
                    settingKeys = SettingConstants.SETTING_GROUP_MAIN_COMMON_FOR_TAB;
                } else if (FeatureSwitcher.isLomoEffectEnabled() && getContext().isNonePickIntent()) {
                    settingKeys = SettingConstants.SETTING_GROUP_COMMON_FOR_LOMOEFFECT;
                }
                List<Holder> list = new ArrayList<Holder>();
                if (getContext().isNonePickIntent() || getContext().isStereoMode()) {
                    ...
                        list.add(new Holder(TAB_INDICATOR_KEY_COMMON, R.drawable.ic_tab_common_setting,
                                settingKeys));
                        list.add(new Holder(TAB_INDICATOR_KEY_CAMERA, R.drawable.ic_tab_camera_setting,
                                SettingConstants.SETTING_GROUP_CAMERA_FOR_TAB));
                        list.add(new Holder(TAB_INDICATOR_KEY_VIDEO, R.drawable.ic_tab_video_setting,
                                SettingConstants.SETTING_GROUP_VIDEO_FOR_TAB));
                    ...
                }
                ...
    
                int size = list.size();
                List<SettingListLayout> pageViews = new ArrayList<SettingListLayout>();
                for (int i = 0; i < size; i++) {
                    Holder holder = list.get(i);
                    // new page view
                    SettingListLayout pageView = (SettingListLayout) getContext().inflate(
                            R.layout.setting_list_layout, SETTING_PAGE_LAYER);
                    ArrayList<ListPreference> listItems = new ArrayList<ListPreference>();
                    pageView.initialize(getListPreferences(holder.mSettingKeys, i == 0));
                    //这里将ArrayList<ListPreference>对象传递到了每一个Item,即SettingListLayout,而这个holder.mSettingKeys是一个int数组,每一个值表示一种状态
                    pageViews.add(pageView);
                    // new indicator view
                    ImageView indicatorView = new ImageView(getContext());
                    if (indicatorView != null) {
                        indicatorView.setBackgroundResource(R.drawable.bg_tab_title);
                        indicatorView.setImageResource(holder.mIndicatorIconRes);
                        indicatorView.setScaleType(ScaleType.CENTER);
                    }
                    mTabHost.addTab(mTabHost.newTabSpec(holder.mIndicatorKey)
                            .setIndicator(indicatorView).setContent(android.R.id.tabcontent));
                }
    
                mAdapter = new MyPagerAdapter(pageViews);
                mPager = (ViewPager) mSettingLayout.findViewById(R.id.pager);
                mPager.setAdapter(mAdapter);
                mPager.setOnPageChangeListener(mAdapter);
                mTabHost.setOnTabChangedListener(this);
            }
            Util.setOrientation(mSettingLayout, getOrientation(), false);
        }
    

    在这个UI初始化的过程中有两个需要关注的对象:一是SettingListLayout(即每一页PageView,共三页),二是ListPreference(用于保存每一个item条目上的可选内容)。
    我们看到每一页PageView中的ListView都有多种item的布局,而这也是我们在做开发中常常会遇到的问题,来看一下Camera是怎样处理的:

          private int getSettingLayoutId(ListPreference pref) {
                // If the preference is null, it will be the only item , i.e.
                // 'Restore setting' in the popup window.
                //将所有item分成以下五种布局类型即可载入五种不同的item layout,注意这里有五个return语句
                if (pref == null) {
                    return R.layout.in_line_setting_restore;
                }
    
                // Currently, the RecordLocationPreference is the only setting
                // which applies the on/off switch.
                if (isSwitchSettingItem(pref)) {
                    return R.layout.in_line_setting_switch;
                } else if (isVirtualSettingItem(pref)) {
                    return R.layout.in_line_setting_virtual;
                } else if (isSwitchVirtualItem(pref)) {
                    return R.layout.in_line_setting_switch_virtual;
                }
                return R.layout.in_line_setting_sublist;
            }
    
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ListPreference pref = mListItem.get(position);
                //五个Layout布局文件对应了五种自定义viewgroup
                if (convertView != null) {
                    if (pref == null) {
                        if (!(convertView instanceof InLineSettingRestore)) {
                            convertView = null;
                        }
                    } else if (isSwitchSettingItem(pref)) {
                        if (!(convertView instanceof InLineSettingSwitch)) {
                            convertView = null;
                        }
                    } else if (isVirtualSettingItem(pref)) {
                        if (!(convertView instanceof InLineSettingVirtual)) {
                            convertView = null;
                        }
                    } else if (isSwitchVirtualItem(pref)) {
                        if (!(convertView instanceof InLineSettingSwitchVirtual)) {
                            convertView = null;
                        }
                    } else {
                        if (!(convertView instanceof InLineSettingSublist)) {
                            convertView = null;
                        }
                    }
                    if (convertView != null) {
                        ((InLineSettingItem) convertView).initialize(pref);
                        SettingUtils.setEnabledState(convertView,
                                (pref == null ? true : pref.isEnabled()));
                        return convertView;
                    }
                }
                //在这里并没有直接进行数据填充,而是交给下一层的自定义viewgroup
                int viewLayoutId = getSettingLayoutId(pref);
                InLineSettingItem view = (InLineSettingItem) mInflater.inflate(viewLayoutId, parent,
                        false);
                if (viewLayoutId == R.layout.in_line_setting_restore) {
                    view.setId(R.id.restore_default);
                }
    
                view.initialize(pref); // no init for restore one
                view.setSettingChangedListener(SettingListLayout.this);
                SettingUtils.setEnabledState(convertView, (pref == null ? true : pref.isEnabled()));
                return view;
            }
          //可以使用下面的方法判断是否是一个带有switch开关的item,其它同理
          private boolean isSwitchSettingItem(ListPreference pref) {
            return SettingConstants.KEY_RECORD_LOCATION.equals(pref.getKey())
                    || SettingConstants.KEY_VIDEO_RECORD_AUDIO.equals(pref.getKey())
                    || SettingConstants.KEY_VIDEO_EIS.equals(pref.getKey())
                    || SettingConstants.KEY_VIDEO_3DNR.equals(pref.getKey())
                    || SettingConstants.KEY_CAMERA_ZSD.equals(pref.getKey())
                    || SettingConstants.KEY_VOICE.equals(pref.getKey())
                    || SettingConstants.KEY_CAMERA_FACE_DETECT.equals(pref.getKey())
                    || SettingConstants.KEY_HDR.equals(pref.getKey())
                    || SettingConstants.KEY_GESTURE_SHOT.equals(pref.getKey())
                    || SettingConstants.KEY_SMILE_SHOT.equals(pref.getKey())
                    || SettingConstants.KEY_SLOW_MOTION.equals(pref.getKey())
                    || SettingConstants.KEY_CAMERA_AIS.equals(pref.getKey())
                    || SettingConstants.KEY_ASD.equals(pref.getKey())
                    || SettingConstants.KEY_DNG.equals(pref.getKey());
        }
    

    根据ListPreference获取对应的Key,然后将固定的key值对应到固定的layout id上,我们以上图中的人脸美化这个条目为例进一步深入,所以接下来进入的是InLineSettingSublist:

        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
            mEntry = (TextView) findViewById(R.id.current_setting);
            mImage = (ImageView) findViewById(R.id.image);
            //PageView内部的ListView显示的当前item layout
            setOnClickListener(mOnClickListener);
        }
        protected OnClickListener mOnClickListener = new OnClickListener() {
    
            @Override
            public void onClick(View view) {
                Log.d(TAG, "onClick() mShowingChildList=" + mShowingChildList + ", mPreference="
                        + mPreference);
                if (!mShowingChildList && mPreference != null && mPreference.isClickable()) {
                    expendChild();
                } else {
                    collapseChild();
                }
            }
        };
        public boolean expendChild() {
            boolean expend = false;
            if (!mShowingChildList) {
                mShowingChildList = true;
                if (mListener != null) {
                    mListener.onShow(this);
                }
                //载入下一个子视图(ListView)
                mSettingLayout = (SettingSublistLayout) mContext.inflate(
                        R.layout.setting_sublist_layout, ViewManager.VIEW_LAYER_SETTING);
                mSettingContainer = mSettingLayout.findViewById(R.id.container);
                //还是那个ListPreference
                mSettingLayout.initialize(mPreference);
                mContext.addView(mSettingLayout, ViewManager.VIEW_LAYER_SETTING);
                mContext.addOnOrientationListener(this);
                mSettingLayout.setSettingChangedListener(this);
                setOrientation(mContext.getOrientationCompensation(), false);
                fadeIn(mSettingLayout);
                highlight();
                expend = true;
            }
            Log.d(TAG, "expendChild() return " + expend);
            return expend;
        }
    

    来看这个子ListView的布局处理:

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder holder = null;
                if (convertView == null) {
                    //该子listview的item上有一个ImageView、一个TextView和一个RadioButton
                    convertView = mInflater.inflate(R.layout.setting_sublist_item, null);
                    holder = new ViewHolder();
                    holder.mImageView = (ImageView) convertView.findViewById(R.id.image);
                    holder.mTextView = (TextView) convertView.findViewById(R.id.title);
                    holder.mRadioButton = (RadioButton) convertView.findViewById(R.id.radio);
                    convertView.setTag(holder);
                } else {
                    holder = (ViewHolder) convertView.getTag();
                }
                int iconId = mPreference.getIconId(position);
                //像我们当前的人脸美化所用的listview是没有icon,所以这里设为GONE即可
                if (mPreference.getIconId(position) == ListPreference.UNKNOWN) {
                    holder.mImageView.setVisibility(View.GONE);
                } else {
                    holder.mImageView.setVisibility(View.VISIBLE);
                    holder.mImageView.setImageResource(iconId);
                }
                holder.mTextView.setText(mPreference.getEntries()[position]);
                holder.mRadioButton.setChecked(position == mSelectedIndex);
                // SettingUtils.setEnabledState(convertView,
                // mPreference.isEnabled(position));
                return convertView;
            }
    

    那么事件如何层层传递到Activity呢?看下各层视图类的定义:

    public class SettingSublistLayout extends RotateLayout implements AdapterView.OnItemClickListener {...}
    
    public class InLineSettingSublist extends InLineSettingItem implements
            SettingSublistLayout.Listener, CameraActivity.OnOrientationListener {...}
    
    public abstract class InLineSettingItem extends RelativeLayout {...}
    
    public class SettingListLayout extends FrameLayout implements InLineSettingItem.Listener,
            AdapterView.OnItemClickListener, OnScrollListener {...}
    
    public class SettingManager extends ViewManager implements View.OnClickListener,
            SettingListLayout.Listener, CameraActivity.OnPreferenceReadyListener, OnTabChangeListener {...}
    

    基本上是一个通过接口层层向外传递的过程,其中InLineSettingItem作为一个抽象类,其定义的接口由其子类实现(子类同时将继承其接口对象),然后就进入了SettingListLayout,进而转发到SettingManager,最终到达CameraActivity。
    我们来看一下这个抽象类的子类都有哪些:


    settingitem.png

    这五个子类就是前面说的五个布局文件中的自定义viewgroup。
    视图关系与事件逻辑就讲到这里,接下来看一下上面提到的ListPreference,回到SettingManager的以下代码:

     int settingKeys[] = SettingConstants.SETTING_GROUP_COMMON_FOR_TAB;
     ...
     pageView.initialize(getListPreferences(holder.mSettingKeys, i == 0));
    

    这个mSettingKeys整形数组初始化为如下,每一个数都表示一条item(即一个Camera属性)

        public static final int[] SETTING_GROUP_COMMON_FOR_TAB = new int[]{
            ROW_SETTING_DUAL_CAMERA_MODE,
            ROW_SETTING_RECORD_LOCATION,//common
            ROW_SETTING_MULTI_FACE_MODE,
            ROW_SETTING_EXPOSURE,//common
            ROW_SETTING_COLOR_EFFECT,//common
            ROW_SETTING_SCENCE_MODE,//common
            ROW_SETTING_WHITE_BALANCE,//common
            ROW_SETTING_IMAGE_PROPERTIES,
            ROW_SETTING_ANTI_FLICKER,//common
        };
    

    除了上面的通用设置属性,还有针对camera和video的针对属性,同理定义的数组如下:

        public static final int[] SETTING_GROUP_CAMERA_FOR_TAB = new int[]{
            ROW_SETTING_ZSD,//camera
            ROW_SETTING_AIS,//camera
            ROW_SETTING_VOICE,//camera
            ROW_SETTING_CAMERA_FACE_DETECT,//camera
            ROW_SETTING_GESTURE_SHOT,
            ROW_SETTING_SMILE_SHOT,//camera
            ROW_SETTING_ASD,//camera
            ROW_SETTING_DNG,
            ROW_SETTING_SELF_TIMER,//camera
            ROW_SETTING_CONTINUOUS_NUM,//camera
            ROW_SETTING_PICTURE_SIZE,//camera
            ROW_SETTING_PICTURE_RATIO,//camera
            ROW_SETTING_ISO,//camera
            ROW_SETTING_FACEBEAUTY_PROPERTIES,//camera:Cfb
        };
        public static final int[] SETTING_GROUP_VIDEO_FOR_TAB = new int[]{
            ROW_SETTING_3DNR,
            ROW_SETTING_VIDEO_STABLE,//video
            ROW_SETTING_MICROPHONE,//video
            ROW_SETTING_AUDIO_MODE,//video
            ROW_SETTING_TIME_LAPSE,//video
            ROW_SETTING_VIDEO_QUALITY,//video
            ROW_SETTING_SLOW_MOTION_VIDEO_QUALITY,
        };
    

    只要Hal层做了相应的支持,上述数组中表示的所有属性调节都将出现在Camera的Setting中
    然后使用该数组封装得到ListPreference对象:

        private ArrayList<ListPreference> getListPreferences(int[] keys, boolean addrestore) {
            ArrayList<ListPreference> listItems = new ArrayList<ListPreference>();
            for (int i = 0; i < keys.length; i++) {
                //keys数组的值对应的是KEYS_FOR_SETTING这个数组的index下标,这里将得到类似pref_camera_id_key这样的值
                String key = SettingConstants.getSettingKey(keys[i]);
                /*
                getListPreference(key)这个方法的实现在SettingCtrl中,然后将调用SettingGenerator的getListPreference(int row)方法,
                传到SettingCtrl的是数组值,然后又转换为了数组下标
                */
                ListPreference pref = mSettingController.getListPreference(key);
                if (pref != null && pref.isShowInSetting()) {
                    if (SettingConstants.KEY_VIDEO_QUALITY.equals(key)) {
                        if (!("on".equals(mSettingController
                                .getSettingValue(SettingConstants.KEY_SLOW_MOTION)))) {
                            listItems.add(pref);
                        }
                    } else {
                        listItems.add(pref);
                    }
    
                }
            }
    
            if (addrestore) {
                listItems.add(null);
            }
            return listItems;
        }
    

    看一下SettingGenerator的getListPreference方法:

        public ListPreference getListPreference(int row) {
            int currentCameraId = mICameraDeviceManager.getCurrentCameraId();
            //根据CameraId得到当前使用的ListPreference
            ArrayList<ListPreference> preferences = mPreferencesMap.get(currentCameraId);
            if (preferences == null) {
                Log.e(TAG, "Call setting before setting updated, return null");
                return null;
            }
            return preferences.get(row);
        }
    

    mPreferencesMap定义如下:

    private HashMap<Integer, ArrayList<ListPreference>> mPreferencesMap;
    //一般来说我们都有两个camera,所以我们需要定义两个ListPreference集合分别来表示前置后置两个摄像头的参数配置信息
    int cameraCounts = mICameraDeviceManager.getNumberOfCameras();
    mPreferencesMap = new HashMap<Integer, ArrayList<ListPreference>>(cameraCounts);
    

    到这里我们得到了当前摄像头所使用的ListPreference,那它与UI视图怎样建立联系呢?上面说过每一个item都对应了一个int值,而这个int值就分别对应了不同的ListPreference对象。
    接下来我们看下ListPreference的创建过程,回到第二篇中讲的CameraDeviceCtrl,在Camera成功open之后,将执行如下方法:

        private void initializeSettingController() {
            Log.d(TAG, "[initializeSettingController]");
            if (!mISettingCtrl.isSettingsInitialized()) {
                //该xml文件定义了setting的所有条目  
                mISettingCtrl.initializeSettings(R.xml.camera_preferences, mPreferences.getGlobal(),
                        mPreferences.getLocal());
            }
            //mPreferences最初是在CameraActivity中new出来的ComboPreferences对象
            mISettingCtrl.updateSetting(mPreferences.getLocal());
            mMainHandler.sendEmptyMessage(MSG_CAMERA_PREFERENCE_READY);
        }
    

    而后进入SettingCtrl:

        @Override
        public void initializeSettings(int preferenceRes, SharedPreferences globalPref,
                SharedPreferences localPref) {
            Log.i(TAG, "[initializeSettings]...");
            mLocalPrefs.put(mICameraDeviceManager.getCurrentCameraId(), localPref);
            mPrefTransfer = new SharedPreferencesTransfer(globalPref, localPref);
            mSettingGenerator = new SettingGenerator(mICameraContext, mPrefTransfer);
            mSettingGenerator.createSettings(preferenceRes);
            createRules();
            mIsInitializedSettings = true;
        }
    

    最终进入SettingGenerator:

        public void createSettings(int preferenceRes) {
            mPreferenceRes = preferenceRes;
            mInflater = new PreferenceInflater(mContext, mPrefTransfer);
            int currentCameraId = mICameraDeviceManager.getCurrentCameraId();
            //自定义了一个Inflater用来解析上面提到的xml文件(并且在解析过程中封装得到多个ListPreference对象),
            //一个摄像头所对应的所有可用setting属性构成了一个PreferenceGroup  
            PreferenceGroup group = (PreferenceGroup) mInflater.inflate(preferenceRes);
            mPreferencesGroupMap.put(currentCameraId, group);
            createSettingItems();
            createPreferences(group, currentCameraId);
        }
        /*
        一个SettingItem记录了当前item条目的id信息、当前的value值、上次选择的value值以及
        默认的value值,另外SettingItem内部持有当前item的ListPreference对象
        */
        private void createSettingItems() {
            int cameraCounts = mICameraDeviceManager.getNumberOfCameras();
            for (int i = 0; i < cameraCounts; i++) {
                ArrayList<SettingItem> settingItems = new ArrayList<SettingItem>();
                for (int settingId = 0; settingId < SettingConstants.SETTING_COUNT; settingId++) {
                    SettingItem settingItem = new SettingItem(settingId);
                    String key = SettingConstants.getSettingKey(settingId);
                    int type = SettingConstants.getSettingType(settingId);
                    settingItem.setKey(key);
                    settingItem.setType(type);
                    settingItems.add(settingItem);
                }
                mSettingItemsMap.put(i, settingItems);
            }
    
        }
        /*
        根据CameraId和上面得到的group将ListPreference保存到HashMap
        */
        private void createPreferences(PreferenceGroup group, int cameraId) {
            Log.i(TAG, "[createPreferences], cameraId:" + cameraId + ", group:" + group);
            ArrayList<ListPreference> preferences = mPreferencesMap.get(cameraId);
            mSupportedImageProperties = new ArrayList<String>();
            mSupportedFaceBeautyProperties = new ArrayList<String>();
            if (preferences == null) {
                preferences = new ArrayList<ListPreference>();
                ArrayList<SettingItem> settingItems = mSettingItemsMap.get(cameraId);
                for (int settingId = 0; settingId < SettingConstants.SETTING_COUNT; settingId++) {
                    String key = SettingConstants.getSettingKey(settingId);
                    ListPreference preference = group.findPreference(key);
    
                    preferences.add(preference);
    
                    SettingItem settingItem = settingItems.get(settingId);
                    //上面说过SettingItem持有一个ListPreference的对象
                    settingItem.setListPreference(preference);
                }
                mPreferencesMap.put(cameraId, preferences);
            }
            // every camera maintain one setting item list.
            //从ICameraDevice得到Parameters过滤掉当前Camera不支持的一些属性
            filterPreferences(preferences, cameraId);
        }
    

    综上得到如下类图关系:


    camerasetting.png

    接着前面说过的,当事件通过接口层层传递到CameraActivity时,将通过ISettingCtrl的对象调整item条目的value值,再通过CameraDeviceCtrl将最新的Camera属性适用到设备。如下所求:

        private SettingManager.SettingListener mSettingListener = new SettingManager.SettingListener() {
            @Override
            public void onSharedPreferenceChanged(ListPreference preference) {
                Log.d(TAG, "[onSharedPreferenceChanged]");
                if (!isCameraOpened()) {
                    return;
                }
                if (preference != null) {
                    String settingKey = preference.getKey();
                    String value = preference.getValue();
                    mISettingCtrl.onSettingChanged(settingKey, value);
                }
                mCameraDeviceCtrl.applyParameters(false);
            }
            ...
        }
    

    而SettingCtrl将对item进行重新赋值(不操作UI),如下:

        private void onSettingChanged(Parameters parameters, int currentCameraId, String key,
                String value) {
            int settingId = SettingConstants.getSettingId(key);
            SettingItem setting = getSetting(settingId);
            String lastValue = setting.getLastValue();
            Log.i(TAG, "[onSettingChanged], key: " + key + ", value:" + value + ", lastValue:"
                    + lastValue);
            if (value == null || value.equals(lastValue) && ! SettingConstants.KEY_PICTURE_SIZE.equals(key)){
                Log.w(TAG, "[onSettingChanged], do not need to change, return.");
                return;
            }
            setting.setValue(value);
            setting.setLastValue(value);
            ...
         }
    

    流程相对复杂但也相对清楚,但我们发现一个问题,说了这么多,item上的value值的变化即UI操作到底在哪里进行的?总得有一个setText()或者setImage()之类的方法才对吧,我们找到SettingSublistLayout的onItemClick事件:

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int index, long id) {
            Log.d(TAG,
                    "onItemClick(" + index + ", " + id + ") and oldIndex = "
                            + mAdapter.getSelectedIndex());
            boolean realChanged = index != mAdapter.getSelectedIndex();
            if (realChanged) {
                //这里最后将数据保存在SharedPreferences中
                mPreference.setValueIndex(index);
            }
            if (mListener != null) {
                //这里最终调用到SettingManager的onSettingChanged()方法
                mListener.onSettingChanged(realChanged);
            }
        }
    

    SettingManager.java

        @Override
        public void onSettingChanged(SettingListLayout settingList, ListPreference preference) {
            Log.i(TAG, "onSettingChanged(" + settingList + ")");
            if (mListener != null) {
                mListener.onSharedPreferenceChanged(preference);
                mPreference = preference;
            }
            refresh();
        }
    

    这个refresh()方法应该就是我们想要找的,但它本身没有,我们查找它的父类ViewManager:

        public final void refresh() {
            if (mShowing) {
                onRefresh();
            }
        }
    

    onRefresh()方法在该父类中没有实现,我们回到它的子类SettingManager:

        @Override
        public void onRefresh() {
            Log.i(TAG, "onRefresh() isShowing()=" + isShowing() + ", mShowingContainer="
                    + mShowingContainer);
            if (mShowingContainer && mAdapter != null) { // just apply checker when
                                                         // showing settings
                //通知UI进行刷新,这就是我们想要找的
                mAdapter.notifyDataSetChanged();
            }
        }
    

    进入内部类MyPagerAdapter:

            @Override
            public void notifyDataSetChanged() {
                super.notifyDataSetChanged();
                for (SettingListLayout page : mPageViews) {
                    if (page != null) {
                        page.setSettingChangedListener(SettingManager.this);
                        page.reloadPreference();
                    }
                }
            }
    

    然后是SettingListLayout:

        public void reloadPreference() {
            int count = mSettingList.getChildCount();
            for (int i = 0; i < count; i++) {
                ListPreference pref = mListItem.get(i);
                if (pref != null) {
                    InLineSettingItem settingItem = (InLineSettingItem) mSettingList.getChildAt(i);
                    settingItem.reloadPreference();
                }
            }
        }
    

    接着是InLineSettingItem,由于它是一个抽象类,而其子类InLineSettingVirtual(也可能是其它子类)同时重写了reloadPreference()方法,我们直接看它的子类方法:

        @Override
        public void reloadPreference() {
            int len = mPreference.getEntries().length;
            mChildPrefs = new ListPreference[len];
            for (int i = 0; i < len; i++) {
                String key = String.valueOf(mPreference.getEntries()[i]);
                mChildPrefs[i] = mContext.getListPreference(key);
                Log.d(TAG, "reloadPreference() mChildPrefs[" + i + "|" + key + "]=" + mChildPrefs[i]);
            }
            updateView();
        }
        @Override
        protected void updateView() {
            if (mPreference == null || mChildPrefs == null) {
                return;
            }
            setOnClickListener(null);
            int len = mChildPrefs.length;
            boolean allDefault = true;
            int enableCount = 0;
            for (int i = 0; i < len; i++) {
                ListPreference pref = mChildPrefs[i];
                if (pref == null) {
                    continue;
                }
                String defaultValue = String.valueOf(mPreference.getEntryValues()[i]);
                String value = pref.getOverrideValue();
                if (value == null) {
                    value = pref.getValue();
                }
                if (pref.isEnabled()) {
                    enableCount++;
                }
                // we assume pref and default value is not null.
                if (allDefault && !defaultValue.equals(value)) {
                    allDefault = false;
                }
            }
            if (allDefault) {
                mEntry.setText(mPreference.getDefaultValue());
            } else {
                mEntry.setText("");
            }
            boolean enabled = (enableCount == len);
            mPreference.setEnabled(enabled);
            setEnabled(mPreference.isEnabled());
            setOnClickListener(mOnClickListener);
            Log.d(TAG, "updateView() enableCount=" + enableCount + ", len=" + len);
        }
    

    至此,一个Camera Setting完整的UI操作过程就结束了。

    相关文章

      网友评论

          本文标题:MTK Camera学习第三篇(设置相关)

          本文链接:https://www.haomeiwen.com/subject/rtdpsftx.html