1. 程式人生 > >Android預設頭像那些事兒

Android預設頭像那些事兒

Android應用市場中幾乎所有APP中都會涉及使用者體系.當然也就需要頁面去處理使用者資訊的展示、使用者頭像的展示等.對於使用者頭像展示,有很多優秀的圖片載入框架,平常寫專案會經常使用到這些圖片載入框架,使用起來也很方便,效率也比較高.但是面對不同的需求時,處理的方式可能就有些不同.下面分析幾種需求.

文章使用Glide框架, 當然其他的圖片載入框架處理方式應該相似,就不多做介紹.簡單介紹下Glide的整合配置

首先配置一下Glide.在build.grade中新增對Gilde的引用及網路框架的引用

compile 'com.github.bumptech.glide:glide:3.7.0'
//OkHttp 3.x
compile 'com.github.bumptech.glide:okhttp3-integration:
[email protected]
' compile 'com.squareup.okhttp3:okhttp:3.2.0’

然後配置一下許可權

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE”/>

接著就可以使用Glide了.

分析

1) 第一種需求

設定一個預設的頭像圖片顯示,這種需求是最常見,也是最容易處理的.
用Glide一句程式碼就可以實現,如下

Glide.with(Activity).load("頭像地址URL").placeholder(R.mipmap.xxxx).dontAnimate().into(ImageView);

with中的引數可以是Activity,fragment,context.
placeholder中的引數就是專案中預設圖片的資源.
dontAnimate方法是取消動畫效果
into中的引數當然就是需要展示影象的ImageView

2) 第二種需求

設定一個圓形(圓角)的預設頭像圖片顯示,這種需求也比較常見,唯一的問題就是圓形(圓角)的圖片展示.對於圓形圖片展示,因為用到Glide所以這裡想到最簡便的解決方法就是找一個繼承自ImageView的自定義控制元件.有很多,文章選用CircleImageView來進行演示,有興趣的童鞋可以深入看一下實現.
github地址

https://github.com/hdodenhof/CircleImageView

那面對這種需求,就可以這樣寫

Glide.with(Activity).load("頭像地址URL")
        .placeholder(R.mipmap.xxxx).dontAn imate().into(CircleImageView);

into中引數為圓形自定義控制元件.

3) 第三種需求

設定一個帶有隨機背景顏色和文字的預設圖片展示,這種需求往往出現在通訊錄,好友等場景下,文字的目的是為了讓使用者更快的找到自己想找的目標(當然,我也是最近寫專案,產品提的這種需求),隨機背景顏色是為了更加美觀(我認為的- -~).
好了,面對這種需求,得先考慮一下怎麼去做,如果去適應Glide,那就看一下placeholder方法,可以看到Glide提供了兩種方法,如下

/**
 * {@inheritDoc}
 */
@Override
public DrawableRequestBuilder<ModelType> placeholder(int resourceId) {
    super.placeholder(resourceId);
    return this;
}

/**
 * {@inheritDoc}
 */
@Override
public DrawableRequestBuilder<ModelType> placeholder(Drawable drawable) {
    super.placeholder(drawable);
    return this;
}

第一個方法是之前用到的,引數是一個預設的資原始檔,第二個過載方法的引數是一個Drawable,顯然文字是變化的,資原始檔並不合適,只能在第二個過載方法上考慮一下.怎麼做呢?其實很簡單,可以通過安卓提供的方法建立一個帶有文字和背景顏色的Drawable物件.貼一下完整程式碼,比較簡單

package com.angent.defaultavatardemo.utils;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;

/**
 * Created by junweiliu on 17/1/18.
 */
