屏幕适配之百分比方案详解

屏幕适配之百分比方案详解

Android设备碎片化十分严重,在开发过程中的适配工作也非常很繁琐,有关屏幕适配的介绍请看之前的文章屏幕适配

最近看到DrawerLayoutsupport v4中提供的类,想到对google提供的这些支持库,自己一点都不熟悉,想着看看Google提供的支持库都有什么内容。结果看着看着在最后忽然看到了Percent Support Library。寻思怎么还百分比呢?仔细一看介绍,我擦,真是太有用了。

Percent Support Library

The Percent package provides APIs to support adding and managing percentage based dimensions in your app.

The Percent Support library adds support for the PercentLayoutHelper.PercentLayoutParams interface and various classes, such as PercentFrameLayout and PercentRelativeLayout.

After you download the Android Support Libraries, this library is located in the /extras/android/support/percent directory. For more information on how to set up your project, follow the instructions in Adding libraries with resources.

The Gradle build script dependency identifier for this library is as follows:

com.android.support:percent:23.3.0

看到了吗? 说提供了PercentFrameLayoutPercentRelativeLayout来支持百分比了。这样不就完美的解决了适配的问题嘛。啥也不说了,立马配置cradle来瞧瞧。

Subclass of FrameLayout that supports percentage based dimensions and margins. You can specify dimension or a margin of child by using attributes with “Percent” suffix.

上代码:

<android.support.percent.PercentFrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:src="@mipmap/ic_launcher"
        app:layout_widthPercent="50%"
        app:layout_heightPercent="50%"
        app:layout_marginTopPercent="25%"
        app:layout_marginLeftPercent="25%"/>
</android.support.percent.PercentFrameLayout>

效果如下:

完美.

支持的属性:

  • layout_widthPercent
  • layout_heightPercent
  • layout_marginPercent
  • layout_marginLeftPercent
  • layout_marginTopPercent
  • layout_marginRightPercent
  • layout_marginBottomPercent
  • layout_marginStartPercent
  • layout_marginEndPercent
  • layout_aspectRatio

It is not necessary to specify layout_width/height if you specify layout_widthPercent. However, if you want the view to be able to take up more space than what percentage value permits, you can add layout_width/height=”wrap_content”. In that case if the percentage size is too small for the View’s content, it will be resized using wrap_content rule.

如果指定了layout_widthPercent就不用指定layout_width/height属性了。(Studio可能会提示错误,设置忽略就好)。然而,如果你想要该View能够占用比设置的百分比值更大的空间时,你可以指定layout_widht/height=“wrap_content”。在这种情况下,如果设置的百分比值在显示内容时太小时,将会使用wrap_content的值重新计算。

就是这个意思:如果指定的百分比太小怕显示不开的话,也可以给它指定wrap_content属性,这样当显示不开的时候就会使用wrap_content的值。

如下:

<android.support.percent.PercentFrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        android:text="顶顶顶顶顶大大大"
        android:textSize="30dp"
        android:singleLine="true"
        app:layout_widthPercent="30%"
        app:layout_heightPercent="5%"
        app:layout_marginTopPercent="25%"
        app:layout_marginLeftPercent="25%"/>
</android.support.percent.PercentFrameLayout>

效果:

加入wrap_content后一点效果也没有啊,还是显示不全啊,还没加wrap_content一样,- -!

你也可以通过只设置width或者heightlayout_aspectRatio这种比例值的方式来让第另一个值自动计算。例如,如果你想要使用16:9的比例,你可以使用:

android:layout_width="300dp"
app:layout_aspectRatio="178%"

这样将会在宽固定为300dp的基础上以16:9(1.78:1)来计算高度。

PercentRelativeLayout的使用都是一样的,这里就不贴了。

那它是怎么实现的呢?其实就是内部给通过属性换算,把本布局的宽高和百分比去计算每个view的大小和位置。但是还有为什么上面设置的wrap_content无效呢?是我理解错了吗?

带着这两个疑问我们来看下源码:

public class PercentFrameLayout extends FrameLayout {
    private final PercentLayoutHelper mHelper = new PercentLayoutHelper(this);

    public PercentFrameLayout(Context context) {
        super(context);
    }

