PhoneStatusBar初始化分析

Android  源码分析  2018年7月11日 am8:47发布6年前 (2018)更新 城堡大人
107 0 0


接上一篇《SystemUI源码分析之PhoneStatusBar启动流程简单分析》,我们简单的了解了是怎么启动PhoneStatusBar的,同时也知道在PhoneStatusBar的start()方法中主要执行了如下几个步骤:

一、createAndAddWindows()

二、addNavigationBar()

三、PhoneStatusBarPolicy()

四、startKeyguard()

本文主要就对这几个步骤进行一定流程的分析和简答的介绍。

一、createAndAddWindows()

在start()方法中,如下一句,调用的父类BaseStatusBar.start()方法

//1.调用父类BaseStatusBar.start(),这里做了一些参数的初始化
super.start(); // calls createAndAddWindows() 
1.BaseStatusBar.start()
    public void start() {
        //初始化一些管理服务类,和注册监听事件等
        mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
        mDisplay = mWindowManager.getDefaultDisplay();
        mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
                Context.DEVICE_POLICY_SERVICE);

        mNotificationColorUtil = NotificationColorUtil.getInstance(mContext);

        mNotificationData = new NotificationData(this);

        mAccessibilityManager = (AccessibilityManager)
                mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);

        mDreamManager = IDreamManager.Stub.asInterface(
                ServiceManager.checkService(DreamService.DREAM_SERVICE));
        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);

        mContext.getContentResolver().registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
                mSettingsObserver);

        ......

        //调用createAndAddWindows(),但这个是抽象的方法,子类必须实现
        createAndAddWindows();

        //用户添加和更换等广播监听
        ......
    }

由于BaseStatusBar中的createAndAddWindows()是抽象方法,子类(PhoneStatusBar)必须实现,因此调用的是PhoneStatusBar中createAndAddWindows()。

2.PhoneStatusBar.createAndAddWindows()
    @Override
    public void createAndAddWindows() {
        addStatusBarWindow();
    }

    private void addStatusBarWindow() {
        makeStatusBarView(); //这里主要是构造SystemUI中的View,比如顶部状态栏,底部导航栏,快捷键栏,消息通知栏等View
        mStatusBarWindowManager = new StatusBarWindowManager(mContext);
        mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());//添加到窗口
    }
3. PhoneStatusBar.makeStatusBarView()