public class MakeRandomPhoto {
    /**
     * 預設字型大小
     */
    private final int DEFAULT_FONT_SIZE = 20;
    /**
     * 預設字型大小
     */
    private final int DEFAULT_FONT_COLOR = Color.WHITE;
    /**
     * 預設的圖片寬
     */
    private final int DEFAULT_WIDTH = 60;
    /**
     * 預設的圖片高
     */
    private final int DEFAULT_HEIGHT = 60;
    /**
     * 預設顯示的文字數目
     */
    private final int DEFAULT_SHOW_NUM = 2;
    /**
     * 預設的圖片顏色
     */
    private final int DEFAULT_COLOR = Color.BLUE;
    /**
     * 圖片寬高
     */
    private int width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT;
    /**
     * 圖片顏色
     */
    private int color = DEFAULT_COLOR;
    /**
     * 文字大小
     */
    private int fontSize = DEFAULT_FONT_SIZE;
    /**
     * 文字顏色
     */
    private int fontColor = DEFAULT_FONT_COLOR;
    /**
     * 預設顯示的文字數
     */
    private int showNum = DEFAULT_SHOW_NUM;
    /**
     * 畫筆
     */
    private Paint mPaint;
    /**
     * 畫筆屬性
     */
    private Paint.FontMetrics fm;
    /**
     * 單例
     */
    public static MakeRandomPhoto instance;


    /**
     * 獲取單例
     *
     * @return
     */
    public static MakeRandomPhoto getInstance() {
        if (instance == null) {
            synchronized (MakeRandomPhoto.class) {
                if (instance == null) {
                    instance = new MakeRandomPhoto();
                }
            }
        }
        return instance;
    }

    /**
     * 設定圖片寬
     *
     * @return
     */
    public MakeRandomPhoto setWidth(int width) {
        if (0 == width) {
            this.width = DEFAULT_WIDTH;
        } else {
            this.width = width;
        }
        return instance;
    }

    /**
     * 設定圖片背景顏色
     *
     * @return
     */
    public MakeRandomPhoto setBackGroudColor(int color) {
        if (0 == color) {
            this.color = DEFAULT_COLOR;
        } else {
            this.color = color;
        }
        return this;
    }

    /**
     * 設定圖片高
     *
     * @return
     */
    public MakeRandomPhoto setHeight(int height) {
        if (0 == height) {
            this.height = DEFAULT_HEIGHT;
        } else {
            this.height = height;
        }
        return this;
    }

    /**
     * 設定文字顏色
     *
     * @return
     */
    public MakeRandomPhoto setTxtColor(int fontcolor) {
        if (0 == fontcolor) {
            this.fontColor = DEFAULT_FONT_COLOR;
        } else {
            this.fontColor = fontcolor;
        }
        return this;
    }

    /**
     * 設定文字大小
     *
     * @return
     */
    public MakeRandomPhoto setTxtSize(int fontsize) {
        if (0 == fontsize) {
            this.fontSize = DEFAULT_FONT_SIZE;
        } else {
            this.fontSize = fontsize;
        }
        return this;
    }

    /**
     * 設定顯示文字個數
     *
     * @return
     */
    public MakeRandomPhoto setShowNum(int showNum) {
        if (0 == showNum) {
            this.showNum = DEFAULT_SHOW_NUM;
        } else {
            this.showNum = showNum;
        }
        return this;
    }

    /**
     * 建立隨機圖片
     *
     * @return
     */
    public Bitmap makeRandomPhotoBp(String txt) {
        if (null == txt || "".equals(txt)) {
            txt = "    ";
        }
        // 處理展示的文字
        if (txt.length() > showNum) {
            txt = txt.substring(txt.length() - showNum);
        }
        // 這裡使用RGB_565,系統開銷小一點
        Bitmap bp = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        Canvas c = new Canvas(bp);
        mPaint = new Paint();
        mPaint.setColor(fontColor);
        mPaint.setTextSize(fontSize);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setAntiAlias(true);
        fm = mPaint.getFontMetrics();
        // 設定背景顏色
        c.drawColor(ColorUtils.getRandomColor(txt.hashCode()));
        // 居中顯示
        c.drawText(txt, width / 2, height / 2 - fm.descent + (fm.descent - fm.ascent) / 2, mPaint);
        c.save(Canvas.ALL_SAVE_FLAG);//儲存
        c.restore();//
        return bp;
    }


    /**
     * 建立隨機圖片(Drawable)
     *
     * @return
     */
    public Drawable makeRandomPhotoDrawable(String txt) {
        Drawable db = new BitmapDrawable(makeRandomPhotoBp(txt));
        return db;
    }

