1. 程式人生 > >Android 配置子Module混淆時遇到的錯誤,和一些零散技術點總結

Android 配置子Module混淆時遇到的錯誤,和一些零散技術點總結

概要說明:
1、子Module不能配置混淆,僅僅只能在主Module中配置混淆。
2、主Module配置了混淆,打包成apk後,其他Module的程式碼也會一起混淆。
3、所有Module中的res目錄下的資源都會在打包時合併到主Module的res目錄下對應檔案位置。
4、所有被主Module直接或間接引用了的Module,在打包時,其AndroidManifest.xml檔案都會合併到主Module的AndroidManifest.xml檔案中。
5、手機橫豎屏時尋找layout目錄的規則。
6、手機橫豎屏時的寬度dp值和高度dp值。
7、注意textView.setTextSize(size)函式的程式碼,size的單位



Error:Execution failed for task ':app:compileDebugJavaWithJavac'.

> Compilation failed; see the compiler error output for details.


上面錯誤導致的原因是所有子Module都不能配置混淆,即minifyEnabled true。如果需要,也只能在主Module中配置。


在主Module中配置了混淆,打包時會作用在所有的Module上,即其他的Module的程式碼也會被混淆。
所有Module下res目錄中的內容也會合併到主Module的res對應目錄和檔案中。參考文章:http://blog.csdn.net/fesdgasdgasdg/article/details/78133821
所有被主Module直接或間接引用的子Module的AndroidManifest.xml檔案,在打包時內容都會合併到主Module的AndroidManifest.xml檔案中,
包括許可權,註冊的元件等






layout目錄描述:
layout-port為豎屏時的佈局目錄。
layout-land為橫屏時的佈局目錄。
layout為預設目錄,即:
豎屏時,系統會首先尋找layout-port目錄的佈局,如果找不到則使用layout目錄的佈局;
橫屏時,系統會首先尋找layout-land目錄的佈局,如果找不到則使用layout目錄的佈局。








我有個容器類的自定義控制元件ImageTextView,其內部包含了一個TextView。但是我想在容器級別上設定個自定義屬性,獲取字型大小imageTextSize,
1)、於是這麼獲取屬性值:

imageTextSize = array.getDimensionPixelSize(attr,
                            (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, TEXT_SIZE, getResources().getDisplayMetrics()));
2)、然後這麼設定
innerTextView.setTextSize(imageTextSize);
執行後看效果我就懵了,這麼字型比普通的TextView字型大一倍?但是innerTextView.getTextSize()與普通的textView.getTextSize()值相等。奇葩。

分析發現:

imageTextSize = array.getDimensionPixelSize(attr,預設值);
看看預設值這個靜態函式程式碼TypedValue.applyDimension():
public static float applyDimension(int unit, float value,
                                       DisplayMetrics metrics)
{
	switch (unit) {
	case COMPLEX_UNIT_PX:
		return value;
	case COMPLEX_UNIT_DIP:
		return value * metrics.density;
	case COMPLEX_UNIT_SP:
		return value * metrics.scaledDensity;
	case COMPLEX_UNIT_PT:
		return value * metrics.xdpi * (1.0f/72);
	case COMPLEX_UNIT_IN:
		return value * metrics.xdpi;
	case COMPLEX_UNIT_MM:
		return value * metrics.xdpi * (1.0f/25.4f);
	}
	return 0;
}

把TEXT_SIZE值當做sp單位,然後乘以了縮放比例。




在看看array.getDimensionPixelSize()函式程式碼:
public int getDimensionPixelSize(@StyleableRes int index, int defValue) {
	if (mRecycled) {
		throw new RuntimeException("Cannot make calls to a recycled instance!");
	}

	final int attrIndex = index;
	index *= AssetManager.STYLE_NUM_ENTRIES;

	final int[] data = mData;
	final int type = data[index+AssetManager.STYLE_TYPE];
	if (type == TypedValue.TYPE_NULL) {
		return defValue;
	} else if (type == TypedValue.TYPE_DIMENSION) {
		return TypedValue.complexToDimensionPixelSize(
			data[index+AssetManager.STYLE_DATA], mMetrics);
	} else if (type == TypedValue.TYPE_ATTRIBUTE) {
		final TypedValue value = mValue;
		getValueAt(index, value);
		throw new UnsupportedOperationException(
				"Failed to resolve attribute at index " + attrIndex + ": " + value);
	}

	throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
			+ " to dimension: type=0x" + Integer.toHexString(type));
}
呼叫了TypedValue.complexToDimensionPixelSize()函式,在深入看看這個函式程式碼:
public static int complexToDimensionPixelSize(int data,
            DisplayMetrics metrics)
{
	final float value = complexToFloat(data);
	final float f = applyDimension(
			(data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK,
			value,
			metrics);
	final int res = (int)(f+0.5f);
	if (res != 0) return res;
	if (value == 0) return 0;
	if (value > 0) return 1;
	return -1;
}

呼叫了TypedValue.applyDimension()程式碼,哈利路亞,這不又轉回來了?乘以了縮放比例。
public static float applyDimension(int unit, float value,
                                       DisplayMetrics metrics)
{
	switch (unit) {
	case COMPLEX_UNIT_PX:
		return value;
	case COMPLEX_UNIT_DIP:
		return value * metrics.density;
	case COMPLEX_UNIT_SP:
		return value * metrics.scaledDensity;
	case COMPLEX_UNIT_PT:
		return value * metrics.xdpi * (1.0f/72);
	case COMPLEX_UNIT_IN:
		return value * metrics.xdpi;
	case COMPLEX_UNIT_MM:
		return value * metrics.xdpi * (1.0f/25.4f);
	}
	return 0;
}

也就是說(記住),我們通過array.getDimensionPixelSize(attr, 預設值)方式獲取到的字型大小值,值經過轉換後的pt值了,已經乘以了縮放比例。


我們在看看textView.setTextSize(size)函式程式碼:
public void setTextSize(float size) {
	setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
}

注意看兩個引數,sp單位,系統認為size值是sp單位的,進入函式看:
public void setTextSize(int unit, float size) {
	Context c = getContext();
	Resources r;

	if (c == null)
		r = Resources.getSystem();
	else
		r = c.getResources();

	setRawTextSize(TypedValue.applyDimension(
			unit, size, r.getDisplayMetrics()));
}


最後一行呼叫了setRawTextSize()函式,括號內又呼叫了TypedValue.applyDimension()靜態函式。shit,不多說了。是不是又把size當成sp值,再乘以了縮放比例?


進入setRawTextSize()函式看看系統拿到放大後的pt值怎麼設定字型大小:

private void setRawTextSize(float size) {
	if (size != mTextPaint.getTextSize()) {
		mTextPaint.setTextSize(size);

		if (mLayout != null) {
			nullLayouts();
			requestLayout();
			invalidate();
		}
	}
}


搜迪斯嫩,設定到了畫筆上(mTextPaint.setTextSize(size);),然後重繪UI(requestLayout();invalidate();)立即生效。


總結這小節:
上例中,我們通過自定義屬性獲取到的字型值,已經是pt單位的了,此時要設定到textView上時,需要呼叫textView.getPaint().setTextSize()進行設定。
在自定義屬性上獲取到的字型大小和尺寸值都是乘以了縮放比例後的放大值。
textView.setTextSize()函式的單位是sp