安卓內(nèi)存優(yōu)化案例二

安卓內(nèi)存優(yōu)化是一個很重要的話題鸳君,有很多方面可以考慮,比如避免內(nèi)存泄漏泻红、減少內(nèi)存抖動夭禽、優(yōu)化圖片加載、使用緩存和對象池等谊路。下面我舉一些代碼案例讹躯,分別展示不合適的寫法和高性能的寫法。
歡迎評論區(qū)留言指正和補充缠劝。

11. 避免使用 AsyncTask 來執(zhí)行異步任務(wù)潮梯。

AsyncTask 的內(nèi)部實現(xiàn)是使用一個線程池和一個消息隊列來管理任務(wù),這會占用內(nèi)存空間惨恭,并可能導(dǎo)致內(nèi)存泄漏和并發(fā)問題秉馏。如果需要執(zhí)行異步任務(wù),可以使用 RxJava 或者 Coroutine 等庫來代替脱羡。例如:

// 不合適的寫法
private class MyTask extends AsyncTask<Void, Void, String> {

    private WeakReference<Context> contextRef;

    public MyTask(Context context) {
        contextRef = new WeakReference<>(context);
    }

    @Override
    protected String doInBackground(Void... params) {
        // do some background work
        return "result";
    }

    @Override
    protected void onPostExecute(String result) {
        Context context = contextRef.get();
        if (context != null) {
            // do something with result and context
        }
    }
}

// 高性能的寫法
private fun doAsyncTask(context: Context) {
    CoroutineScope(Dispatchers.IO).launch {
        // do some background work
        val result = "result"
        withContext(Dispatchers.Main) {
            // do something with result and context
        }
    }
}

這樣做可以避免不必要的內(nèi)存分配和回收萝究,避免內(nèi)存泄漏和并發(fā)問題,并提高異步任務(wù)的管理和調(diào)度锉罐。

12. 避免使用 BitmapFactory 來加載圖片帆竹。

BitmapFactory 的內(nèi)部實現(xiàn)是使用 nativeDecodeStream 方法來解碼圖片,這會消耗較多的內(nèi)存空間氓鄙,并可能導(dǎo)致OOM馆揉。如果需要加載圖片,可以使用 Glide 或者 Picasso 等庫來代替抖拦。例如:

// 不合適的寫法
ImageView imageView = findViewById(R.id.image_view);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image); // 這會創(chuàng)建一個原始大小的位圖對象升酣,占用內(nèi)存空間,并可能導(dǎo)致OOM
imageView.setImageBitmap(bitmap);

// 高性能的寫法
ImageView imageView = findViewById(R.id.image_view);
Glide.with(this).load(R.drawable.image).into(imageView); // 這會根據(jù)視圖的大小和屏幕密度來加載合適大小的位圖對象态罪,節(jié)省內(nèi)存空間噩茄,并避免OOM

這樣做可以避免不必要的位圖對象的創(chuàng)建,節(jié)省內(nèi)存空間复颈,并提高圖片加載的效率和質(zhì)量绩聘。

13. 避免使用 Serializable 接口來實現(xiàn)序列化沥割。

Serializable 接口的內(nèi)部實現(xiàn)是使用反射機制來序列化和反序列化對象,這會消耗較多的CPU和內(nèi)存資源凿菩,并可能導(dǎo)致性能下降机杜。如果需要實現(xiàn)序列化,可以使用 Parcelable 接口或者 ProtoBuf 等庫來代替衅谷。例如:

// 不合適的寫法
public class User implements Serializable {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // getter and setter methods
}

// 高性能的寫法
public class User implements Parcelable {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // getter and setter methods

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(age);
    }

    public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {

        @Override
        public User createFromParcel(Parcel source) {
            return new User(source.readString(), source.readInt());
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };
}

這樣做可以避免不必要的反射操作椒拗,節(jié)省CPU和內(nèi)存資源,并提高序列化和反序列化的效率获黔。

14. 避免使用 LinkedList 來存儲數(shù)據(jù)蚀苛。

LinkedList 的內(nèi)部實現(xiàn)是使用一個雙向鏈表來存儲數(shù)據(jù),這會占用較多的內(nèi)存空間玷氏,并且可能導(dǎo)致內(nèi)存碎片堵未。如果需要存儲數(shù)據(jù),可以使用 ArrayList 或者 ArrayDeque 來代替盏触。例如:

// 不合適的寫法
LinkedList<String> list = new LinkedList<>();
list.add("a");
list.add("b");
list.add("c");

// 高性能的寫法
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");

這樣做可以節(jié)省內(nèi)存空間渗蟹,因為 ArrayListArrayDeque 的內(nèi)部實現(xiàn)是使用一個數(shù)組來存儲數(shù)據(jù),沒有額外的開銷耻陕。另外拙徽,它們還可以提供更快的隨機訪問和迭代的性能。