    /**
     * 建立群組影象
     *
     * @param leftTopBp
     * @param rightTopBp
     * @param leftBottomBp
     * @param rightBottomBp
     * @return
     */
    public Bitmap makeGroupPhotoBp(Bitmap leftTopBp, Bitmap rightTopBp, Bitmap leftBottomBp, Bitmap rightBottomBp) {
        Bitmap bp = Bitmap.createBitmap(width * 2, height * 2, Bitmap.Config.RGB_565);
        Canvas c = new Canvas(bp);
        Paint mPaint = new Paint();
        // 繪製左上角
        c.drawBitmap(leftTopBp, 0, 0, mPaint);
        // 繪製右上角
        c.drawBitmap(rightTopBp, width, 0, mPaint);
        // 繪製左下角
        c.drawBitmap(leftBottomBp, 0, height, mPaint);
        // 繪製右下角
        c.drawBitmap(rightBottomBp, width, height, mPaint);
        c.save(Canvas.ALL_SAVE_FLAG);//儲存
        c.restore();
        return bp;
    }

    /**
     * 建立群組圖片(Drawable)
     *
     * @return
     */
    public Drawable makeGroupPhotoDrawable(Bitmap leftTopBp, Bitmap rightTopBp, Bitmap leftBottomBp, Bitmap rightBottomBp) {
        Drawable db = new BitmapDrawable(makeGroupPhotoBp(leftTopBp, rightTopBp, leftBottomBp, rightBottomBp));
        return db;
    }
}

使用方法,例如在介面卡中

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        viewHolder = null;
        UserBean bean = mDatas.get(position);
        if (convertView == null) {
            convertView = mInflater.from(mContext).inflate(R.layout.item_user, null);
            viewHolder = new ViewHolder();
            viewHolder.userNameTv = (TextView) convertView.findViewById(R.id.tv_user_name);
            viewHolder.userPhotoIv = (ImageView) convertView.findViewById(R.id.ci_user_photo);
            viewHolder.userPhotoTv = (TextView) convertView.findViewById(R.id.tv_user_photo);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        viewHolder.userNameTv.setText(bean.getUserName());
        // Glide載入
        Glide.with(mContext).load(bean.getUserPhoto())
                .placeholder(MakeRandomPhoto.getInstance().setWidth(48).setHeight(48).setTxtSize(20).setTxtColor(Color.parseColor("#ffffff")).setShowNum(2).makeRandomPhotoDrawable(bean.getUserName())).dontAnimate().into(viewHolder.userPhotoIv);
        return convertView;
    }

封裝了一個製作預設頭像的工具類,提供方法設定相關屬性,每個設定方法都會返回物件本身是為了方便連綴使用,看一下核心方法

/**
 * 建立隨機圖片
 *
 * @return
 */
public Bitmap makeRandomPhotoBp(String txt) {
    if (null == txt || "".equals(txt)) {
        txt = "    ";
    }
    if (txt.length() > showNum) {
        txt = txt.substring(txt.length() - showNum);
    }
    // 這裡使用RGB_565,系統開銷小一點
    Bitmap bp = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
    Canvas c = new Canvas(bp);
    mPaint = new Paint();
    mPaint.setColor(fontColor);
    mPaint.setTextSize(fontSize);
    mPaint.setTextAlign(Paint.Align.CENTER);
    mPaint.setAntiAlias(true);
    fm = mPaint.getFontMetrics();
    // 設定背景顏色
    c.drawColor(ColorUtils.getRandomColor(txt.hashCode()));
    // 居中顯示
    c.drawText(txt, width / 2, height / 2 - fm.descent + (fm.descent - fm.ascent) / 2, mPaint);
    c.save(Canvas.ALL_SAVE_FLAG);//儲存
    c.restore();//
    return bp;
}

首先對傳入的文字進行處理,截取出需要顯示的文字,預設顯示字串的最後兩個字元,當然也可以自己設定.然後建立了一個Bitmap,這裡使用RGB_565而不是ARGB_8888,是因為RGB_565的開銷要小於ARGB_8888,一個背景色對畫質的要求不是很高.最後就是建立畫布,在畫布中去完成背景色和文字的繪製.有一個ColorUtils,這個是封裝的一個隨機顏色工具,一起看一下.

package com.angent.defaultavatardemo.utils;

import android.graphics.Color;
import android.support.annotation.IntRange;

import com.angent.defaultavatardemo.R;

/**
 * Created by junweiliu on 17/1/18.
 */
