當前位置:首頁 » 安卓系統 » android代碼檢查

android代碼檢查

發布時間: 2023-03-29 19:08:49

『壹』 一行代碼搞定 Android 復雜列表埋點曝光

一個好的產品離不開數據分析,在手機 APP 中,數據分析極致化需要細致到某個時刻列表曝光的了哪幾個 Item。

2022 年了,基本上目前 Android 上可以滑動的復雜列表都是 RecyclerView 或者其擴展,這里分享一個封裝的思路。

如果非要細化細節:

各種方案核心都差不多,最關鍵的就是通過 LayoutManager 獲取屏幕內第一個可見和最後一個可見 item position,上報其區間內的 Item。這里簡稱這個邏輯為 檢查上報邏輯

但是觸發時機有所不同,通常如下方案一和二所述,當然除了方案一和方案二外,還有一些別的方案,比如監聽 RecyclerView 的布局樹變化觸發 檢查上報邏輯 等方案。

可以發現方案二相比方案一更有利於減少各種回調的注冊和周期的控制,下文會在方案二的基礎上,闡述用法和相關實現思路。

倉庫地址: RecyclerViewExposure

這里會主要說明一些主要邏輯,需要完整的邏輯可以 fork 倉庫 查看

思路來自於 lifecycle 的設計,這里主要是想讓 Activity/Fragment 提供可見和不可見的狀態變化給外部訂閱

對 List Item 的收集處理是 RecyclerViewExposure 最核心的收集數據邏輯,這里針對在 Activity 的使用作為例子。上文已經講述如何做一個 PageLifeCycleHolder 為其他組件提供頁面可見狀態,下文將直接使用。

『貳』 android性能測試工具有哪些

大概有如下幾個工具:
android針對上面這些會影響到應用性能的情況提供了一些列的工具:
1 布局復雜度:
hierarchyviewer:檢測布局復雜度,各視圖的布局耗時情況:

Android開發者模式—GPU過渡繪制:

2 耗電量:Android開發者模式中的電量統計;
3 內存:
應用運行時內存使用情況查看:Android Studio—Memory/CPU/GPU;

內存泄露檢測工具:DDMS—MAT;
4 網路:Android Studio—NetWork;
5 程序執行效率:
靜態代碼檢查工具:Android studio—Analyze—Inspect Code.../Code cleanup... ,用於檢測代碼中潛在的問題、存在效率問題的代碼段並提供改善方案;
DDMS—TraceView,用於查找程序運行時具體耗時在哪;
StrictMode:用於查找程序運行時具體耗時在哪,需要集成到代碼中;
Andorid開發者模式—GPU呈現模式分析。
6 程序穩定性:monkey,通過monkey對程序在提交測試前做自測,可以檢測出明顯的導致程序不穩定的問題,執行monkey只需要一行命令,提交測試前跑一次可以避免應用剛提交就被打回的問題。
說明:
上面提到的這些工具可以進Android開發者官網性能工具介紹查看每個工具的介紹和使用說明;

Android開發者選項中有很多測試應用性能的工具,對應用性能的檢測非常有幫助,具體可以查看:All about your phone's developer options和15個必知的Android開發者選項對Android開發者選項中每一項的介紹;

針對Android應用性能的優化,Google官方提供了一系列的性能優化視頻教程,對應用性能優化具有非常好的指導作用,具體可以查看:優酷Google Developers或者Android Performance Patterns。

二 第三方性能優化工具介紹
除了android官方提供的一系列性能檢測工具,還有很多優秀的第三方性能檢測工具使用起來更方便,比如對內存泄露的檢測,使用leakcanry比MAT更人性化,能夠快速查到具體是哪存在內存泄露。
leakcanary:square/leakcanary · GitHub,通過集成到程序中的方式,在程序運行時檢測應用中存在的內存泄露,並在頁面中顯示,在應用中集成leancanry後,程序運行時會存在卡頓的情況,這個是正常的,因為leancanry就是通過gc操作來檢測內存泄露的,gc會知道應用卡頓,說明文檔:LeakCanary 中文使用說明、LeakCanary: 讓內存泄露無所遁形。
GT:GT Home,GT是騰訊開發的一款APP的隨身調測平台,利用GT,可以對CPU、內存、流量、點亮、幀率/流暢度進行測試,還可以查看開發日誌、crash日誌、抓取網路數據包、APP內部參數調試、真機代碼耗時統計等等,需要說明的是,應用需要集成GT的sdk後,GT這個apk才能在應用運行時對各個性能進行檢測。