这里就是初始化View,代码很长很长,看看初始化了什么。

    protected PhoneStatusBarView makeStatusBarView() {
        final Context context = mContext;

        //加载资源、更新尺寸和更新资源
        Resources res = context.getResources();
        updateDisplaySize(); // populates mDisplayMetrics
        updateResources();

        //顶部状态栏布局
        mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                R.layout.super_status_bar, null);

        mStatusBarWindow.setService(this);
        //设置触摸事件监听
        mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                checkUserAutohide(v, event);
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    if (mExpandedVisible) {
                        animateCollapsePanels();
                    }
                }
                return mStatusBarWindow.onTouchEvent(event);
            }
        });
        //初始化statusbarview控件
        mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
        mStatusBarView.setBar(this);

        //初始化PanelHolder
        PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
        mStatusBarView.setPanelHolder(holder);

        //初始化NotificationPanelView
        mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
                R.id.notification_panel);
        mNotificationPanel.setStatusBar(this);

        if (!ActivityManager.isHighEndGfx()) {
        	//设置背景颜色
            mStatusBarWindow.setBackground(null);
            mNotificationPanel.setBackground(new FastColorDrawable(context.getColor(
                    R.color.notification_panel_solid_background)));
        }

        //设置Notification通知样式,添加事件
        mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow);
        mHeadsUpManager.setBar(this);
        mHeadsUpManager.addListener(this);
        mHeadsUpManager.addListener(mNotificationPanel);
        mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
        mNotificationData.setHeadsUpManager(mHeadsUpManager);

        if (MULTIUSER_DEBUG) {
            mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
                    R.id.header_debug_info);
            mNotificationPanelDebugText.setVisibility(View.VISIBLE);
        }

        try {
            //是否显示NavigationBar,如果 showNav为true,就显示。同时设置一些事件的监听
            boolean showNav = mWindowManagerService.hasNavigationBar();
            if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
            if (showNav) {
                mNavigationBarView =
                    (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);

                mNavigationBarView.setDisabledFlags(mDisabled1);
                mNavigationBarView.setBar(this);
                mNavigationBarView.setOnVerticalChangedListener(
                        new NavigationBarView.OnVerticalChangedListener() {
                    @Override
                    public void onVerticalChanged(boolean isVertical) {
                        if (mAssistManager != null) {
                            mAssistManager.onConfigurationChanged();
                        }
                        mNotificationPanel.setQsScrimEnabled(!isVertical);
                    }
                });
                mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
                    @Override
                    public boolean onTouch(View v, MotionEvent event) {
                        checkUserAutohide(v, event);
                        return false;
                    }});
            }
        } catch (RemoteException ex) {
            // no window manager? good luck with that
        }

        mAssistManager = new AssistManager(this, context);

        // figure out which pixel-format to use for the status bar.
        //状态栏使用的像素格式
        mPixelFormat = PixelFormat.OPAQUE;

      //status_bar_expanded布局的控件
        mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
                R.id.notification_stack_scroller);
        mStackScroller.setLongPressListener(getNotificationLongClicker());
        mStackScroller.setPhoneStatusBar(this);
        mStackScroller.setGroupManager(mGroupManager);
        mStackScroller.setHeadsUpManager(mHeadsUpManager);
        mGroupManager.setOnGroupChangeListener(mStackScroller);

      //引入NotificationOverflowContainer的布局
        mKeyguardIconOverflowContainer =
                (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
                        R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
        mKeyguardIconOverflowContainer.setOnActivatedListener(this);
        mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
        mStackScroller.setOverflowContainer(mKeyguardIconOverflowContainer);

      //引入SpeedBump的布局
        SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate(
                        R.layout.status_bar_notification_speed_bump, mStackScroller, false);
        mStackScroller.setSpeedBumpView(speedBump);
      //引入EmptyShadeView的布局
        mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
                R.layout.status_bar_no_notifications, mStackScroller, false);
        mStackScroller.setEmptyShadeView(mEmptyShadeView);
        //引入DismissView的布局
        mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
                R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
        mDismissView.setOnButtonClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MetricsLogger.action(mContext, MetricsLogger.ACTION_DISMISS_ALL_NOTES);
                clearAllNotifications();
            }
        });
        mStackScroller.setDismissView(mDismissView);
        mExpandedContents = mStackScroller;

        mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
        mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
        mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);

        ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
        ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
        View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
        mScrimController = new ScrimController(scrimBehind, scrimInFront, headsUpScrim,
                mScrimSrcModeEnabled);
        mHeadsUpManager.addListener(mScrimController);
        mStackScroller.setScrimController(mScrimController);
        mScrimController.setBackDropView(mBackdrop);
        mStatusBarView.setScrimController(mScrimController);
        mDozeScrimController = new DozeScrimController(mScrimController, context);

        mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
        mHeader.setActivityStarter(this);
        mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
        mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
        mKeyguardBottomArea =
                (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
        mKeyguardBottomArea.setActivityStarter(this);
        mKeyguardBottomArea.setAssistManager(mAssistManager);
        mKeyguardIndicationController = new KeyguardIndicationController(mContext,
                (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
                        R.id.keyguard_indication_text));
        mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);

        // set the inital view visibility
        setAreThereNotifications();

      //创建IconController对象
        mIconController = new StatusBarIconController(
                mContext, mStatusBarView, mKeyguardStatusBar, this);

        // Background thread for any controllers that need it.
      //创建线程并启动线程
        mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
        mHandlerThread.start();

        // Other icons
      //位置
        mLocationController = new LocationControllerImpl(mContext,
                mHandlerThread.getLooper()); // will post a notification
      //电池
        mBatteryController = new BatteryController(mContext);
        mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() {
            @Override
            public void onPowerSaveChanged() {
                mHandler.post(mCheckBarModes);
                if (mDozeServiceHost != null) {
                    mDozeServiceHost.firePowerSaveChanged(mBatteryController.isPowerSave());
                }
            }
            @Override
            public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
                // noop
            }
        });
        //网络
        mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper());
        mHotspotController = new HotspotControllerImpl(mContext);
        //蓝牙
        mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper());
        //安全
        mSecurityController = new SecurityControllerImpl(mContext);
        if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) {
            mRotationLockController = new RotationLockControllerImpl(mContext);
        }
          //用户信息
        mUserInfoController = new UserInfoController(mContext);
         //音量
        mVolumeComponent = getComponent(VolumeComponent.class);
        if (mVolumeComponent != null) {
            mZenModeController = mVolumeComponent.getZenController();
        }
      //投射
        mCastController = new CastControllerImpl(mContext);
        //信号
        final SignalClusterView signalCluster =
                (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster);
        final SignalClusterView signalClusterKeyguard =
                (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
        final SignalClusterView signalClusterQs =
                (SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
        mNetworkController.addSignalCallback(signalCluster);
        mNetworkController.addSignalCallback(signalClusterKeyguard);
        mNetworkController.addSignalCallback(signalClusterQs);
        signalCluster.setSecurityController(mSecurityController);
        signalCluster.setNetworkController(mNetworkController);
        signalClusterKeyguard.setSecurityController(mSecurityController);
        signalClusterKeyguard.setNetworkController(mNetworkController);
        signalClusterQs.setSecurityController(mSecurityController);
        signalClusterQs.setNetworkController(mNetworkController);
        final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
        if (isAPhone) {
            mNetworkController.addEmergencyListener(mHeader);
        }

        //手电筒
        mFlashlightController = new FlashlightController(mContext);
        mKeyguardBottomArea.setFlashlightController(mFlashlightController);
        mKeyguardBottomArea.setPhoneStatusBar(this);
        mKeyguardBottomArea.setUserSetupComplete(mUserSetup);
        mAccessibilityController = new AccessibilityController(mContext);
        mKeyguardBottomArea.setAccessibilityController(mAccessibilityController);
        mNextAlarmController = new NextAlarmController(mContext);
        //锁屏监听器
        mKeyguardMonitor = new KeyguardMonitor(mContext);
        if (UserSwitcherController.isUserSwitcherAvailable(UserManager.get(mContext))) {
            mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
                    mHandler);
        }
        //用户切换
        mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
                (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
                mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);


        // Set up the quick settings tile panel
        mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
        if (mQSPanel != null) {
            final QSTileHost qsh = new QSTileHost(mContext, this,
                    mBluetoothController, mLocationController, mRotationLockController,
                    mNetworkController, mZenModeController, mHotspotController,
                    mCastController, mFlashlightController,
                    mUserSwitcherController, mKeyguardMonitor,
                    mSecurityController);
            mQSPanel.setHost(qsh);
            mQSPanel.setTiles(qsh.getTiles());
            mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
            mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
            mHeader.setQSPanel(mQSPanel);
            qsh.setCallback(new QSTileHost.Callback() {
                @Override
                public void onTilesChanged() {
                    mQSPanel.setTiles(qsh.getTiles());
                }
            });
        }

        // User info. Trigger first load.
        mHeader.setUserInfoController(mUserInfoController);
        mKeyguardStatusBar.setUserInfoController(mUserInfoController);
        mKeyguardStatusBar.setUserSwitcherController(mUserSwitcherController);
        mUserInfoController.reloadUserInfo();

        mHeader.setBatteryController(mBatteryController);
        ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController(
                mBatteryController);
        mKeyguardStatusBar.setBatteryController(mBatteryController);
        mHeader.setNextAlarmController(mNextAlarmController);

        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        mBroadcastReceiver.onReceive(mContext,
                new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));


        // receive broadcasts
        //注册广播接收者,接收关闭系统对话框、屏幕开关
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        filter.addAction(Intent.ACTION_SCREEN_ON);
        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);

        IntentFilter demoFilter = new IntentFilter();
        if (DEBUG_MEDIA_FAKE_ARTWORK) {
            demoFilter.addAction(ACTION_FAKE_ARTWORK);
        }
        demoFilter.addAction(ACTION_DEMO);
        context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
                android.Manifest.permission.DUMP, null);

        // listen for USER_SETUP_COMPLETE setting (per-user)
        resetUserSetupObserver();

        // disable profiling bars, since they overlap and clutter the output on app windows
        ThreadedRenderer.overrideProperty("disableProfileBars", "true");

        // Private API call to make the shadows look better for Recents
        ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));

        return mStatusBarView;
    }