public class ColorUtils {
    /**
     * 隨機顏色起始
     */
    private static final int RANDOM_COLOR_START_RANGE = 0;
    /**
     * 隨機顏色終止
     */
    private static final int RANDOM_COLOR_END_RANGE = 7;


    /**
     * 獲取隨機color名稱
     *
     * @param colorPosition 唯一值,這裡用string的hashcode
     * @return
     */
    public static String getRandomColorName(@IntRange(from = RANDOM_COLOR_START_RANGE, to = RANDOM_COLOR_END_RANGE)
                                            int colorPosition) {
        colorPosition = Math.abs(colorPosition) % RANDOM_COLOR_END_RANGE;
        return String.format("random_color_%d", colorPosition + 1);
    }

    /**
     * 獲取隨機color顏色
     *
     * @param colorPosition 唯一值,這裡用string的hashcode
     * @return
     */
    public static int getRandomColor(@IntRange(from = RANDOM_COLOR_START_RANGE, to = RANDOM_COLOR_END_RANGE)
                                     int colorPosition) {
        String colorNmae = getRandomColorName(colorPosition);
        int resId = Color.parseColor("#8a8a8a");
        if (colorNmae.contains("1")) {
            resId = Color.parseColor("#8a8a8a");
        } else if (colorNmae.contains("2")) {
            resId = Color.parseColor("#f7b54e");
        } else if (colorNmae.contains("3")) {
            resId = Color.parseColor("#17c295");
        } else if (colorNmae.contains("4")) {
            resId = Color.parseColor("#4da9eb");
        } else if (colorNmae.contains("5")) {
            resId = Color.parseColor("#b38979");
        } else if (colorNmae.contains("6")) {
            resId = Color.parseColor("#568aad");
        } else if (colorNmae.contains("7")) {
            resId = Color.parseColor("#f2725e");
        } else {
            resId = Color.parseColor("#8a8a8a");
        }
        return resId;
    }

    /**
     * 獲取color資源
     *
     * @param colorPosition 唯一值,這裡用string的hashcode
     * @return
     */
    public static int getCircleColorBgId(@IntRange(from = RANDOM_COLOR_START_RANGE, to = RANDOM_COLOR_END_RANGE)
                                         int colorPosition) {
        String colorNmae = getRandomColorName(colorPosition);
        int resId = R.mipmap.random_color_one;
        if (colorNmae.contains("1")) {
            resId = R.mipmap.random_color_one;
        } else if (colorNmae.contains("2")) {
            resId = R.mipmap.random_color_two;
        } else if (colorNmae.contains("3")) {
            resId = R.mipmap.random_color_three;
        } else if (colorNmae.contains("4")) {
            resId = R.mipmap.random_color_four;
        } else if (colorNmae.contains("5")) {
            resId = R.mipmap.random_color_five;
        } else if (colorNmae.contains("6")) {
            resId = R.mipmap.random_color_six;
        } else if (colorNmae.contains("7")) {
            resId = R.mipmap.random_color_seven;
        } else {
            resId = R.mipmap.random_color_one;
        }
        return resId;
    }
}

ColorUtils的主要作用就是通過字串的hashcode值,來生成一個隨機的顏色值,當然相同字串的hashcode值是相同的,這樣就保證了每個文字對應一個相同的隨機顏色.
ColorUtils中還提供了一個獲取隨機背景圖片的方法,這個方法是幹嘛用的呢?
這個就是為了第二種方案寫的,如果不依賴Glide,不使用placeholder方法.怎麼實現這種隨機背景顏色上帶有文字的預設頭像呢,看一下佈局檔案,可能就懂了.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="horizontal">
    <TextView
            android:id="@+id/tv_user_photo"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_centerVertical="true"
            android:layout_marginBottom="10dp"
            android:layout_marginLeft="16dp"
            android:layout_marginRight="16dp"
            android:layout_marginTop="10dp"
            android:gravity="center"
            android:textColor="#ffffff"
            android:textSize="20sp"
            android:visibility="visible"
    />

    <com.angent.defaultavatardemo.widget.CircleImageView
            android:id="@+id/ci_user_photo"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_centerVertical="true"
            android:layout_marginBottom="10dp"
            android:layout_marginLeft="16dp"
            android:layout_marginRight="16dp"
            android:layout_marginTop="10dp"
            android:visibility="visible"/>


    <TextView
            android:id="@+id/tv_user_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@+id/ci_user_photo"
            android:text="名字"
            android:textColor="#333333"
            android:textSize="16sp"/>

