Android实战:清理内存

原创
2019/09/30 08:15
阅读数 394

编程环境:genymotion android v4.2.2、android studio 2.0。

1. 实战1


1.1 查看内存总量

// import android.annotation.TargetApi;
// import android.app.ActivityManager;
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private String getCurrentMeminfo() {
        StringBuffer sb = new StringBuffer();
        ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
        ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        activityManager.getMemoryInfo(mi);
        sb.append("剩余内存:"+(mi.availMem/1024/1024)+"MB\n");
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            sb.append("总内存: " + (mi.totalMem/1024/1024) + "MB\n");
        }
        sb.append("内存是否过低:" + mi.lowMemory);
        return sb.toString();
    }

在SDK API 15以及之前并不存在ActivityManager.MemoryInfo并没有totalMem属性,而创建项目时候选择的minimum sdk的API为15:

所以在代码中加上了注解@TargetApi以防止报错。这段代码里没有处理API 15以及以下版本的如何获取总内存的问题。

获取内存使用情况的另外一个方法是解析文件/proc/meminfo,总内存、剩余内存等都可以得到,而且该方法没有版本限制。

1.2 清理内存

首先要在AndroidManifest.xml中添加权限:

<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />

内存清理代码如下:

// import android.app.ActivityManager;
    /**
     * 清理内存
     */
    private void clearMem() {
        ActivityManager activityManger = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
        List<activitymanager.runningappprocessinfo> appList = activityManger.getRunningAppProcesses();
        if (appList != null) {
            for (int i = 0; i &lt; appList.size(); i++) {
                ActivityManager.RunningAppProcessInfo appInfo = appList.get(i);
                String[] pkgList = appInfo.pkgList;
                if (appInfo.importance &gt; ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
                    for (int j = 0; j &lt; pkgList.length; j++) {
                        activityManger.killBackgroundProcesses(pkgList[j]);
                    }
                }
            }
        }
    }

ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE这个级别是可以修改的,值不同,内存清理效果不同。 其他值: http://developer.android.com/intl/zh-cn/reference/android/app/ActivityManager.RunningAppProcessInfo.html

1.3 源码

项目结构:

MainActivity.java:

package me.letiantian.memorycleaner;

import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.content.res.Configuration;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.content.Context;
import android.widget.Toast;

import java.util.List;

public class MainActivity extends AppCompatActivity {

    private Button usageBtn, cleanBtn;
    private TextView infoTv;

    private static String LOG_TAG = "cleaner";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.v(LOG_TAG, "onCreate...");

        usageBtn = (Button) findViewById(R.id.usage_btn);
        cleanBtn = (Button) findViewById(R.id.clean_btn);
        infoTv = (TextView) findViewById(R.id.info_tv);

        usageBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.v(LOG_TAG, "" + Build.VERSION_CODES.JELLY_BEAN);  // 16
                infoTv.setText(getCurrentMeminfo());
            }
        });

        cleanBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                infoTv.setText("清理中...");
                clearMem();
                infoTv.setText("清理完成\n" + getCurrentMeminfo());
            }
        });

    }


    /**
     * 获取内存信息
     * @return
     */
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private String getCurrentMeminfo() {
        StringBuffer sb = new StringBuffer();
        ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
        ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        activityManager.getMemoryInfo(mi);
        sb.append("剩余内存:"+(mi.availMem/1024/1024)+"MB\n");
        if(Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.JELLY_BEAN) {
            sb.append("总内存: " + (mi.totalMem/1024/1024) + "MB\n");
        }
        sb.append("内存是否过低:" + mi.lowMemory);
        return sb.toString();
    }

    /**
     * 清理内存
     */
    private void clearMem() {
        ActivityManager activityManger = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
        List<activitymanager.runningappprocessinfo> appList = activityManger.getRunningAppProcesses();
        if (appList != null) {
            for (int i = 0; i &lt; appList.size(); i++) {
                ActivityManager.RunningAppProcessInfo appInfo = appList.get(i);

                Log.v(LOG_TAG, "pid: " + appInfo.pid);
                Log.v(LOG_TAG, "processName: " + appInfo.processName);
                Log.v(LOG_TAG, "importance: " + appInfo.importance);

                String[] pkgList = appInfo.pkgList;
                if (appInfo.importance &gt; ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
                    for (int j = 0; j &lt; pkgList.length; j++) {
                        activityManger.killBackgroundProcesses(pkgList[j]);
                    }
                }
            }
        }
    }

}

1.4 使用效果

但是旋转屏幕后,activity重建,TextView显示的内存信息会消失:

另外,布局仍然视同layout目录下的activity_main布局。

1.5 改进

