編輯:關於Android編程
筆者最近遇到一個非常有意思的bug,貼出來和大家分享下。
那是一個溫暖的早晨,陽光曬得人很舒服。一封bug郵件像一片葉子飄到我的郵箱。
一番交流,筆者確認負責的Widget開關在Android5.0以上系統沒有作用。相信很多做過移動網絡開關的朋友都知道,傳統的方法是在ConnectivityManager中通過反射兩個方法setMobileDataEnabled和getMobileDataEnabled來控制移動網絡開和關的。
/**
* Gets the value of the setting for enabling Mobile data.
*
* @return Whether mobile data is enabled.
* @hide
*/
public boolean getMobileDataEnabled() {
try {
return mService.getMobileDataEnabled();
} catch (RemoteException e) {
return true;
}
}
/**
* Sets the persisted value for enabling/disabling Mobile data.
*
* @param enabled Whether the mobile data connection should be
* used or not.
* @hide
*/
public void setMobileDataEnabled(boolean enabled) {
try {
mService.setMobileDataEnabled(enabled);
} catch (RemoteException e) {
}
}
但是打開5.0以上的源碼,這兩個方法已經不存在了。
推薦一個不錯的在線看源碼的網站。在線源碼網址。
此時老大的提醒幫了我,我打開5.0以上代碼的TelephonyMananger類嘗試通過反射獲取setDataEnabled和getDataEnabled類完成操作。
源碼
/** @hide */
@SystemApi
public void setDataEnabled(boolean enable) {
try {
getITelephony().setDataEnabled(enable);
} catch (RemoteException e) {
Log.e(TAG, Error calling ITelephony#setDataEnabled, e);
}
}
/** @hide */
@SystemApi
public boolean getDataEnabled() {
try {
return getITelephony().getDataEnabled();
} catch (RemoteException e) {
Log.e(TAG, Error calling ITelephony#getDataEnabled, e);
}
return false;
}
我的反射方法:
public void setMobileDataState(Context cxt, boolean mobileDataEnabled) {
TelephonyManager telephonyService = (TelephonyManager) cxt.getSystemService(Context.TELEPHONY_SERVICE);
try {
Method setMobileDataEnabledMethod = telephonyService.getClass().getDeclaredMethod(setDataEnabled, boolean.class);
if (null != setMobileDataEnabledMethod)
{
setMobileDataEnabledMethod.invoke(telephonyService, mobileDataEnabled);
}
}
catch (Exception e) {
LogHelper.v(TAG, Error setting + ((InvocationTargetException)e).getTargetException() + telephonyService);
}
}
public boolean getMobileDataState(Context cxt) {
TelephonyManager telephonyService = (TelephonyManager) cxt.getSystemService(Context.TELEPHONY_SERVICE);
try {
Method getMobileDataEnabledMethod = telephonyService.getClass().getDeclaredMethod(getDataEnabled);
if (null != getMobileDataEnabledMethod)
{
boolean mobileDataEnabled = (Boolean) getMobileDataEnabledMethod.invoke(telephonyService);
return mobileDataEnabled;
}
}
catch (Exception e) {
LogHelper.v(TAG, Error getting + ((InvocationTargetException)e).getTargetException() + telephonyService);
}
return false;
}
但是報了InvocationTargetException錯誤。通過:
((InvocationTargetException)e).getTargetException()
方法得知是執行反射執行時發生如下錯誤:
Error settingjava.lang.SecurityException: Neither user 10240 nor current process has android.permission.MODIFY_PHONE_STATE.android.telephony.TelephonyManager
這個時候老大提醒我把APP移動到system/app下試試。
幾番嘗試,仍是同樣的結果。
這個時候一個我無意的操作,將APP移動到system/priv-app,竟然成功了。在這個目錄下,開關又可以重新工作了。
當然,我們的應用不可能裝在這個目錄下,只能采取折中的方案。但整個過程還是很開心的,這個bug算是我第一次發現了不同Android版本之間源碼的差異,感覺很有意思。希望對大家有所啟發。
屬性動畫---res/animator屬性動畫故名思議就是通過動畫的方式改變對象的屬性了,我們首先需要了解幾個屬性:Duration動畫的持續時間,默認300ms。Tim
我們通過使用DexClassLoader能夠將classes.dex中的類動態的加載進入當前進程。當然,也就可以預先定一些代理的接口完成四大組件的功能。整體功
剛接觸android的時候看到項目裡面用到了ImageLoader這個圖片緩存插件,當初抱著“知其然必要知其所以然”的想法還專門下載了它的源碼沒頭
Android提供了常見的音頻、視頻的編碼、解碼機制。借助於多媒體類MediaPlayer的支持,開發人員可以很方便在在應用中播放音頻、視頻。本篇博客主要講解在An