初始化完View后,就添加到窗口,上面也提到过

    private void addStatusBarWindow() {
        makeStatusBarView();
        mStatusBarWindowManager = new StatusBarWindowManager(mContext);
        mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());//添加到窗口中。
    }

到此createAndAddWindows()这步骤就完成了。

二、addNavigationBar()

   // For small-screen devices (read: phones) that lack hardware navigation buttons
    private void addNavigationBar() {
        if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
        if (mNavigationBarView == null) return;

        prepareNavigationBarView();//1.prepareNavigationBarView

        mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());//添加到窗口中
    }
1.prepareNavigationBarView()

这里主要是设置底部导航状态栏点击、触摸、长按事件等监听。

    private void prepareNavigationBarView() {
        mNavigationBarView.reorient();
        //底部导航状态栏点击、触摸、长按事件监听
        mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
        mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
        mNavigationBarView.getRecentsButton().setLongClickable(true);
        mNavigationBarView.getRecentsButton().setOnLongClickListener(mLongPressBackRecentsListener);
        mNavigationBarView.getBackButton().setLongClickable(true);
        mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener);
        mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
        mNavigationBarView.getHomeButton().setOnLongClickListener(mLongPressHomeListener);
        mAssistManager.onConfigurationChanged();
    }

三、PhoneStatusBarPolicy()