    public PercentFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public PercentFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 从名字上就能看出来下面就是处理如果指定百分比过小不足显示内容时,就去使用`wrap_content`的逻辑
        if (mHelper.handleMeasuredStateTooSmall()) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        mHelper.restoreOriginalParams();
    }

    public static class LayoutParams extends FrameLayout.LayoutParams
            implements PercentLayoutHelper.PercentLayoutParams {

        private PercentLayoutHelper.PercentLayoutInfo mPercentLayoutInfo;

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
            // PercentLayoutInfo中去解析自定义属性的值
            mPercentLayoutInfo = PercentLayoutHelper.getPercentLayoutInfo(c, attrs);
        }

        public LayoutParams(int width, int height) {
            super(width, height);
        }

        public LayoutParams(int width, int height, int gravity) {
            super(width, height, gravity);
        }

        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }

        public LayoutParams(MarginLayoutParams source) {
            super(source);
        }

        public LayoutParams(FrameLayout.LayoutParams source) {
            super((MarginLayoutParams) source);
            gravity = source.gravity;
        }

        public LayoutParams(LayoutParams source) {
            this((FrameLayout.LayoutParams) source);
            mPercentLayoutInfo = source.mPercentLayoutInfo;
        }

        @Override
        public PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo() {
            if (mPercentLayoutInfo == null) {
                mPercentLayoutInfo = new PercentLayoutHelper.PercentLayoutInfo();
            }

            return mPercentLayoutInfo;
        }

        @Override
        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
            PercentLayoutHelper.fetchWidthAndHeight(this, a, widthAttr, heightAttr);
        }
    }
}

源码不长,主要是三个部分:

  • 重写onMeasure,根据百分比转换成对应的尺寸
  • 重写onLayout
  • 自定义LayoutParams,在FrameLayout.LayoutParams的基础上多实现了一个接口。包含了PercentLayoutHelper.PercentLayoutInfo属性,而文档中对PercentLayoutInfo的介绍是Container for information about percentage dimensions and margins. It acts as an extension for LayoutParams.

我们也先一步步的来分析,首先看下mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);:

/**
     * Iterates over children and changes their width and height to one calculated from percentage
     * values.
     * @param widthMeasureSpec Width MeasureSpec of the parent ViewGroup.
     * @param heightMeasureSpec Height MeasureSpec of the parent ViewGroup.
     */
public void adjustChildren(int widthMeasureSpec, int heightMeasureSpec) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "adjustChildren: " + mHost + " widthMeasureSpec: "
                    + View.MeasureSpec.toString(widthMeasureSpec) + " heightMeasureSpec: "
                    + View.MeasureSpec.toString(heightMeasureSpec));
        }

        int widthHint = View.MeasureSpec.getSize(widthMeasureSpec);
        int heightHint = View.MeasureSpec.getSize(heightMeasureSpec);
        // mHost是由构造函数传递过来的,就是PercentFrameLayout自身。
        for (int i = 0, N = mHost.getChildCount(); i < N; i++) {
            View view = mHost.getChildAt(i);
            ViewGroup.LayoutParams params = view.getLayoutParams();
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "should adjust " + view + " " + params);
            }
            if (params instanceof PercentLayoutParams) {
                // 通过PercentLayoutParams. getPercentLayoutInfo()方法得到PercentLayoutInfo,至于PercentLayoutInfo类在上面也说过了。
                PercentLayoutInfo info =
                        ((PercentLayoutParams) params).getPercentLayoutInfo();
                if (Log.isLoggable(TAG, Log.DEBUG)) {
                    Log.d(TAG, "using " + info);
                }
                if (info != null) {
                    if (params instanceof ViewGroup.MarginLayoutParams) {
                        // PercentFrameLayout.LayoutParams继承自FrameLayout.LayoutParams,而FrameLayout.LayoutParams又继承自ViewGroup.MarginLayoutParams
                        info.fillMarginLayoutParams(view, (ViewGroup.MarginLayoutParams) params,
                                widthHint, heightHint);
                    } else {
                        info.fillLayoutParams(params, widthHint, heightHint);
                    }
                }
            }
        }
    }

所以上面代码的意思就是通过对每个子View调用getLayoutParams方法,然后从该LayoutParams中获取到它的PercentLayoutInfo属性,然后再调用PercentLayoutInfo.fillMarginLayoutParams()方法。

那我们继续看一下PercentLayoutInfo.fillMarginLayoutParams()方法的实现,该方法是根据百分比去设置尺寸和margin:

