Android需求2

设置中增加一个一级菜单显示内存信息,进入后的界面可自己定义,显示当前已用内存和手机总内存,同时还有一个按钮,点击按钮清理掉除设置外的所有后台应用。

系统内置的方法的获取内存的方法

  1. strings.xml中的 total_memory 属性 ,发现又系统方法获取内存,通过全局搜索 total_memory
  2. 发现 process_stats_summary的有一项的 title是 total_memory
  3. process_stats_summary进行 R.xml.process_stats_summary 全局搜索
  4. 发现 ProcessStatsSummary.java进行了调用,路径为 com.android.settings.applications,里面是获取内存的方法

手机总内存和已用内存的实现

  1. top_level_setting.xml中添加一级菜单,代码如下:
<PreferenceScreen>
    ...
    ...
	<Preference
        android:fragment="com.android.settings.memory.MemoryFragment"
        android:icon="@drawable/ic_phone_info"
        android:key="top_memory_info"
        android:order="40"
        android:title="@string/memory_info"
        android:summary="@string/read_memory_summary" />
</PreferenceScreen>
  1. com.android.settings目录下新建一个包 memory,并在该包下新建一个类 MemoryFragment,该类继承 SettingsPreferenceFragment使用ActivityManager类来获取内存信息:
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
 ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
 manager.getMemoryInfo(memoryInfo);总内存: memoryInfo.totalMem
可用内存: memoryInfo.availMem


参考文件:

package com.android.settings.memory;

import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;


import android.os.RemoteException;
import android.text.format.Formatter;
import android.util.Log;
import android.app.settings.SettingsEnums;
import android.widget.Toast;

import androidx.preference.Preference;

import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.applications.ProcStatsData.MemInfo;
import com.android.settings.applications.ProcessStatsBase;

import java.util.List;


public class MemoryFragment extends SettingsPreferenceFragment {

    private static final String TAG = "MemoryFragment";
    private Context context;


    private static final String KEY_TOTAL_MEMORY = "my_total_memory";
    private static final String KEY_USED_MEMORY = "my_used_memory";

    private Preference mTotalMemory;
    private Preference mUsedMemory;

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        addPreferencesFromResource(R.xml.memory_info_show);

        mTotalMemory = findPreference(KEY_TOTAL_MEMORY);
        mUsedMemory = findPreference(KEY_USED_MEMORY);

        showMemory();

    }

    public void showMemory(){
        // Get Memory information
        ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
        manager.getMemoryInfo(memoryInfo);

        String totalMemory = Formatter.formatShortFileSize(context, memoryInfo.totalMem);
        String availMemory = Formatter.formatShortFileSize(context, memoryInfo.availMem);
        Log.d(TAG, "totalMemory: " + totalMemory + "<==> availMemory==> " + availMemory);

        //Assign memory information to the control
        mTotalMemory.setSummary(totalMemory);
        mUsedMemory.setSummary(availMemory);
    }

    @Override
    public int getMetricsCategory() {
        return SettingsEnums.PROCESS_STATS_SUMMARY;
    }

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

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        this.context = context;
    }


}
  1. xml包下 新建一个二级目录布局文件 ,名为 memory_info_show.xml
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:settings="http://schemas.android.com/apk/res-auto"
    android:key="customize_menu"
    android:title="@string/memory_menu">

    <Preference
        android:key="my_total_memory"
        android:title="@string/total_memory"
        android:icon="@drawable/ic_emergency_gesture_24dp"
        android:order="100"/>

    <Preference
        android:key="my_used_memory"
        android:title="@string/used_memory"
        android:icon="@drawable/ic_emergency_gesture_24dp"
        android:order="150" />


</PreferenceScreen>
  1. strings.xml中添加标题内容
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <!-- Memory Title -->
    <string name="memory_menu">Memory for Phone</string>
    <!-- Show Memory info -->
    <string name="memory_info">Show Memory</string>
    <!-- Memory Summary -->
    <string name="read_memory_summary">Memory</string>
    <!-- Used Memory -->
    <string name="used_memory">Used Memory</string>
    
    ...
    ...
</resources>
  1. 效果实现

mtk的modem在哪里启动 mtk clearmotion_android studio