这里主要是做一些状态监听,比如sim状态改变、蓝牙链接或断开,音量变化、热点等,然后改变顶部状态栏的icon

    public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot,
            UserInfoController userInfoController, BluetoothController bluetooth) {
        mContext = context;
        mCast = cast;
        mHotspot = hotspot;
        mBluetooth = bluetooth;
        mBluetooth.addStateChangedCallback(this);
        mService = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        mUserInfoController = userInfoController;

        // listen for broadcasts  闹钟、SIM、TTY等
        IntentFilter filter = new IntentFilter();
        filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
        filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
        filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);

        // listen for user / profile change.
        try {
            ActivityManagerNative.getDefault().registerUserSwitchObserver(mUserSwitchListener);
        } catch (RemoteException e) {
            // Ignore
        }

        // TTY status tty状态
        mService.setIcon(SLOT_TTY,  R.drawable.stat_sys_tty_mode, 0, null);
        mService.setIconVisibility(SLOT_TTY, false);

        // bluetooth status  蓝牙
        updateBluetooth();

        // Alarm clock 闹钟
        mService.setIcon(SLOT_ALARM_CLOCK, R.drawable.stat_sys_alarm, 0, null);
        mService.setIconVisibility(SLOT_ALARM_CLOCK, false);

        // zen
        mService.setIcon(SLOT_ZEN, R.drawable.stat_sys_zen_important, 0, null);
        mService.setIconVisibility(SLOT_ZEN, false);

        // volume 声音
        mService.setIcon(SLOT_VOLUME, R.drawable.stat_sys_ringer_vibrate, 0, null);
        mService.setIconVisibility(SLOT_VOLUME, false);
        updateVolumeZen();

        // cast 投射
        mService.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, 0, null);
        mService.setIconVisibility(SLOT_CAST, false);
        mCast.addCallback(mCastCallback);

        // hotspot热点
        mService.setIcon(SLOT_HOTSPOT, R.drawable.stat_sys_hotspot, 0,
                mContext.getString(R.string.accessibility_status_bar_hotspot));
        mService.setIconVisibility(SLOT_HOTSPOT, mHotspot.isHotspotEnabled());
        mHotspot.addCallback(mHotspotCallback);

        // managed profile
        mService.setIcon(SLOT_MANAGED_PROFILE, R.drawable.stat_sys_managed_profile_status, 0,
                mContext.getString(R.string.accessibility_managed_profile));
        mService.setIconVisibility(SLOT_MANAGED_PROFILE, false);
    }