</RelativeLayout>

在CircleImageView下邊有一個TextView,位置剛好和CircleImageView重合,並且在下層.再看一下程式碼中的寫法

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        ...
        viewHolder.userNameTv.setText(bean.getUserName());
        // 設定隨機顏色背景
        viewHolder.userPhotoTv.setBackgroundResource(ColorUtils.getCircleColorBgId(bean.getUserName().hashCode()));
        // 設定文字
        viewHolder.userPhotoTv.setText(bean.getUserName().substring(bean.getUserName().length() - 2));
        // 載入影象
        Glide.with(mContext).load(bean.getUserPhoto()).dontAnimate().into(viewHolder.userPhotoIv);
        return convertView;
    }

應該很簡單,這種方案的思路就是,如果Glide載入圖片成功了,就把地下的TextView遮住,如果沒有載入成功,那麼下層的TextView就作為預設頭像顯示.

應該還有其他更好的方案,這裡就提供這兩種.測試了一下兩種方案的效能,基本沒有差別.推薦第二種方案,顯示時比較清晰

最後看一下效果圖吧

這裡寫圖片描述

原始碼地址

原始碼下載

相關推薦

Android預設頭像那些事兒

Android應用市場中幾乎所有APP中都會涉及使用者體系.當然也就需要頁面去處理使用者資訊的展示、使用者頭像的展示等.對於使用者頭像展示,有很多優秀的圖片載入框架,平常寫專案會經常使用到這些圖片載入框架,使用起來也很方便,效率也比較高.但是面對不同的需求時,處

Android+Handler+Thread 那些事兒

工作 dem 什麽 美的 晚安 告訴 圖書 下載 都沒有   前言,才開始學安卓十幾天,不料被線程擋住了前進的步伐,因為之前操作系統課程並沒有認真聽老師講課,導致現在理解這些抽象的東西有些小困難。沒關系,苦學之路,總會碰到坎坷,這裏也給那些迷失在Android之路的小

Android-Lifecycle超能解析-生命週期的那些事兒

本文篇幅較長,請大家耐心閱讀。 Lifecycle是什麼? Lifecycle是一個生命週期感知元件,一般用來響應Activity、Fragment等元件的生命週期變化,並將變化通知到已註冊的觀察者。有助於更好地組織程式碼,讓程式碼邏輯符合生命週期規範,減少記憶

Android直播,音視訊播放那些事兒

新浪開源直播框架:https://github.com/SinaVDDeveloper 前言 隨著音視訊領域的火熱,在很多領域(教育,遊戲,娛樂,體育,跑步,餐飲,音樂等)嘗試做音視訊直播/點播功能,那麼作為開發一個小白,如何快速學習音視訊基礎知識,瞭解音視訊編解碼的傳輸協

Android中的自繪View的那些事兒(五)之 遮罩濾鏡:BlurMaskFilter 和 EmbossMaskFilter 的簡介

MaskFilter MaskFilter翻譯過來叫遮罩濾鏡,它可以為Paint邊緣的alpha通道應用轉換。目前有兩個子類:BlurMaskFilter 和 EmbossMaskFilter。它們分別可實現出模糊效果和浮雕效果。 BlurMaskFilter BlurM

Android 混淆那些事兒

本文主要講述了程式碼混淆和資源混淆的原理,Studio預設的混淆方案,混淆的引數,以及如何對Apk進行程式碼混淆(自定義混淆檔案)和資源混淆(結合微信混淆和美團混淆兩種方案),避免Apk被逆向。為什麼要混淆我們的apk在打包釋出之前,都要進行混淆處理來避免原始碼

關於Android整合高德地圖的那些事兒...顯示地圖

    記得在2016年的時候, 有個專案需要在地圖上新增Marker 並且連點成線記錄座標 和 地理圍欄,  當時也是第一次做,確實有點懵, 不過時間久了, 也還挺簡單的 ; 最近專案中又用到了地圖 , 藉此機會 , 重構下之前的邏輯 , 之前用的是高德地圖 , 個人感覺還

Android中JNI程式設計的那些事兒 【轉】