/**
         * Fills {@code ViewGroup.MarginLayoutParams} dimensions and margins based on percentage
         * values.
         */
        public void fillMarginLayoutParams(View view, ViewGroup.MarginLayoutParams params,
                int widthHint, int heightHint) {
            // 根据百分比值设置View的尺寸
            fillLayoutParams(params, widthHint, heightHint);

            // 从注释中就能知道,fillLayoutParams是计算尺寸,那下面这部分就是处理margin了
            // mPreservedParams来记录原始的margin值
            // Preserve the original margins, so we can restore them after the measure step.
            mPreservedParams.leftMargin = params.leftMargin;
            mPreservedParams.topMargin = params.topMargin;
            mPreservedParams.rightMargin = params.rightMargin;
            mPreservedParams.bottomMargin = params.bottomMargin;
            MarginLayoutParamsCompat.setMarginStart(mPreservedParams,
                    MarginLayoutParamsCompat.getMarginStart(params));
            MarginLayoutParamsCompat.setMarginEnd(mPreservedParams,
                    MarginLayoutParamsCompat.getMarginEnd(params));

            if (leftMarginPercent >= 0) {
                params.leftMargin = (int) (widthHint * leftMarginPercent);
            }
            if (topMarginPercent >= 0) {
                params.topMargin = (int) (heightHint * topMarginPercent);
            }
            if (rightMarginPercent >= 0) {
                params.rightMargin = (int) (widthHint * rightMarginPercent);
            }
            if (bottomMarginPercent >= 0) {
                params.bottomMargin = (int) (heightHint * bottomMarginPercent);
            }
            boolean shouldResolveLayoutDirection = false;
            if (startMarginPercent >= 0) {
                MarginLayoutParamsCompat.setMarginStart(params,
                        (int) (widthHint * startMarginPercent));
                shouldResolveLayoutDirection = true;
            }
            if (endMarginPercent >= 0) {
                MarginLayoutParamsCompat.setMarginEnd(params,
                        (int) (widthHint * endMarginPercent));
                shouldResolveLayoutDirection = true;
            }
            if (shouldResolveLayoutDirection && (view != null)) {
                // Force the resolve pass so that start / end margins are propagated to the
                // matching left / right fields
                MarginLayoutParamsCompat.resolveLayoutDirection(params,
                        ViewCompat.getLayoutDirection(view));
            }
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "after fillMarginLayoutParams: (" + params.width + ", " + params.height
                        + ")");
            }
        }

再看一下PercentLayoutInfo.fillLayoutParams()的实现,该方法是通过百分比设置View的尺寸:

        /**
         * Fills {@code ViewGroup.LayoutParams} dimensions based on percentage values.
         */
        public void fillLayoutParams(ViewGroup.LayoutParams params, int widthHint,
                int heightHint) {
            // mPreservedParams来记录原始的宽高值
            // Preserve the original layout params, so we can restore them after the measure step.
            mPreservedParams.width = params.width;
            mPreservedParams.height = params.height;

            // We assume that width/height set to 0 means that value was unset. This might not
            // necessarily be true, as the user might explicitly set it to 0. However, we use this
            // information only for the aspect ratio. If the user set the aspect ratio attribute,
            // it means they accept or soon discover that it will be disregarded.
            final boolean widthNotSet =
                    (mPreservedParams.mIsWidthComputedFromAspectRatio
                            || mPreservedParams.width == 0) && (widthPercent < 0);
            final boolean heightNotSet =
                    (mPreservedParams.mIsHeightComputedFromAspectRatio
                            || mPreservedParams.height == 0) && (heightPercent < 0);

            // 如果指定了百分比属性,就用宽高值和百分比去算出具体的宽高
            if (widthPercent >= 0) {
                params.width = (int) (widthHint * widthPercent);
            }

            if (heightPercent >= 0) {
                params.height = (int) (heightHint * heightPercent);
            }
            // 如果指定了宽高的比例值,就用比例值去算出宽高,从这里能看出`aspectRatio`的优先级比百分比要高。他可以覆盖百分比之前设置的值。
            if (aspectRatio >= 0) {
                if (widthNotSet) {
                    params.width = (int) (params.height * aspectRatio);
                    // Keep track that we‘ve filled the width based on the height and aspect ratio.
                    mPreservedParams.mIsWidthComputedFromAspectRatio = true;
                }
                if (heightNotSet) {
                    params.height = (int) (params.width / aspectRatio);
                    // Keep track that we‘ve filled the height based on the width and aspect ratio.
                    mPreservedParams.mIsHeightComputedFromAspectRatio = true;
                }
            }

            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "after fillLayoutParams: (" + params.width + ", " + params.height + ")");
            }
        }

