[转]截图原理(一)——Android自动化测试学习历程(2)

三、Robotium的截屏处理的代码分析

步骤:

(1)

代码分析:

追本溯源,开始找路。。。

第一步跳转到的函数:takeScreenshot(String name)

复制代码
/**
     * Takes a screenshot and saves it with the specified name in "/sdcard/Robotium-Screenshots/". 
     * Requires write permission (android.permission.WRITE_EXTERNAL_STORAGE) in AndroidManifest.xml of the application under test.
     *
     * @param name the name to give the screenshot
     *
     */
//上面的话翻译下来就是:存储的位置确定了,就是在mnt/sdcard/Robotium-Screenshots/目录下
//但是需要写sd卡的权限,需要给under test的application在AndroidManifest.xml中配置permission,那么这里也就解释了我上面的运行过程中第二个问题

    public void takeScreenshot(String name){
        takeScreenshot(name, 100);
    }
复制代码
第二步跳转到的函数:takeScreenshot(String name, int quality)

复制代码
/**
     * Takes a screenshot and saves the image with the specified name in "/sdcard/Robotium-Screenshots/". 
     * Requires write permission (android.permission.WRITE_EXTERNAL_STORAGE) in AndroidManifest.xml of the application under test.
     *
     * @param name the name to give the screenshot
     * @param quality the compression rate. From 0 (compress for lowest size) to 100 (compress for maximum quality)
     *
     */
//上面的话翻译下来就是:图片存储位置以及读写权限与第一步中相同
//参数分别表示picture的name,以及清晰度(从0到100),默认是100,当然你也可以直接在函数中调用这个函数,然后设置这个quality的值

    public void takeScreenshot(String name, int quality){
        screenshotTaker.takeScreenshot(name, quality);
    }
复制代码
第三步跳转到的函数:screenshotTaker.takeScreenshot(String name, int quality)

复制代码
/**
     * Takes a screenshot and saves it in "/sdcard/Robotium-Screenshots/". 
     * Requires write permission (android.permission.WRITE_EXTERNAL_STORAGE) in AndroidManifest.xml of the application under test.
     * 
     * @param view the view to take screenshot of
     * @param name the name to give the screenshot image
     * @param quality the compression rate. From 0 (compress for lowest size) to 100 (compress for maximum quality).
     */
//第三步走到了一个新的类中,是screenShotTaker的类
//这个才是真正的执行Screenshot的函数,这个才是截图的逻辑
    public void takeScreenshot(final String name, final int quality) {
        //1、得到目前屏幕所有视图
        View decorView = getScreenshotView();
        if(decorView == null) 
            return;
        //2、初始化
        initScreenShotSaver();
        //3、实例化截图对象
        ScreenshotRunnable runnable = new ScreenshotRunnable(decorView, name, quality);
        //4、调用截图对象的run方法
        activityUtils.getCurrentActivity(false).runOnUiThread(runnable);
    }
复制代码
第四步(1 得到屏幕所有视图)跳转到的函数:getScreenshotView()

复制代码
/**
     * Gets the proper view to use for a screenshot.  
     */
    private View getScreenshotView() {
        //获取到屏幕上的view
        View decorView = viewFetcher.getRecentDecorView(viewFetcher.getWindowDecorViews());
        final long endTime = SystemClock.uptimeMillis() + Timeout.getSmallTimeout();

        while (decorView == null) {    

            final boolean timedOut = SystemClock.uptimeMillis() > endTime;

            if (timedOut){
                return null;
            }
            sleeper.sleepMini();
            decorView = viewFetcher.getRecentDecorView(viewFetcher.getWindowDecorViews());
        }
        wrapAllGLViews(decorView);

        return decorView;
    }
复制代码
 第五步跳转到的函数:viewFetcher.getWindowDecorViews()

复制代码
/**
     * Returns the WindorDecorViews shown on the screen.
     * 
     * @return the WindorDecorViews shown on the screen
     */
    //翻译下来就是:获取到展示在screen上的所有WindowDecorViews,是一个View的数组,然后这个view的数组返回后,再作为viewFetcher.getRecentDecorView的参数
    //用反射方法去获取 View 视图数组
    
    @SuppressWarnings("unchecked")
    public View[] getWindowDecorViews()
    {
        Field viewsField;
        Field instanceField;
        try {
            viewsField = windowManager.getDeclaredField("mViews");
            instanceField = windowManager.getDeclaredField(windowManagerString);
            viewsField.setAccessible(true);
            instanceField.setAccessible(true);
            Object instance = instanceField.get(null);
            View[] result;
            if (android.os.Build.VERSION.SDK_INT >= 19) {
                result = ((ArrayList<View>) viewsField.get(instance)).toArray(new View[0]);
            } else {
                result = (View[]) viewsField.get(instance);
            }
            return result;
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
    
复制代码
第六步跳转到的函数:viewFetcher.getRecentDecorView(View[] views)

复制代码
/**
     * Returns the most recent DecorView
     *
     * @param views the views to check
     * @return the most recent DecorView
     */
     //翻译下来就是:返回最近的DecorView


     public final View getRecentDecorView(View[] views) {
         if(views == null)
             return null;
         
         final View[] decorViews = new View[views.length];
         int i = 0;
         View view;
      //通过遍历View数组,来得到most recent DecorView
         for (int j = 0; j < views.length; j++) {
             view = views[j];
             if (view != null && view.getClass().getName()
                     .equals("com.android.internal.policy.impl.PhoneWindow$DecorView")) {
                 decorViews[i] = view;
                 i++;
             }
         }
         return getRecentContainer(decorViews);
     }
复制代码
第七步:(1中的获取屏幕已经结束,看2的init操作)

复制代码
/**
     * This method initializes the aysnc screenshot saving logic
     */
  //翻译下来就是:初始化一个aysnc(异步)的sreenshot的保存逻辑

    private void initScreenShotSaver() {
        if(screenShotSaverThread == null || screenShotSaver == null) {
            //声明一个HandlerThread对象
            screenShotSaverThread = new HandlerThread("ScreenShotSaver");
            screenShotSaverThread.start();
            //把screenShotSaverThread捆绑到handler
            screenShotSaver = new ScreenShotSaver(screenShotSaverThread);
        }
    }
复制代码
但是这里用到了HandlerThread和Handler,看之。。。

第八步跳转的函数:ScreenShotSaver(HandlerThread thread)

复制代码
/**
     * This class is a Handler which deals with saving the screenshots on a separate thread.
     *
     * The screenshot logic by necessity has to run on the ui thread.  However, in practice
     * it seems that saving a screenshot (with quality 100) takes approx twice as long
     * as taking it in the first place. 
     *
     * Saving the screenshots in a separate thread like this will thus make the screenshot
     * process approx 3x faster as far as the main thread is concerned.
     *
     */
   //翻译下来就是:这是一个继承自Handler,在一个单独的thread上处理如何存储sreenchots的类
     //screenshot的逻辑必须要跑在ui线程上,然而,事实上,好像这个保存screenshot反而花费了将近2倍的时间
     //保存这个screenshots在另一个线程中,就会使得这个处理能够快三倍,当然是与跑在主线程上相比而言

    private class ScreenShotSaver extends Handler {
        public ScreenShotSaver(HandlerThread thread) {
            super(thread.getLooper());
        }
复制代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值