MainActivity.java中引入代码:

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        String infoTvContent = savedInstanceState.getString("infotv");
        infoTv.setText(infoTvContent);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("infotv", infoTv.getText().toString());
    }

这样在旋转屏幕后重建activity后可以恢复infoTv之前的内容。

也可以用SharedPreferences来储存信息。

另外,在res目录下创建目录layout-land存放横屏的布局文件activity_main.xml。

项目结构:

横屏效果:

1.6 源码

https://github.com/someus/Learn-Android/tree/master/02-memory-cleaner/v1

1.7 参考

How to get current memory usage in android? Android清理内存 Android 一键清理、内存清理功能实现 Android 屏幕旋转 处理 AsyncTask 和 ProgressDialog 的最佳方案 Restoring state of TextView after screen rotation? Losing data when rotate screen

2. 实战2


本文中给实战1中的程序加一个菜单。

2.1 项目结构

2.2 代码

activity_menu.xml内容如下:

<!--?xml version="1.0" encoding="utf-8"?-->
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
    <item android:id="@+id/menu_usage" android:orderInCategory="1" app:showAsAction="never" android:title="查看内存使用情况" />
    <item android:id="@+id/menu_clean" android:orderInCategory="2" app:showAsAction="never" android:title="清理内存" />
</menu>

在MainActivity.java中添加:

    /**
     * 菜单
     * @param menu
     * @return
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.activity_menu, menu);
        return super.onCreateOptionsMenu(menu);
    }

    /**
     * 当某个菜单项被选中时
     * @param item
     * @return
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_usage:
                infoTv.setText(getCurrentMeminfo());
                return true;
            case R.id.menu_clean:
                clearMem();
                infoTv.setText("清理完成\n" + getCurrentMeminfo());
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

2.3 效果

2.4 源码

https://github.com/someus/Learn-Android/tree/master/02-memory-cleaner/v2

2.5 参考

这三个文章质量都不错:

Android系列之UI组件----Menu菜单

 Android ActionBar完全解析,使用官方推荐的最佳导航栏(上)

Android ActionBar完全解析,使用官方推荐的最佳导航栏(下)

3. 实战3


这一次使用ToolBar制作菜单。

3.1 项目结构

3.2 代码

在AndroidManifest.xml中的application节点添加android:theme="@style/Theme.AppCompat.Light.NoActionBar"

<application android:allowbackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsrtl="true" android:theme="@style/Theme.AppCompat.Light.NoActionBar">
    ...
</application>

在布局文件layout/activity_main.xml中添加android.support.v7.widget.Toolbar节点

<!--?xml version="1.0" encoding="utf-8"?-->
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" tools:context="me.letiantian.memorycleanerv3.MainActivity" android:orientation="vertical">

    <android.support.v7.widget.toolbar android:id="@+id/my_toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:elevation="4dp" android:theme="@style/ThemeOverlay.AppCompat.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
    ....... 

MainActivity.java:

package me.letiantian.memorycleanerv3;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private Toolbar myToolbar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myToolbar = (Toolbar) findViewById(R.id.my_toolbar);  //!
        setSupportActionBar(myToolbar);                       //!
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_menu, menu);   //!
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_usage:
                Toast.makeText(getApplicationContext(), "查看内存使用情况", Toast.LENGTH_SHORT).show();
                return true;
            case R.id.menu_clean:
                Toast.makeText(getApplicationContext(), "清理内存", Toast.LENGTH_SHORT).show();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

}

3.3 运行效果

3.4 源码

https://github.com/someus/Learn-Android/tree/master/02-memory-cleaner/v3

3.5 参考

Adding the App Bar android:ToolBar详解(手把手教程) =>标题栏的颜色等是可以修改的。

4. 实战4


本文中将实战1中的程序实现为一个dialog。

4.1 代码

先看效果:

原理很简单,将AndroidManifest.xml中application节点的android:theme的值修改为@style/Theme.AppCompat.Dialog:

    <application android:allowbackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsrtl="true" android:theme="@style/Theme.AppCompat.Dialog">

Android Activity as a dialog中指出了两个需要注意的地方:

1、默认情况下,点击屏幕上程序之外的空间将会关闭程序,可以通过下面的代码禁止这种行为:

this.setFinishOnTouchOutside(false);

2、但这种情况下需要按钮或者其他view被点击时finish程序,例如:

Button close_button = (Button) findViewById(R.id.close_button);
close_button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        finish();
    }
});

4.2 源码

https://github.com/someus/Learn-Android/tree/master/02-memory-cleaner/v4

4.3 参考

Android Activity as a dialog

使用自定义透明Dialog样式的Activity

</application></linearlayout></activitymanager.runningappprocessinfo></activitymanager.runningappprocessinfo>

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部