到这里onMeasure中通过百分比值设置宽高以及margin的部分就看完了,那我们接着看一下关于百分比值过小时对wrap_content的处理:

if (mHelper.handleMeasuredStateTooSmall()) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

看一下PercentLayoutHelper.handleMeasuredStateTooSmall()方法的实现:

/**
     * Iterates over children and checks if any of them would like to get more space than it
     * received through the percentage dimension.
     *
     * If you are building a layout that supports percentage dimensions you are encouraged to take
     * advantage of this method. The developer should be able to specify that a child should be
     * remeasured by adding normal dimension attribute with {@code wrap_content} value. For example
     * he might specify child‘s attributes as {@code app:layout_widthPercent="60%p"} and
     * {@code android:layout_width="wrap_content"}. In this case if the child receives too little
     * space, it will be remeasured with width set to {@code WRAP_CONTENT}.
     *
     * @return True if the measure phase needs to be rerun because one of the children would like
     * to receive more space.
     */
    public boolean handleMeasuredStateTooSmall() {
        boolean needsSecondMeasure = false;
        for (int i = 0, N = mHost.getChildCount(); i < N; i++) {
            View view = mHost.getChildAt(i);
            ViewGroup.LayoutParams params = view.getLayoutParams();
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "should handle measured state too small " + view + " " + params);
            }
            if (params instanceof PercentLayoutParams) {
                PercentLayoutInfo info =
                        ((PercentLayoutParams) params).getPercentLayoutInfo();
                if (info != null) {
                    // shouldHandleMeasuredWidthTooSmall方法来进行判断
                    if (shouldHandleMeasuredWidthTooSmall(view, info)) {
                        needsSecondMeasure = true;
                        params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
                    }
                    if (shouldHandleMeasuredHeightTooSmall(view, info)) {
                        needsSecondMeasure = true;
                        params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
                    }
                }
            }
        }
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "should trigger second measure pass: " + needsSecondMeasure);
        }
        return needsSecondMeasure;
    }

那继续看一下shouldHandleMeasuredWidthTooSmall()方法:

private static boolean shouldHandleMeasuredWidthTooSmall(View view, PercentLayoutInfo info) {
        int state = ViewCompat.getMeasuredWidthAndState(view) & ViewCompat.MEASURED_STATE_MASK;
        return state == ViewCompat.MEASURED_STATE_TOO_SMALL && info.widthPercent >= 0 &&
                info.mPreservedParams.width == ViewGroup.LayoutParams.WRAP_CONTENT;
    }

继续看ViewCompat.getMeasuredWidthAndState()的源码:

public static int getMeasuredWidthAndState(View view) {
        return IMPL.getMeasuredWidthAndState(view);
    }

继续往下看,这个IMPL是什么呢?

static final ViewCompatImpl IMPL;
    static {
        final int version = android.os.Build.VERSION.SDK_INT;
        if (version >= 23) {
            IMPL = new MarshmallowViewCompatImpl();
        } else if (version >= 21) {
            IMPL = new LollipopViewCompatImpl();
        } else if (version >= 19) {
            IMPL = new KitKatViewCompatImpl();
        } else if (version >= 17) {
            IMPL = new JbMr1ViewCompatImpl();
        } else if (version >= 16) {
            IMPL = new JBViewCompatImpl();
        } else if (version >= 15) {
            IMPL = new ICSMr1ViewCompatImpl();
        } else if (version >= 14) {
            IMPL = new ICSViewCompatImpl();
        } else if (version >= 11) {
            IMPL = new HCViewCompatImpl();
        } else if (version >= 9) {
            IMPL = new GBViewCompatImpl();
        } else if (version >= 7) {
            IMPL = new EclairMr1ViewCompatImpl();
        } else {
            IMPL = new BaseViewCompatImpl();
        }
    }

继续看,IMPL.getMeasuredWidthAndState(),方法其实最终就是使用的BaseViewCompatImpl.getMeasuredWidthAndState()方法,接着看它的的源码:

 @Override
        public int getMeasuredWidthAndState(View view) {
            return view.getMeasuredWidth();
        }

最后就是调用了getMeasuredWidth()方法。 没毛病- -!