15. 避免使用 StringTokenizer 來分割字符串诗宣。

StringTokenizer 的內(nèi)部實現(xiàn)是使用一個字符數(shù)組來存儲字符串膘怕,并且每次調(diào)用 nextToken() 方法都會創(chuàng)建一個新的字符串對象,這會消耗較多的CPU和內(nèi)存資源召庞,并可能導(dǎo)致GC岛心。如果需要分割字符串,可以使用 split() 方法或者 Scanner 類來代替篮灼。例如:

// 不合適的寫法
StringTokenizer st = new StringTokenizer("Hello World!");
while (st.hasMoreTokens()) {
    String token = st.nextToken(); // 每次調(diào)用都會創(chuàng)建一個新的字符串對象
    // do something with token
}

// 高性能的寫法
String[] tokens = "Hello World!".split(" "); // 這只會創(chuàng)建一個字符串?dāng)?shù)組對象
for (String token : tokens) {
    // do something with token
}

這樣做可以避免不必要的字符串對象的創(chuàng)建忘古,節(jié)省CPU和內(nèi)存資源,并提高字符串分割的效率诅诱。

16. 避免使用 SimpleDateFormat 來格式化日期和時間髓堪。

SimpleDateFormat 的內(nèi)部實現(xiàn)是使用一個 Calendar 對象來存儲日期和時間,并且每次調(diào)用 format() 方法都會創(chuàng)建一個新的 Date 對象娘荡,這會消耗較多的CPU和內(nèi)存資源干旁,并可能導(dǎo)致GC。如果需要格式化日期和時間炮沐,可以使用 DateTimeFormatter 或者 FastDateFormat 等庫來代替争群。例如:

// 不合適的寫法
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
String formattedDate = sdf.format(date); // 每次調(diào)用都會創(chuàng)建一個新的日期對象

// 高性能的寫法
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime date = LocalDateTime.now();
String formattedDate = dtf.format(date); // 這不會創(chuàng)建任何新的對象

這樣做可以避免不必要的日期對象的創(chuàng)建,節(jié)省CPU和內(nèi)存資源大年,并提高日期和時間格式化的效率换薄。

17. 避免使用 SparseIntArray 來存儲稀疏矩陣玉雾。

SparseIntArray 的內(nèi)部實現(xiàn)是使用兩個數(shù)組來存儲鍵和值,這會占用較多的內(nèi)存空間轻要,并且可能導(dǎo)致數(shù)組擴容和復(fù)制复旬。如果需要存儲稀疏矩陣,可以使用 SparseMatrix 或者 EJML 等庫來代替冲泥。例如:

// 不合適的寫法
SparseIntArray matrix = new SparseIntArray();
matrix.put(0, 1);
matrix.put(1, 2);
matrix.put(2, 3);

// 高性能的寫法
SparseMatrix matrix = new SparseMatrix(3, 3);
matrix.set(0, 0, 1);
matrix.set(1, 1, 2);
matrix.set(2, 2, 3);

這樣做可以節(jié)省內(nèi)存空間赢底,因為 SparseMatrixEJML 的內(nèi)部實現(xiàn)是使用一個鏈表或者一個哈希表來存儲非零元素柏蘑,沒有額外的開銷粹庞。另外,它們還可以提供更快的矩陣運算和轉(zhuǎn)置的性能庞溜。

18. 避免使用 JSONObject 來解析JSON字符串革半。

JSONObject 的內(nèi)部實現(xiàn)是使用一個 HashMap 來存儲鍵值對,這會占用較多的內(nèi)存空間流码,并且可能導(dǎo)致哈希沖突和擴容。如果需要解析JSON字符串六敬,可以使用 Gson 或者 Moshi 等庫來代替。例如:

// 不合適的寫法
String json = "{\"name\":\"Alice\",\"age\":18}";
JSONObject jsonObject = new JSONObject(json); // 這會創(chuàng)建一個哈希表對象驾荣,占用內(nèi)存空間外构,并可能導(dǎo)致哈希沖突和擴容
String name = jsonObject.getString("name");
int age = jsonObject.getInt("age");

// 高性能的寫法
String json = "{\"name\":\"Alice\",\"age\":18}";
Gson gson = new Gson();
User user = gson.fromJson(json, User.class); // 這會直接創(chuàng)建一個用戶對象,節(jié)省內(nèi)存空間播掷,并提高JSON解析的效率
String name = user.getName();
int age = user.getAge();

這樣做可以避免不必要的哈希表對象的創(chuàng)建,節(jié)省內(nèi)存空間垒酬,并提高JSON解析的效率和質(zhì)量件炉。