杀死除自己外的其他后台应用

清除多任务后台 Recents(多任务)

Android 9.0 与Android 8.1 中的点击Recent键清除按钮有些区别,之前Android 8.1 的全部清除按钮位于SystemUI中,而Android 9.0 的“全部清除”按钮位于Launcher3中;

**Android 获取上下文几个方法的区别 **

  1. getContext(): 这是View的一个方法,获取视图上下文,view一般是依托于Activity,所以这个方法返回的是当前Activity实例,一般在Activity中可以使用 YourActivityName.this代替。
  2. getApplicationContext(): 这个是获取整个生命周期的上下文,一般用于application中,获取app相关的基础信息。
  3. getBaseContext(): 是ContextWrapper中的方法,基本不用,Google也不推荐使用,是一种委托,在一个context获取另一个context。
  4. getApplication(): 这个是获取当前进程的Application实例,可以去操作自己写的Application中的方法。

SystemUI 的参考资料 : https://www.jianshu.com/p/2e0f403e5299

SystemUI 源码分析 :

SystemUIrecents 实现流程分析 :

  1. SystemUI 的功能划分一般为以下几个部分
  • StatusBar(状态栏):通知消息提示和状态展示
  • NavigationBar(导航栏):返回,HOME,Recent
  • KeyGuard(键盘锁):锁屏模块
  • Recents:近期应用管理,以堆叠的形式展示
  • Notification Panel(通知面板):展示系统或应用的通知内容,提供快速系统设置开关
  • Volume:展示或控制音量的变化:媒体、铃音、通知、通话音量
  • ScreenShot(截屏):长按电源键+音量下键后截屏,用以展示截取的屏幕照片/内容
  • PowerUI:主要处理和Power相关的事件。
  • RingtonePlayer:铃音播放
  • StackDivider:控制管理分屏
  • PipUI:画中画管理(Android7.0)

工具使用 :在SDK目录下,sdk/tools/bin/uiautomatorviewer.bat 文件 , 双击打开文件 ,待进入 UI Automator Viewer,手机打开某个页面


清除任务后台除设置外

通过ActivtyManager来进行获取和移除任务栈

  1. 在二级布局文件 memory_info_show.xml中增加一个Preference来设置一个点击事件 my_clear_background
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:settings="http://schemas.android.com/apk/res-auto"
    android:key="customize_menu"
    android:title="@string/memory_menu">

    <Preference
        android:key="my_total_memory"
        android:title="@string/total_memory"
        android:icon="@drawable/ic_emergency_gesture_24dp"
        android:order="100" />

    <Preference
        android:key="my_used_memory"
        android:title="@string/used_memory"
        android:icon="@drawable/ic_emergency_gesture_24dp"
        android:order="150" />

    <Preference
        android:key="my_clear_background"
        android:icon="@drawable/btn_clear_bg"
        android:title="@string/clear_title"
        android:summary="@string/clear_summary"
        android:order="160"/>

</PreferenceScreen>
  1. 在实现类中MemoryFragment.java类中,获取控件的key,并为其添加点击事件,并通过ActivityManager类来进行获取开启的任务栈,并进行判断,移除任务栈,方法
    public void killAllAppsExceptionSettings()
package com.android.settings.memory;

import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;


import android.os.RemoteException;
import android.text.format.Formatter;
import android.util.Log;
import android.app.settings.SettingsEnums;
import android.widget.Toast;

import androidx.preference.Preference;

import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.applications.ProcStatsData.MemInfo;
import com.android.settings.applications.ProcessStatsBase;

import java.util.List;


public class MemoryFragment extends SettingsPreferenceFragment implements Preference.OnPreferenceClickListener {

    private static final String TAG = "MemoryFragment";
    private Context context;


    private static final String KEY_TOTAL_MEMORY = "my_total_memory";
    private static final String KEY_USED_MEMORY = "my_used_memory";
    private static final String KEY_CLEAR_BACKGROUND = "my_clear_background";

    private Preference mTotalMemory;
    private Preference mUsedMemory;
    private Preference mClearBackground;

 	private long freeMemory;

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        addPreferencesFromResource(R.xml.memory_info_show);