onMeasure的到这里就分析完了。

那接着来看一下onLayout方法,onLayout方法直接调用了PercentLayoutHelper.restoreOriginalParams,:

/**
     * Iterates over children and restores their original dimensions that were changed for
     * percentage values. Calling this method only makes sense if you previously called
     * {@link PercentLayoutHelper#adjustChildren(int, int)}.
     */
    public void restoreOriginalParams() {
        for (int i = 0, N = mHost.getChildCount(); i < N; i++) {
            View view = mHost.getChildAt(i);
            ViewGroup.LayoutParams params = view.getLayoutParams();
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "should restore " + view + " " + params);
            }
            if (params instanceof PercentLayoutParams) {
                PercentLayoutInfo info =
                        ((PercentLayoutParams) params).getPercentLayoutInfo();
                if (Log.isLoggable(TAG, Log.DEBUG)) {
                    Log.d(TAG, "using " + info);
                }
                if (info != null) {
                    if (params instanceof ViewGroup.MarginLayoutParams) {
                        info.restoreMarginLayoutParams((ViewGroup.MarginLayoutParams) params);
                    } else {
                        info.restoreLayoutParams(params);
                    }
                }
            }
        }
    }

调用了PercentLayoutInfo.restoreMarginLayoutParams()方法,我们看下它的源码:

/**
         * Restores original dimensions and margins after they were changed for percentage based
         * values. Calling this method only makes sense if you previously called
         * {@link PercentLayoutHelper.PercentLayoutInfo#fillMarginLayoutParams}.
         */
        public void restoreMarginLayoutParams(ViewGroup.MarginLayoutParams params) {
            restoreLayoutParams(params);
            // mPreservedParams的值在之前ad
            params.leftMargin = mPreservedParams.leftMargin;
            params.topMargin = mPreservedParams.topMargin;
            params.rightMargin = mPreservedParams.rightMargin;
            params.bottomMargin = mPreservedParams.bottomMargin;
            MarginLayoutParamsCompat.setMarginStart(params,
                    MarginLayoutParamsCompat.getMarginStart(mPreservedParams));
            MarginLayoutParamsCompat.setMarginEnd(params,
                    MarginLayoutParamsCompat.getMarginEnd(mPreservedParams));
        }

意思是说,再他们被以百分比为基础的数据更改之后恢复成原始的尺寸和margin。

然后继续看一下restoreLayoutParams():

/**
         * Restores original dimensions after they were changed for percentage based values. Calling
         * this method only makes sense if you previously called
         * {@link PercentLayoutHelper.PercentLayoutInfo#fillLayoutParams}.
         */
        public void restoreLayoutParams(ViewGroup.LayoutParams params) {
            if (!mPreservedParams.mIsWidthComputedFromAspectRatio) {
                // Only restore the width if we didn‘t compute it based on the height and
                // aspect ratio in the fill pass.
                params.width = mPreservedParams.width;
            }
            if (!mPreservedParams.mIsHeightComputedFromAspectRatio) {
                // Only restore the height if we didn‘t compute it based on the width and
                // aspect ratio in the fill pass.
                params.height = mPreservedParams.height;
            }

            // Reset the tracking flags.
            mPreservedParams.mIsWidthComputedFromAspectRatio = false;
            mPreservedParams.mIsHeightComputedFromAspectRatio = false;
        }

好了到这里也分析完了onLayout的方法,大意就是在onMeasure之前先将原始的宽高和margin都备份一下,然后在onMeasure中根据百分比去设置对应的宽高和margin,等到设置完之后在onLayout方法中再去将这些值恢复到之前备份的起始数据。说实话我没看明白为什么要这样做?

通过上面的代码分析我们知道对布局影响力的优先顺序: app:layout_aspectRatio > app:layout_heightPercent > android:layout_height如果我们同时都设置这三个参数值的话,最终会用app:layout_aspectRatio的值。

遗留问题:

  • 为什么在onLayout方法中去恢复数据,这有什么作用?
  • 看代码在处理如果指定的百分比过小但又指定wrap_content时,会重新根据wrap_content去重新计算的逻辑没有错,但是为什么我在上面测试的时候确没效果?

有知道上面这两个问题的告诉我一下。



更多内容请关注Github

时间: 2024-10-06 18:09:04

屏幕适配之百分比方案详解的相关文章