『叄』 Android-android中如何通過代碼檢測是否有root許可權

最直接有效的方式就是執行su命令,su就是切換到root用戶,如果su命令可以執行,限則表示root成功。

具體測試方式:

1.安裝進入adb目錄(SDK中自帶adb)。

2.adb shell 進入shell模式。

3.su 切換到root用戶。

4.切換到root用戶後會顯示一個#號。

5.或直接在android 版本的 shell (附件)中執行命令。


『肆』 怎麼用代碼判斷android手機是否開啟了ROOT許可權

android手機開啟了root許可權,主要是根據root之後,獲取了手機的最高許可權,底層linux系統就會生成一個以su結尾的文件,su代表super超級許可權,如下代碼:
/**
* 判斷當前手機是否有ROOT許可權
* @return
*/
public boolean isRoot(){
boolean bool = false;

try{
if ((!new File("/system/bin/su").exists()) && (!new File("/system/xbin/su").exists())){
bool = false;
} else {
bool = true;
}
Log.d(TAG, "bool = " + bool);
} catch (Exception e) {

}
return bool;
}
android底層是使用linux進行編譯和一些驅動、網路管理的,所以可以根據linux的許可權特性來判斷是否root,許可權的管理在linux裡面很多,包括讀寫、刪除文件的許可權,也有關於訪問網路的許可權,這些許可權都需要開通才能有。

『伍』 Android檢測是否有網路的代碼