        mTotalMemory = findPreference(KEY_TOTAL_MEMORY);
        mUsedMemory = findPreference(KEY_USED_MEMORY);
        mClearBackground = findPreference(KEY_CLEAR_BACKGROUND);

        showMemory();
        mClearBackground.setOnPreferenceClickListener(this);

    }

    public void showMemory(){
        // Get Memory information
        ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
        manager.getMemoryInfo(memoryInfo);
			
		// Get Total Memory , Avail Memory and used Memory
        String totalMemory = Formatter.formatShortFileSize(context, memoryInfo.totalMem);
        String availMemory = Formatter.formatShortFileSize(context, memoryInfo.availMem);
        // 获取已用的内存大小
        String usedMemory= Formatter.formatShortFileSize(context, (memoryInfo.totalMem - memoryInfo.availMem));
        Log.d(TAG, "totalMemory: " + totalMemory + "<==> availMemory==> " + availMemory + "<==> usedMemory " + usedMemory );
 		
 		// 获取当前的可用内存
 		freeMemory = memoryInfo.availMem;

        //Assign memory information to the control
        mTotalMemory.setSummary(totalMemory);
        mUsedMemory.setSummary(availMemory);
    }

    @Override
    public int getMetricsCategory() {
        return SettingsEnums.PROCESS_STATS_SUMMARY;
    }

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

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        this.context = context;
    }

	// 清除除设置应用外其他所有后台应用
    public void killAllAppsExceptionSettings(){
        int MAX_TASKS = 100;
        // 获取Activity管理类
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        // 获取用户最近使用过的应用程序信息集合,第一个参数:最大值,第二个参数:ActivityManager.RECENT_IGNORE_UNAVAILABL
        /**
        *	RecentTaskInfo 类,主要的字段
        * 		Intent	baseIntent	得到能跳转这个Task的Activity,即能通过这个Intent启动这个Intent指向的程序。
        *		int		id			得到这个Task的标识,如果是-1,则标识这个程序没有启动,其他数字表示启动了。
       	*		int		persistentId	任务的唯一值
        */
        List<ActivityManager.RecentTaskInfo> recentTasks = am.getRecentTasks(MAX_TASKS,
                ActivityManager.RECENT_IGNORE_UNAVAILABLE);
        Log.d(TAG, "recentTasks.size = " + recentTasks.size());
        // 进行一个循环遍历,并通过比较,筛选出不需要移除的哪一项,并忽略
        for (ActivityManager.RecentTaskInfo recentInfo : recentTasks) {
            Intent intent = new Intent(recentInfo.baseIntent);
            if (recentInfo.origActivity != null) {
                intent.setComponent(recentInfo.origActivity);
            }
            if (!intent.getComponent().getClassName().equals("com.android.settings.Settings")){
                Log.d(TAG, "forceStopPackage ==> " + intent.getComponent().getPackageName() + "  <==  className ==> " + intent.getComponent().getClassName());
                am.killBackgroundProcesses(intent.getComponent().getPackageName());
                //RemoveTask.removeTask(mContext, recentInfo.persistentId);
                try {
                    //	清除最近的任务  Remove a task by id
                    ActivityManager.getService().removeTask(recentInfo.persistentId);
                } catch (RemoteException e) {
                    Log.w(TAG, "Failed to remove task=" +recentInfo.persistentId);
                }
            }
        }
    }

    @Override
    public boolean onPreferenceClick(Preference preference) {
        Log.d(TAG, "onPreferenceClick: " +  preference.getKey() );
        ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
        manager.getMemoryInfo(memoryInfo);
        // 计算当前的释放的内存
        String nowMemory  = Formatter.formatShortFileSize(context , (freeMemory - memoryInfo.availMem));
        Log.d(TAG,"Last Memory ==> " + nowMemory);
        switch (preference.getKey()){
            case "my_clear_background":
                //SendBroadcast();
                killAllAppsExceptionSettings();
                Toast.makeText(context, "Clear All Apps Success!! Free Memory: " + nowMemory, Toast.LENGTH_SHORT).show();
                break;
        }
        return false;
    }

}
  1. 实现效果
    在Settings中的二级菜单中,点击Clear按钮,实现清除后台所有任务,除Settings外