19. 避免使用 Random 類來生成隨機數(shù)。

Random 類的內(nèi)部實現(xiàn)是使用一個線性同余發(fā)生器來生成隨機數(shù)妻率,這會導(dǎo)致隨機數(shù)的質(zhì)量不高,并且可能導(dǎo)致并發(fā)問題宫静。如果需要生成隨機數(shù)券时,可以使用 ThreadLocalRandom 或者 SecureRandom 等類來代替伏伯。例如:

// 不合適的寫法
Random random = new Random();
int n = random.nextInt(10); // 這會生成一個不太隨機的整數(shù)说搅,并且可能導(dǎo)致并發(fā)問題

// 高性能的寫法
int n = ThreadLocalRandom.current().nextInt(10); // 這會生成一個更隨機的整數(shù),并且避免并發(fā)問題

這樣做可以提高隨機數(shù)的質(zhì)量和安全性弄唧,并避免并發(fā)問題。

20. 避免使用 Log 類來打印日志侯养。

Log 類的內(nèi)部實現(xiàn)是使用一個 PrintStream 對象來輸出日志到控制臺或者文件澄干,這會消耗較多的CPU和內(nèi)存資源,并且可能導(dǎo)致IO阻塞和性能下降麸俘。如果需要打印日志,可以使用 Timber 或者 Logger 等庫來代替逞泄。例如:

// 不合適的寫法
Log.d("TAG", "Hello World!"); // 這會輸出一條日志到控制臺或者文件静檬,消耗CPU和內(nèi)存資源,并且可能導(dǎo)致IO阻塞和性能下降

// 高性能的寫法
Timber.d("Hello World!"); // 這會輸出一條日志到控制臺或者文件侮腹,節(jié)省CPU和內(nèi)存資源稻励,并提高日志輸出的效率和質(zhì)量

這樣做可以避免不必要的IO操作父阻,節(jié)省CPU和內(nèi)存資源望抽,并提高日志輸出的效率和質(zhì)量。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末斟览,一起剝皮案震驚了整個濱河市辑奈,隨后出現(xiàn)的幾起案子已烤,更是在濱河造成了極大的恐慌妓羊,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,002評論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件裕循,死亡現(xiàn)場離奇詭異净刮,居然都是意外死亡,警方通過查閱死者的電腦和手機淹父,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評論 3 400
  • 文/潘曉璐 我一進店門弹灭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來揪垄,“玉大人,你說我怎么就攤上這事捡鱼】崂ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 169,787評論 0 365
  • 文/不壞的土叔 我叫張陵溶浴,是天一觀的道長士败。 經(jīng)常有香客問我,道長谅将,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,237評論 1 300
  • 正文 為了忘掉前任逊躁,我火速辦了婚禮隅熙,結(jié)果婚禮上核芽,老公的妹妹穿的比我還像新娘念脯。我一直安慰自己,他們只是感情好吉懊,可當(dāng)我...
    茶點故事閱讀 69,237評論 6 398
  • 文/花漫 我一把揭開白布假勿。 她就那樣靜靜地躺著,像睡著了一般恶导。 火紅的嫁衣襯著肌膚如雪浸须。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,821評論 1 314
  • 那天裂垦,我揣著相機與錄音肌索,去河邊找鬼。 笑死诚亚,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的闸准。 我是一名探鬼主播梢灭,決...
    沈念sama閱讀 41,236評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼瘾英!你這毒婦竟也來了颂暇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,196評論 0 277
  • 序言:老撾萬榮一對情侶失蹤湿蛔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后阳啥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,716評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡斩狱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,794評論 3 343
  • 正文 我和宋清朗相戀三年所踊,在試婚紗的時候發(fā)現(xiàn)自己被綠了概荷。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,928評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡继薛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惋增,到底是詐尸還是另有隱情,我是刑警寧澤像棘,帶...
    沈念sama閱讀 36,583評論 5 351
  • 正文 年R本政府宣布壶冒,位于F島的核電站,受9級特大地震影響烟零,放射性物質(zhì)發(fā)生泄漏咸作。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,264評論 3 336
  • 文/蒙蒙 一墅诡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧末早,春花似錦、人聲如沸然磷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽痪欲。三九已至,卻和暖如春栗柒,著一層夾襖步出監(jiān)牢的瞬間知举,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評論 1 274
  • 我被黑心中介騙來泰國打工雇锡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人曙痘。 一個月前我還...
    沈念sama閱讀 49,378評論 3 379
  • 正文 我出身青樓立肘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親茧痒。 傳聞我的和親對象是個殘疾皇子融蹂,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,937評論 2 361

推薦閱讀更多精彩內(nèi)容