後續可能為需要加入一些特定的模組到android中,所以JNI還需繼續熟悉起來 首先說明,Android系統不允許一個純粹使用C/C++的程式出現,它要求必須是通過Java程式碼嵌入Native C/C++——即通過JNI的方式來使用本地(Native)程式碼。因此

那些年,那些事兒,我們一起php

做出 幹凈 程序員 彈出 高考 那種 家務 每次 哥哥 謹以此文悼念自己的堅持了8年的初戀以及逝去的青春。 晚上七點,寫完日報,上傳今天更新的代碼。簡單的收拾,擠上了回家的地鐵,天氣慢慢變熱了,地鐵中的味道也豐富了起來。站在角落,拿出手機,也就這段時間我可以玩

html頁面中拍照和上傳照片那些事兒(二)

read itl 加載完成 大小 上傳照片 那些事 cnblogs 設置 新建 本文為原創,轉載請註明出處: cnzt 文章:cnzt-p http://www.cnblogs.com/zt-blog/p/6895352.html 本文主要說下iOS上

ASP.NET Core HTTP 管道中的那些事兒

那些事兒 管道 IApplicationBuilderIApplicationBuilder 是應用大家最熟悉它的地方應該就是位於 Startup.cs 文件中的 Configure 方法了吧public void Configure(IApplicationBuilder app, ILoggerF

分布式系統的那些事兒(三) - 系統與系統之間的調用

數據格式 轉換 處理 分布 互調 圖片處理 動作 人性 並且 系統與系統之間的調用通俗來講,分為本地同一臺服務器上的服務相互調用與遠程服務調用,這個都可以稱之為RPC通信。淺白點講,客戶訪問服務器A,此時服務器要完成某個動作必須訪問服務器B,服務器A與B互相通信,相互調用,

移動端頁面布局的那些事兒

默認值 oat 暫時 占用 基於 正常 cep 兩個 均衡 移動端頁面布局的那些事兒 http://www.xiaoxiangzi.com/Programme/CSS/4298.html 一. viewport 什麽是viewport 簡單來講,viewport就是瀏覽

分布式系統的那些事兒(三) - MQ時代的通信

任務 會有 服務端 分布 ive 結果 團隊 並不會 短信 之前在講RPC通信的各種好處,特別好用,但是RPC並不是萬能的,也並不是適用於各種場景的,因為他是同步的;現如今很多場景下的調用都是異步的,系統A調用B後,並不需要知道B的結果,而且對B的結果無所謂,甚至你B掛了都

TCP 的那些事兒(上)

fas 也說 alt hal 收獲 很好 浪費 服務器 book http://coolshell.cn/articles/11564.html TCP是一個巨復雜的協議,因為他要解決很多問題,而這些問題又帶出了很多子問題和陰暗面。所以學習TCP本身是個比較痛苦的過

TCP 的那些事兒(下)

以及 int 不能 資源 body 快速 ssi oid ima http://coolshell.cn/articles/11609.html 這篇文章是下篇,所以如果你對TCP不熟悉的話,還請你先看看上篇《TCP的那些事兒(上)》 上篇中,我們介紹了TCP的協議

CORS——跨域請求那些事兒

lob 有效期 site cati 項目 light 另一個 send 決定 在日常的項目開發時會不可避免的需要進行跨域操作,而在實際進行跨域請求時,經常會遇到類似 No ‘Access-Control-Allow-Origin‘ header is present on

[聊一聊系列]聊一聊前端存儲那些事兒

我們 老朋友 必須 獲取 sql 壓力 做了 lan read https://segmentfault.com/a/1190000005927232 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://seg

阿裏聚安全移動安全專家分享:APP渠道推廣作弊攻防那些事兒

工作人員 感染 androi 時代 right 有效 市場 實驗 刷的 移動互聯網高速發展,要保持APP持續並且高速增長所需的成本也越來越高。美團網CEO在今年的一次公開會議上講到:“2017年對移動互聯網公司來說是非常恐的。”。主要表現在三個方面,手機數不漲了、競品太多、

OpenSSL 有關密鑰的那些事兒(HOWTO keys)

sign som side note don ace quit ner tracking <DRAFT!> OpenSSL 有關密鑰的那些事兒(HOWTO keys) 1. 介紹(Introduction) Keys are the basis o