四、startKeyguard()

    private void startKeyguard() {
        KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
        mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
                mStatusBarWindow, mStatusBarWindowManager, mScrimController);
        mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
    }

这一部分后面单独分析,,目前没了深入了解

 历史上的今天

  1. 2024: ToolBar的简单使用(0条评论)
  2. 2024: ActionBar中Menu使用(0条评论)
  3. 2023: 《阿里Android手册》笔记(0条评论)
  4. 2021: 骆一禾:月 亮(0条评论)
  5. 2019: Log工具类(0条评论)
版权声明 1、 本站名称: 笔友城堡
2、 本站网址: https://www.biumall.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权,请留言

暂无评论

暂无评论...

随机推荐

[摘]查找当前目录下所有文件某一行的内容

前言在做monkey时,会间隔把当前所有应用的内存占用打印出来,因此为了方便查看内存是否有持续增长,会使用命令查看所有dump的文件内容。好记性不如烂笔头正文以下在Window系统中的git bash环境中测试(或者算是Linux环境)find . -type f -name “*.tx...

嫣然若雪:余生,看淡所有,珍惜拥有

现实生活中,有太多的欲望,求不到,爱不得,为自己搭建了牢笼,囚禁在很深的执念里,得不到,放不下。人生本就不易,生活里本就有太多的苦,烦恼不捡自然无,要捡天天有,没有谁能把日子过得一直顺遂。有些人,因为自己的执念,让生活增添不必要的负担;有些人,因为一点小事,让自己活得心烦意乱。人生的痛苦都是自...

SQLite Expert的注册记录

前言SQLite Expert软件很不错,在使用数据库时,这个软件是查看数据库的号帮手,当然,这个也是偶尔使用。这里分析一下网上的注册方法。正文这里介绍下载和注册。下载官方下载对应的位数的SQLite Expert:http://www.sqliteexpert.com/downlo...

android.view.ViewRootImpl$CalledFromWrongThreadException

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.哎,对自己无语了,竟然一时犯了这...

[摘]深入浅出UML类图(三)

本文作者:刘伟  http://blog.csdn.net/lovelion类与类之间的关系(2)      2. 依赖关系依赖(Dependency)关系是一种使用关系,特定事物的改变有可能会影响到使用该事物的其他事物,在需要表示一个事物使用另一个事物时使用依赖关系。大多数情况下,...

常用的Monkey命令

Monkey的概念“猴子测试”是指没有测试经验的人甚至对计算机根本不了解的人(就像猴子一样)不需要知道程序的任何用户交互方面的知识,如果给他一个程序,他就会针对他看到的界面进行操作,其操作是无目的的、乱点乱按的。这种测试方式在产品周期中的早期阶段会找到很多很好的bug,为用户节省不少的时间。...