天天看點

Android螢幕分辨率擷取方法--源碼剖析

                                 本文來自 http://blog.csdn.net/liuxian13183/  ,引用必須注明出處!

在适配的過程中,有時我們會用到螢幕寬高,那麼如何獲得螢幕的分辨率?

方法有兩種:

第一種是通過WindowManager接口獲得Diaplay對象,通過Display對象來獲得

WindowManager manager = (WindowManager) context

.getSystemService(Context.WINDOW_SERVICE);

 Display display = manager.getDefaultDisplay();

 DisplayMetrics  outMetrics=new DisplayMetrics();

 display.getMetrics(outMetrics);

 screenHeight = outMetrics.heightPixels;

 screenWidth = outMetrics.widthPixels;

 //screenHeight = display.getHeight();此種方法已廢棄

//screenWidth = display.getWidth();此種方法已廢棄

或者

從源碼上來看,拿height來說:

private final Point mTmpPoint = new Point();

public int getHeight() {
        synchronized (mTmpPoint) {
            long now = SystemClock.uptimeMillis();
            if (now > (mLastGetTime+20)) {
                getSizeInternal(mTmpPoint, true);
                mLastGetTime = now;
            }
            return mTmpPoint.y;
        }
    }      
主要是找mTmpPoint 的y坐标
private void getSizeInternal(Point outSize, boolean doCompat) {
        try {
            IWindowManager wm = getWindowManager();
            if (wm != null) {
                wm.getDisplaySize(outSize);
                CompatibilityInfo ci;
                if (doCompat && (ci=mCompatibilityInfo.getIfNeeded()) != null) {
                    synchronized (mTmpMetrics) {
                        mTmpMetrics.noncompatWidthPixels = outSize.x;
                        mTmpMetrics.noncompatHeightPixels = outSize.y;
                        mTmpMetrics.density = mDensity;
                        ci.applyToDisplayMetrics(mTmpMetrics);
                        outSize.x = mTmpMetrics.widthPixels;
                        outSize.y = mTmpMetrics.heightPixels;
                    }
                }
            } else {
                // This is just for boot-strapping, initializing the
                // system process before the window manager is up.
                outSize.x = getRawWidth();
                outSize.y = getRawHeight();
            }
            if (false) {
                RuntimeException here = new RuntimeException("here");
                here.fillInStackTrace();
                Slog.v(TAG, "Returning display size: " + outSize, here);
            }
            if (DEBUG_DISPLAY_SIZE && doCompat) Slog.v(
                    TAG, "Returning display size: " + outSize);
        } catch (RemoteException e) {
            Slog.w("Display", "Unable to get display size", e);
        }
    }      
然後我們發現通過CompatibilityInfo對象設定metrics是一種方法,另一種是getRawHeight()
public int getRawHeight() {
        int h = getRawHeightNative();
        if (DEBUG_DISPLAY_SIZE) Slog.v(
                TAG, "Returning raw display height: " + h);
        return h;
    }
    private native int getRawHeightNative();      

最終是一native方法,通過底層實作。

方法二:通過Resource對象來獲得DisplayMetrics來取得

DisplayMetrics metrics = context.getResources().getDisplayMetrics();

screenHeight = metrics.heightPixels;

screenWidth = metrics.widthPixels;

總體來說,都是要取得DisplayMetrics,那麼我們來看看它的構成:

/**
     * Standard quantized DPI for low-density screens.
     */
    public static final int DENSITY_LOW = 120;

    /**
     * Standard quantized DPI for medium-density screens.
     */
    public static final int DENSITY_MEDIUM = 160;

    /**
     * Standard quantized DPI for 720p TV screens.  Applications should
     * generally not worry about this density, instead targeting
     * {@link #DENSITY_XHIGH} for 1080p TV screens.  For situations where
     * output is needed for a 720p screen, the UI elements can be scaled
     * automatically by the platform.
     */
    public static final int DENSITY_TV = 213;

    /**
     * Standard quantized DPI for high-density screens.
     */
    public static final int DENSITY_HIGH = 240;

    /**
     * Standard quantized DPI for extra-high-density screens.
     */
    public static final int DENSITY_XHIGH = 320;      

分别有預設的Density值

預設實作方法:

public void setToDefaults() {
        widthPixels = 0;
        heightPixels = 0;
        density = DENSITY_DEVICE / (float) DENSITY_DEFAULT;
        densityDpi = DENSITY_DEVICE;
        scaledDensity = density;
        xdpi = DENSITY_DEVICE;
        ydpi = DENSITY_DEVICE;
        noncompatWidthPixels = 0;
        noncompatHeightPixels = 0;
    }      
一般都要實作下面方面,來獲得想要的值
public void setTo(DisplayMetrics o) {
        widthPixels = o.widthPixels;
        heightPixels = o.heightPixels;
        density = o.density;
        densityDpi = o.densityDpi;
        scaledDensity = o.scaledDensity;
        xdpi = o.xdpi;
        ydpi = o.ydpi;
        noncompatWidthPixels = o.noncompatWidthPixels;
        noncompatHeightPixels = o.noncompatHeightPixels;
        noncompatDensity = o.noncompatDensity;
        noncompatScaledDensity = o.noncompatScaledDensity;
        noncompatXdpi = o.noncompatXdpi;
        noncompatYdpi = o.noncompatYdpi;
    }      
看下Resource類
public Resources(AssetManager assets, DisplayMetrics metrics,
            Configuration config, CompatibilityInfo compInfo) {
        mAssets = assets;
        mMetrics.setToDefaults();
        mCompatibilityInfo = compInfo;
        updateConfiguration(config, metrics);
        assets.ensureStringBlocks();
    }      
看到updateConfiguration(config, metrics);方法
/**
     * Store the newly updated configuration.
     */
    public void updateConfiguration(Configuration config,
            DisplayMetrics metrics) {
        updateConfiguration(config, metrics, null);
    }      
/**
     * @hide
     */
    public void updateConfiguration(Configuration config,
            DisplayMetrics metrics, CompatibilityInfo compat) {
        synchronized (mTmpValue) {
            if (false) {
                Slog.i(TAG, "**** Updating config of " + this + ": old config is "
                        + mConfiguration + " old compat is " + mCompatibilityInfo);
                Slog.i(TAG, "**** Updating config of " + this + ": new config is "
                        + config + " new compat is " + compat);
            }
            if (compat != null) {
                mCompatibilityInfo = compat;
            }
            if (metrics != null) {
                mMetrics.setTo(metrics);
            }      

我們會看到這樣的結果,是以在形成Resources的時候,metrics已經寫入。

可是剛才我們用的是this.getResouces直接來獲得的Resource對象

ContextThemeWrapper:

@Override
    public Resources getResources() {
        if (mResources != null) {
            return mResources;
        }
        if (mOverrideConfiguration == null) {
            mResources = super.getResources();
            return mResources;
        } else {
            Context resc = createConfigurationContext(mOverrideConfiguration);
            mResources = resc.getResources();
            return mResources;
        }
    }      

主要是在Context裡實作,具體怎麼實作,估計還是要看native的代碼才知道。

螢幕分辨率的問題就先介紹到這兒。

繼續閱讀