Android # 图片自动适配屏幕,APK反编译详解,Google Maps Android API,Keytool

本文主题:(图片缩放)自动适配屏幕,APK反编译详解,Google Maps Android API,Keytool  (图片缩放)自动适配屏幕支持缩放旋转,自动居中的imageview http://deanandbai-gmail-com.iteye.com/blog/1850329 apk反编译工具 http://pan.baidu.com/s/1qWFcueC Android APK反编译详解 http://blog.csdn.net/ithomer/article/details/67

基于rem的移动端响应式适配方案(详解) 移动端H5页面的设计稿尺寸大小规范

基于rem的移动端响应式适配方案(详解) : https://www.jb51.net/article/118067.htm 移动端H5页面的设计稿尺寸大小规范 http://www.tuyiyi.com/v/53039.html 原文地址:https://www.cnblogs.com/bydzhangxiaowei/p/9536126.html

Nginx的负载均衡方案详解

Nginx的负载均衡方案详解 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs Nginx的负载均衡方案有: 1.轮询 轮询即Round Robin,根据Nginx配置文件中的顺序,依次把客户端的Web请求分发到不同的后端服务器. 配置的例子如下: http{ upstream sampleapp { server <<dns entry or IP Address(optional with port)>>; server <&l

iOS多线程实现方案详解01——NSThread

NSThread 一.创建和启动线程 1.开线程的几种方式 1)先创建线程,后启动 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [thread start]; 2)创建线程后自动直接启动 [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil]; [sel

传美云商系统软件方案详解

传美云商系统是通过颐和果园让公众所知道的,颐和果园是做水果生鲜食品市场的,运用传美云商这个软件为什么能打通互联网市场?究其主要原因是因新零售正在发生日新月异的变化! 任何新零售都需要数据的支撑.办公室场景的一大优点是消费者比较稳定,通过奇点云打造的智能货架,可以很好的做到数据采集和沉淀,深度洞察办公室人群消费行为,对商家精细化运营和商品管理做出优化指导. "AI智能系统"会让每一个消费者成为会员(消费即会员),并自动记录消费者的停留时间和购买喜好,获取详细的消费行为.通过数据分析,推算

Android中图片压缩方案详解

如感觉排版不舒服,可移步至此处查看 图片的展示可以说在我们任何一个应用中都避免不了,可是大量的图片就会出现很多的问题,比如加载大图片或者多图时的OOM问题,可以移步到Android高效加载大图.多图避免程序OOM.还有一个问题就是图片的上传下载问题,往往我们都喜欢图片既清楚又占的内存小,也就是尽可能少的耗费我们的流量,这就是我今天所要讲述的问题:图片的压缩方案的详解. 1.质量压缩法 设置bitmap options属性,降低图片的质量,像素不会减少 第一个参数为需要压缩的bitmap图片对象,

App域名劫持之DNS高可用 - 开源版HttpDNS方案详解(转)

http://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=209805123&idx=1&sn=ced8d67c3e2cc3ca38ef722949fa21f8&3rd=MzA3MDU4NTYzMw==&scene=6#rd 主题 开源 本文根据冯磊和赵星宇在“高可用架构”微信群所做的HttpDNS智能缓存库原理整理而成,转发请注明来自微信公众号ArchNotes. 冯磊,目前主要从事手机应用平台的构建,任职新浪网技术

高并发架构系列:Redis缓存和MySQL数据一致性方案详解

一.需求起因在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库.这个业务场景,主要是解决读数据从Redis缓存,一般都是按照下图的流程来进行业务操作.读取缓存步骤一般没有什么问题,但是一旦涉及到数据更新:数据库和缓存更新,就容易出现缓存(Redis)和数据库(MySQL)间的数据一致性问题. 不管是先写MySQL数据库,再删除Redis缓存:还是先删除缓存,再写库,都有可能出现数

jQuery数据缓存方案详解:$.data()的使用

我们经常使用隐藏控件或者是js全局变量来临时存储数据,全局变量容易导致命名污染,隐藏控件导致经常读写dom浪费性能.jQuery提供了自己的数据缓存方案,能够达到和隐藏控件.全局变量相同的效果,但是jQuery实现方式更优雅.为了更好地使用jQuery数据缓存方案,我们需要掌握$.data().$.cache.$.expando.$.hasData().$.removeData(). $.hasData()用来判断某个对象是否有附加的属性,可以给任何JavaScript对象和HTMLElemen