public class CheckNetwork {
private NetworkStateReceiver netStateReceiver;
private Context mContext;
private long servicetimes = 0;
private Utility myUtility = null;
private int runInternerTime = 0;
private HandlerNetwork mHandlerNetwork = new HandlerNetwork();
private static CheckNetwork mNetworkState = null;
private Map<String, Handler> mHandlerOuterMap = new HashMap<String, Handler>();

public static CheckNetwork getNetworkState(Context context) {
if (mNetworkState == null) {
mNetworkState = new CheckNetwork(context);
}
return mNetworkState;
}

private CheckNetwork(Context context) {
mContext = context;
myUtility = new Utility(mContext);

registNetworkStatusReceiver();

}

public void registNetworkStatusReceiver() {
netStateReceiver = new NetworkStateReceiver(mHandlerNetwork);
IntentFilter filter = new IntentFilter(
"android.net.conn.CONNECTIVITY_CHANGE");
filter.addAction("android.intent.action.MY_NET_BOOTCHECK");
mContext.registerReceiver(netStateReceiver, filter);

Intent intent = new Intent("android.intent.action.MY_NET_BOOTCHECK");
mContext.sendBroadcast(intent);
}

/**
* 增加一個網路狀態消息接受者
*
* @param key
* @param handler
*/
public void addHandler(String key, Handler handler) {

mHandlerOuterMap.put(key, handler);
if (!key.equals("IntegrateActHandlerKey")) {
// 當整合頁添加handle時,網路狀態還沒准備好,所以不通過handle對外發通知
sendNetworkMessage(mHandlerOuterMap);
}
}

/**
* 向接受者集合中的接受者發送網路狀態的消息
*
* @param map
*/
public static void sendNetworkMessage(Map<String, Handler> map) {

Set<String> key = map.keySet();
for (Object element : key) {
String s = (String) element;
Message msg = Message.obtain();
msg.what = GlobalParams.Handle_Msg.NetWorkStatus.ordinal();
map.get(s).sendMessage(msg);
}
}

private class HandlerNetwork extends Handler {
@Override
public void handleMessage(Message msg) {
if (msg.what == GlobalParams.Handle_Msg.ConnectSuccess.ordinal()) {
if (System.currentTimeMillis() - servicetimes > 3000) {// 防止短時間內接收多個廣播,執行多次
runInternerTime = 0;
servicetimes = System.currentTimeMillis();
new CheckServerThread().start();
}
} else if (msg.what == GlobalParams.Handle_Msg.ConnectFail
.ordinal()) {
if (System.currentTimeMillis() - servicetimes > 2000) {// 防止短時間內接收多個廣播,執行多次
servicetimes = System.currentTimeMillis();
runInternerTime++;
if (runInternerTime > 3) {
// Intent intent = new Intent(context,
// IntegrateActivity.class);
// context.startActivity(intent);

GlobalParams.NetworkStatus = 0;
sendNetworkMessage(mHandlerOuterMap);
} else {
Log.e("RUN", "本地連接不上嘗試第" + runInternerTime + "次");
Message msgrun = Message.obtain();
msgrun.what = GlobalParams.Handle_Msg.InternerFail
.ordinal();
mHandlerNetwork.sendMessageDelayed(msgrun, 3000);
}

}
} else if (msg.what == GlobalParams.Handle_Msg.InternerFail
.ordinal()) {
//檢測棒子與路由器間的連接不足3次時,繼續檢測
Intent intent = new Intent(
"android.intent.action.MY_NET_BOOTCHECK");
mContext.sendBroadcast(intent);
}else if(msg.what==GlobalParams.Handle_Msg.NetWorkStatusIn.ordinal()){
if(msg.arg1==0){
GlobalParams.NetworkStatus = 2;
sendNetworkMessage(mHandlerOuterMap);
}else{
GlobalParams.NetworkStatus = 1;
sendNetworkMessage(mHandlerOuterMap);
}
}
}
}

private class CheckServerThread extends Thread{
@Override
public void run() {
File f = new File(Environment.getExternalStorageDirectory().getPath()
+ "/CudgelLauncher/Images");
if (!f.exists())
f.mkdirs();
File ftemp = new File(Environment.getExternalStorageDirectory()
.getPath() + "/CudgelLauncher/Temp");
if (!ftemp.exists())
ftemp.mkdirs();

// 等待SD卡准備完成
while (true) {
try {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
// 因為舊的配置文件都不適合用於新版,所以要把舊的都清除再重新載入
myUtility.delete(new File("/data/data/"
+ GlobalParams.PROCESSPACKNAME
+ "/databases/cudgellauncher"));
myUtility.delete(new File("/system/media/cudgel"));
myUtility.delete(new File("/mnt/sdcard/CudgelLauncher"));
break;
}
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

XmlParser parser = new XmlParser();
File fileConfig = new File("/mnt/sdcard/CudgelLauncher/config.xml");
File file = new File("/mnt/sdcard/CudgelLauncher/ConfigInterface.xml");
while (true) {
try {
Map<String, String> mapConfig = parser
.getServiceAsmx(fileConfig);
Map<String, String> mapInterface = parser.getServiceAsmx(file);
if (!fileConfig.exists() || mapConfig == null
|| !mapConfig.containsKey("area") || !file.exists()
|| mapInterface == null
|| !mapInterface.containsKey("servicenamespace")) {
// 第一次運運沒配置文件時或防止配置文件被損壞,重新復制
myUtility.saveConfigFile(Environment
.getExternalStorageDirectory().getPath()
+ "/CudgelLauncher", "Config.xml", R.raw.config,
mContext);
myUtility.saveConfigFile(Environment
.getExternalStorageDirectory().getPath()
+ "/CudgelLauncher", "ConfigInterface.xml",
R.raw.configinterface, mContext);
} else {
GlobalParams.AreaID = mapConfig.get("area");
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
//開始檢測通不通公網
PingAddrUtils pingAddrUtils=new PingAddrUtils(mHandlerNetwork,GlobalParams.Handle_Msg.NetWorkStatusIn.ordinal());
pingAddrUtils.startPingAddr();
super.run();
}
}
}

ublic class PingAddrUtils {
private final static byte[] writeLock = new byte[0];
private String[] urls = new String[] { "tiipot.chinadhia.com",
"www.youku.com", "v.qq.com", "www.letv.com", "www..com",
"www.pptv.com", "tv.sohu.com" };
private String[] names = new String[] { "雲聯", "優酷", "騰訊", "樂視", "網路",
"pptv", "搜狐" };
private boolean[] isConected = { false, false, false, false, false, false,
false };
private Handler mHandler;
private int msgWhat;
private Timer timer;

/**
* mHandler用於接收返回成功連接或失敗的消息
*
* @param mHandler
* @param mContext
*/
public PingAddrUtils(Handler mHandler, int msgWhat) {
this.mHandler = mHandler;
this.msgWhat = msgWhat;
}

/**
* 開始ping地址,返回值通過消息形式發送到構造方法傳入的Handler,msg.What也是用構造方法傳入的msgWhat
* 參數說明arg1:0失敗;1通了;obj:用於生成二維碼的字元串(String)
*
* @param msgWhat
*/
public void startPingAddr() {
// 開始檢測時把狀態都置為false以防重復檢測時出現錯誤結果
for (int i = 0; i < isConected.length; i++) {
isConected[i] = false;
}
for (int i = 0; i < urls.length; i++) {
new IpAddrThread(i).start();
}
timer = new Timer();
timer.schele(new TimerTask() {
@Override
public void run() {
if (!isAllConected()) {// 全通線程中已處理了,所以這里只考慮沒有全通的情況
boolean isAnyOneConected = false;
for (int i = 0; i < isConected.length; i++) {
isAnyOneConected = isAnyOneConected || isConected[i];
}
if (isAnyOneConected) {
sendMessage(1);// 有某個地址連接成功了。
} else {
sendMessage(0);// 全部地址連接失敗。
}
}
}
}, 9000);// 9秒後
}

/***
* 判斷是否所有地址都一ping通
*
* @return
*/
private boolean isAllConected() {
boolean isAllConected = true;
for (int j = 0; j < isConected.length; j++) {
// 所有都為TRUE isAllConected才為TRUE
isAllConected = isAllConected && isConected[j];
}
return isAllConected;
}

class IpAddrThread extends Thread {
int IpNum;

public IpAddrThread(int IpNum) {
this.IpNum = IpNum;
}

@Override
public void run() {
try {
Process p = Runtime.getRuntime().exec(
"ping -c 3 -w 5 " + urls[IpNum]);
int status = p.waitFor();

if (status == 0) {
// pass
// mPingIpAddrResult = "連接正常";
setThisIpTrue(IpNum);
} else {
// Fail:Host unreachable
// mPingIpAddrResult = "連接不可達到";
}
} catch (UnknownHostException e) {
// Fail: Unknown Host
// mPingIpAddrResult = "出現未知連接";
} catch (IOException e) {
// Fail: IOException
// mPingIpAddrResult = "連接出現IO異常";
} catch (InterruptedException e) {
// Fail: InterruptedException
// mPingIpAddrResult = "連接出現中斷異常";
}
}
}

/**
* 生成用於產生二維碼的字元串。01~10~21~31~41~50~61,有7組結果,用符號~分隔,每組結果都有兩位數字,第一位數字代表是哪個伺服器(
* 0是XX,1是優酷,2是 騰訊, 3是樂視, 4是網路,5是pptv,6是搜狐),第二位數字代碼ping的結果(0表示不通,1表示已通)
*
* @return
*/
private String getQRCodeString() {
String oRCodeString = "";
for (int i = 0; i < isConected.length; i++) {
int state = 0;
if (isConected[i]) {
state = 1;
}
oRCodeString = oRCodeString + i + state;
if (i < isConected.length - 1) {
oRCodeString = oRCodeString + "~";
}
}
writeFileSdcard(oRCodeString);
return oRCodeString;
}

/**
* 寫入SD卡
*
* @param filePath
* @param message
*/
private void writeFileSdcard(String message) {

try {
File file = new File("/mnt/sdcard/netstatus.txt");
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
if (!file.exists()) {
file.createNewFile();
}
// FileOutputStream fout = openFileOutput(fileName, MODE_PRIVATE);

FileOutputStream fout = new FileOutputStream(file);

byte[] bytes = message.getBytes();

fout.write(bytes);

fout.close();

}

catch (Exception e) {

e.printStackTrace();

}

}

/**
* 定義消息並發送
*
* @param state
*/
private void sendMessage(int state) {
Message msg = Message.obtain();
msg.what = msgWhat;
msg.arg1 = state;// 全通
msg.obj = getQRCodeString();
mHandler.sendMessage(msg);
}

/**
* 把該ipNum代表的地址的通達狀況置為True並判斷是否所有都已聯通,如果都已連通則發送成功連接的消息
*
* @param IpNum
*/
private void setThisIpTrue(int IpNum) {
synchronized (writeLock) {
isConected[IpNum] = true;// 把本地址的標記置為true;
if (isAllConected()) {
sendMessage(1);
timer.cancel();
timer = null;

}

}
}
}

熱點內容
配置控制台干什麼用的 發布:2025-07-05 10:54:51 瀏覽:958
連信從哪裡改登錄密碼 發布:2025-07-05 10:54:12 瀏覽:396
怎麼修改查詢密碼 發布:2025-07-05 10:49:48 瀏覽:965
matlab文件存儲 發布:2025-07-05 10:40:46 瀏覽:84
梅州市用工實名制管理平台雲存儲 發布:2025-07-05 10:28:59 瀏覽:76
安卓origin怎麼設置 發布:2025-07-05 10:20:10 瀏覽:540
安卓為什麼跳水 發布:2025-07-05 09:55:08 瀏覽:88
達內學校php 發布:2025-07-05 09:52:05 瀏覽:399
獲取資料庫所有表 發布:2025-07-05 09:39:12 瀏覽:654
wcfphp 發布:2025-07-05 09:39:07 瀏覽:178