Android开发实战《手机安全卫士》——10.“进程管理”模块实现 & PopupWindow & 内存清理

1.软件管理——PopupWindow的使用

之前,我们完成了“软件管理”模块中的软件展示功能,现在需要实现——点击某个条目时,弹出对应的选单,在选单中可以执行相应操作,如图所示:

在这里插入图片描述

这个选单可以使用Android官方提供的PopupWindows控件来实现。

修改AppManagerActivity,修改intiListView()方法,对每一项图文条目注册点击事件,并新建showPopupWindow(),作为显示PopupWindow窗体的方法,代码如下:

package com.example.mobilesafe.activity;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.StatFs;
import android.text.format.Formatter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;

import com.example.mobilesafe.R;
import com.example.mobilesafe.dao.AppInfoDao;
import com.example.mobilesafe.domain.AppInfo;

import java.util.ArrayList;
import java.util.List;

public class AppManagerActivity extends AppCompatActivity {

    private ListView lv_app_list;

    private List<AppInfo> mAppInfoList;

    private MyAdapter mAdapter;

    // 系统应用所在的集合
    private List<AppInfo> mSystemList;

    // 用户应用所在的集合
    private List<AppInfo> mCustomerList;

    private TextView tv_title_type;

    private AppInfo mAppInfo;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            // 4.使用数据适配器
            mAdapter = new MyAdapter();
            lv_app_list.setAdapter(mAdapter);
        }
    };


    class MyAdapter extends BaseAdapter{

        // 在ListView中多添加一种类型条目,条目总数有2种
        @Override
        public int getViewTypeCount() {
            return super.getViewTypeCount() + 1;
        }

        // 根据索引值决定展示哪种类型的条目
        @Override
        public int getItemViewType(int position) {
            if (position == 0 || position == mCustomerList.size() + 1){
                // 纯文本条目
                return 0;
            }else {
                // 图文条目
                return 1;
            }
        }

        @Override
        public int getCount() {
            return mCustomerList.size() + mSystemList.size() + 2;
        }

        @Override
        public AppInfo getItem(int position) {
            if (position == 0 || position == mCustomerList.size() + 1){
                // 纯文本条目
                return null;
            }else {
                // 图文条目
                if (position < mCustomerList.size() + 1){
                    // 用户应用
                    return mCustomerList.get(position - 1);
                }else {
                    // 系统应用
                    return mSystemList.get(position - mCustomerList.size() - 2);
                }
            }
            // return mAppInfoList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // 判断当前索引指向的条目类型状态码
            int itemViewType = getItemViewType(position);
            if (itemViewType == 0){
                // 纯文本条目
                ViewTitleHolder holder = null;
                if (convertView == null){
                    convertView = View.inflate(getApplicationContext(),R.layout.list_app_item_text,null);
                    holder = new ViewTitleHolder();
                    holder.tv_title_des = convertView.findViewById(R.id.tv_title_des);
                    convertView.setTag(holder);
                }else {
                    holder = (ViewTitleHolder) convertView.getTag();
                }
                if (position == 0){
                    holder.tv_title_des.setText("用户应用("+mCustomerList.size()+")");
                }else {
                    holder.tv_title_des.setText("系统应用("+mSystemList.size()+")");
                }
                return convertView;
            }else {
                // 图文条目
                ViewHolder holder = null;
                // 1.判断ConverView是否为空
                if (convertView == null){
                    convertView = View.inflate(getApplicationContext(),R.layout.list_app_item,null);
                    // 2.获取控件实例赋值给ViewHolder
                    holder = new ViewHolder();
                    holder.iv_icon_application = convertView.findViewById(R.id.iv_icon_application);
                    holder.tv_app_name = convertView.findViewById(R.id.tv_app_name);
                    holder.tv_app_location = convertView.findViewById(R.id.tv_app_location);
                    // 3.将Holder放到ConverView上
                    convertView.setTag(holder);
                }else {
                    holder = (ViewHolder) convertView.getTag();
                }
                // 4.获取Holder中的控件实例,赋值
                holder.iv_icon_application.setBackground(getItem(position).getIcon());
                holder.tv_app_name.setText(getItem(position).getName());
                // 5.显示应用安装的位置
                if (getItem(position).isSdCard()){
                    holder.tv_app_location.setText("sd卡应用");
                }else {
                    holder.tv_app_location.setText("内存应用");
                }
                // 6.返回现有条目填充上数据的View对象
                return convertView;
            }
        }
    }

    static class ViewHolder{
        ImageView iv_icon_application;
        TextView tv_app_name;
        TextView tv_app_location;
    }

    static class ViewTitleHolder{
        TextView tv_title_des;
    }

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

        // 初始化磁盘 & SD卡可用大小
        initTitle();
        
        // 初始化ListView
        intiListView();

    }

    /**
     * 初始化磁盘 & SD卡可用大小
     */
    private void initTitle() {
        // 0.初始化控件
        TextView tv_memory = findViewById(R.id.tv_memory);
        TextView tv_sd_memory = findViewById(R.id.tv_sd_memory);
        // 1.获取磁盘(内存,区分于手机运行内存)可用大小,磁盘路径
        String path = Environment.getDataDirectory().getAbsolutePath();
        // 2.获取SD卡可用大小,SD卡路径
        String sdpath = Environment.getExternalStorageDirectory().getAbsolutePath();
        // 3.获取以上两个路径下文件夹的可用大小
        long space = getAvailSpace(path);
        long sdspace = getAvailSpace(sdpath);
        // 4.对bytes为单位的数值格式化
        String strSpace = Formatter.formatFileSize(this, space);
        String strSdSpace = Formatter.formatFileSize(this, sdspace);
        // 5.给控件赋值
        tv_memory.setText("磁盘可用:" + strSpace);
        tv_sd_memory.setText("sd卡可用:" + strSdSpace);
    }

    /**
     * 计算文件夹的可用大小
     * @param path 路径名
     * @return 可用空间大小,单位为byte=8bit
     */
    private long getAvailSpace(String path) {
        // 获取可用磁盘大小的对象
        StatFs statFs = new StatFs(path);
        // 获取可用区块的个数
        long availableBlocks = statFs.getAvailableBlocks();
        // 获取区块的大小
        long blockSize = statFs.getBlockSize();
        // 可用空间大小 = 区块大小 * 可用区块个数
        return availableBlocks * blockSize;
    }

    /**
     * 初始化ListView
     */
    private void intiListView() {
        // 1.初始化控件
        tv_title_type = findViewById(R.id.tv_title_type);
        lv_app_list = findViewById(R.id.lv_app_list);
        new Thread(){
            @Override
            public void run() {
                // 2.准备填充ListView中数据适配器的数据
                mAppInfoList = AppInfoDao.getAppInfoList(getApplicationContext());
                mSystemList = new ArrayList<>();
                mCustomerList = new ArrayList<>();
                // 分割集合
                for (AppInfo appInfo : mAppInfoList) {
                    if (appInfo.isSystem()){
                        mSystemList.add(appInfo);
                    }else {
                        mCustomerList.add(appInfo);
                    }
                }
                // 3.发送空消息进行数据绑定
                mHandler.sendEmptyMessage(0);
            }
        }.start();
        // 4.给ListView注册滚动事件
        lv_app_list.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                // 在滚动过程中调用方法
                if (mSystemList != null && mCustomerList != null){
                    if (firstVisibleItem >= mCustomerList.size() + 1){
                        // 滚动到了系统应用
                        tv_title_type.setText("系统应用("+mSystemList.size()+")");
                    }else {
                        // 滚动到了用户应用
                        tv_title_type.setText("用户应用("+mCustomerList.size()+")");
                    }
                }
            }
        });

        // 5.给ListView中的每个条目注册点击事件
        lv_app_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (position == 0 || position == mCustomerList.size() + 1){
                    // 纯文本条目
                    return;
                }else {
                    // 图文条目
                    if (position < mCustomerList.size() + 1){
                        // 用户应用
                        mAppInfo = mCustomerList.get(position - 1);
                    }else {
                        // 系统应用
                        mAppInfo = mSystemList.get(position - mCustomerList.size() - 2);
                    }
                    showPopupWindow(view);
                }
            }
        });
    }

    /**
     * 显示PopupWindow窗体
     * @param view 当前选中条目的view
     */
    private void showPopupWindow(View view) {
        View popupView = View.inflate(this, R.layout.popupwindow_layout, null);
        TextView tv_uninstall = popupView.findViewById(R.id.tv_uninstall);
        TextView tv_start = popupView.findViewById(R.id.tv_start);
        TextView tv_share = popupView.findViewById(R.id.tv_share);

        // 1.创建窗体对象,指定宽高
        PopupWindow popupWindow = new PopupWindow(popupView, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, true);

        // 2.设置一个背景
        popupWindow.setBackgroundDrawable(new ColorDrawable());

        // 3.指定窗体位置
        popupWindow.showAsDropDown(view,50,-view.getHeight());

        // 卸载
        tv_uninstall.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        // 启动
        tv_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        // 分享
        tv_share.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
    }
}

在res/layout下新建popupwindow_layout.xml,作为PopupWindow窗体的布局,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="wrap_content"
    android:background="@drawable/local_popup_bg"
    android:layout_height="wrap_content">

    <TextView
        android:text="卸载"
        android:id="@+id/tv_uninstall"
        android:drawableTop="@drawable/img1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:text="启动"
        android:id="@+id/tv_start"
        android:drawableTop="@drawable/img2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:text="分享"
        android:id="@+id/tv_share"
        android:drawableTop="@drawable/img3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

2.软件管理——PopupWindow的动画

为了丰富PopupWindow的表现效果,我们添加一段淡入淡出的动画效果。

修改AppManagerActivity,修改showPopupWindow()方法,添加一段对PopupWindow出现时的透明 & 缩放动画,代码如下:

    /**
     * 显示PopupWindow窗体
     * @param view 当前选中条目的view
     */
    private void showPopupWindow(View view) {
        View popupView = View.inflate(this, R.layout.popupwindow_layout, null);
        TextView tv_uninstall = popupView.findViewById(R.id.tv_uninstall);
        TextView tv_start = popupView.findViewById(R.id.tv_start);
        TextView tv_share = popupView.findViewById(R.id.tv_share);

        // 设置透明动画
        AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
        alphaAnimation.setDuration(1000);
        alphaAnimation.setFillAfter(true);

        // 设置缩放动画
        ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        scaleAnimation.setDuration(1000);
        alphaAnimation.setFillAfter(true);

        // 设置动画集合Set(传tru代表共享一个数学函数)
        AnimationSet animationSet = new AnimationSet(true);
        animationSet.addAnimation(alphaAnimation);
        animationSet.addAnimation(scaleAnimation);

        // 1.创建窗体对象,指定宽高
        PopupWindow popupWindow = new PopupWindow(popupView, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, true);

        // 2.设置一个背景
        popupWindow.setBackgroundDrawable(new ColorDrawable());

        // 3.指定窗体位置
        popupWindow.showAsDropDown(view,50,-view.getHeight());

        // 4.popupView
        popupView.startAnimation(animationSet);
    }

3.软件管理——卸载应用 & 启动应用 & 分享应用

前面我们完成了在点击每个条目时弹出PopupWindow,现在需要逐步实现PopupWindow中的三个功能——卸载、启动、分享。

修改AppManagerActivity,对PopupWindow中的三个TextView控件分别注册点击事件,执行相应逻辑,注意在删除某个应用后要重写onResume(),以此来更新数据集合,代码如下:

package com.example.mobilesafe.activity;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.StatFs;
import android.text.format.Formatter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;

import com.example.mobilesafe.R;
import com.example.mobilesafe.dao.AppInfoDao;
import com.example.mobilesafe.domain.AppInfo;
import com.example.mobilesafe.utils.ToastUtil;

import java.util.ArrayList;
import java.util.List;

public class AppManagerActivity extends AppCompatActivity {

    private ListView lv_app_list;

    private List<AppInfo> mAppInfoList;

    private MyAdapter mAdapter;

    // 系统应用所在的集合
    private List<AppInfo> mSystemList;

    // 用户应用所在的集合
    private List<AppInfo> mCustomerList;

    private TextView tv_title_type;

    private AppInfo mAppInfo;

    private PopupWindow mPopupWindow;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            // 4.使用数据适配器
            mAdapter = new MyAdapter();
            lv_app_list.setAdapter(mAdapter);
        }
    };

    class MyAdapter extends BaseAdapter{

        // 在ListView中多添加一种类型条目,条目总数有2种
        @Override
        public int getViewTypeCount() {
            return super.getViewTypeCount() + 1;
        }

        // 根据索引值决定展示哪种类型的条目
        @Override
        public int getItemViewType(int position) {
            if (position == 0 || position == mCustomerList.size() + 1){
                // 纯文本条目
                return 0;
            }else {
                // 图文条目
                return 1;
            }
        }

        @Override
        public int getCount() {
            return mCustomerList.size() + mSystemList.size() + 2;
        }

        @Override
        public AppInfo getItem(int position) {
            if (position == 0 || position == mCustomerList.size() + 1){
                // 纯文本条目
                return null;
            }else {
                // 图文条目
                if (position < mCustomerList.size() + 1){
                    // 用户应用
                    return mCustomerList.get(position - 1);
                }else {
                    // 系统应用
                    return mSystemList.get(position - mCustomerList.size() - 2);
                }
            }
            // return mAppInfoList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // 判断当前索引指向的条目类型状态码
            int itemViewType = getItemViewType(position);
            if (itemViewType == 0){
                // 纯文本条目
                ViewTitleHolder holder = null;
                if (convertView == null){
                    convertView = View.inflate(getApplicationContext(),R.layout.list_app_item_text,null);
                    holder = new ViewTitleHolder();
                    holder.tv_title_des = convertView.findViewById(R.id.tv_title_des);
                    convertView.setTag(holder);
                }else {
                    holder = (ViewTitleHolder) convertView.getTag();
                }
                if (position == 0){
                    holder.tv_title_des.setText("用户应用("+mCustomerList.size()+")");
                }else {
                    holder.tv_title_des.setText("系统应用("+mSystemList.size()+")");
                }
                return convertView;
            }else {
                // 图文条目
                ViewHolder holder = null;
                // 1.判断ConverView是否为空
                if (convertView == null){
                    convertView = View.inflate(getApplicationContext(),R.layout.list_app_item,null);
                    // 2.获取控件实例赋值给ViewHolder
                    holder = new ViewHolder();
                    holder.iv_icon_application = convertView.findViewById(R.id.iv_icon_application);
                    holder.tv_app_name = convertView.findViewById(R.id.tv_app_name);
                    holder.tv_app_location = convertView.findViewById(R.id.tv_app_location);
                    // 3.将Holder放到ConverView上
                    convertView.setTag(holder);
                }else {
                    holder = (ViewHolder) convertView.getTag();
                }
                // 4.获取Holder中的控件实例,赋值
                holder.iv_icon_application.setBackground(getItem(position).getIcon());
                holder.tv_app_name.setText(getItem(position).getName());
                // 5.显示应用安装的位置
                if (getItem(position).isSdCard()){
                    holder.tv_app_location.setText("sd卡应用");
                }else {
                    holder.tv_app_location.setText("内存应用");
                }
                // 6.返回现有条目填充上数据的View对象
                return convertView;
            }
        }
    }

    static class ViewHolder{
        ImageView iv_icon_application;
        TextView tv_app_name;
        TextView tv_app_location;
    }

    static class ViewTitleHolder{
        TextView tv_title_des;
    }

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

        // 初始化磁盘 & SD卡可用大小
        initTitle();
        
        // 初始化ListView
        intiListView();

    }

    /**
     * 初始化磁盘 & SD卡可用大小
     */
    private void initTitle() {
        // 0.初始化控件
        TextView tv_memory = findViewById(R.id.tv_memory);
        TextView tv_sd_memory = findViewById(R.id.tv_sd_memory);
        // 1.获取磁盘(内存,区分于手机运行内存)可用大小,磁盘路径
        String path = Environment.getDataDirectory().getAbsolutePath();
        // 2.获取SD卡可用大小,SD卡路径
        String sdpath = Environment.getExternalStorageDirectory().getAbsolutePath();
        // 3.获取以上两个路径下文件夹的可用大小
        long space = getAvailSpace(path);
        long sdspace = getAvailSpace(sdpath);
        // 4.对bytes为单位的数值格式化
        String strSpace = Formatter.formatFileSize(this, space);
        String strSdSpace = Formatter.formatFileSize(this, sdspace);
        // 5.给控件赋值
        tv_memory.setText("磁盘可用:" + strSpace);
        tv_sd_memory.setText("sd卡可用:" + strSdSpace);
    }

    /**
     * 计算文件夹的可用大小
     * @param path 路径名
     * @return 可用空间大小,单位为byte=8bit
     */
    private long getAvailSpace(String path) {
        // 获取可用磁盘大小的对象
        StatFs statFs = new StatFs(path);
        // 获取可用区块的个数
        long availableBlocks = statFs.getAvailableBlocks();
        // 获取区块的大小
        long blockSize = statFs.getBlockSize();
        // 可用空间大小 = 区块大小 * 可用区块个数
        return availableBlocks * blockSize;
    }

    /**
     * 初始化ListView
     */
    private void intiListView() {
        // 1.初始化控件
        tv_title_type = findViewById(R.id.tv_title_type);
        lv_app_list = findViewById(R.id.lv_app_list);
        // 4.给ListView注册滚动事件
        lv_app_list.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                // 在滚动过程中调用方法
                if (mSystemList != null && mCustomerList != null){
                    if (firstVisibleItem >= mCustomerList.size() + 1){
                        // 滚动到了系统应用
                        tv_title_type.setText("系统应用("+mSystemList.size()+")");
                    }else {
                        // 滚动到了用户应用
                        tv_title_type.setText("用户应用("+mCustomerList.size()+")");
                    }
                }
            }
        });

        // 5.给ListView中的每个条目注册点击事件
        lv_app_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (position == 0 || position == mCustomerList.size() + 1){
                    // 纯文本条目
                    return;
                }else {
                    // 图文条目
                    if (position < mCustomerList.size() + 1){
                        // 用户应用
                        mAppInfo = mCustomerList.get(position - 1);
                    }else {
                        // 系统应用
                        mAppInfo = mSystemList.get(position - mCustomerList.size() - 2);
                    }
                    showPopupWindow(view);
                }
            }
        });
    }

    /**
     * 显示PopupWindow窗体
     * @param view 当前选中条目的view
     */
    private void showPopupWindow(View view) {
        View popupView = View.inflate(this, R.layout.popupwindow_layout, null);
        TextView tv_uninstall = popupView.findViewById(R.id.tv_uninstall);
        TextView tv_start = popupView.findViewById(R.id.tv_start);
        TextView tv_share = popupView.findViewById(R.id.tv_share);

        // 设置透明动画
        AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
        alphaAnimation.setDuration(1000);
        alphaAnimation.setFillAfter(true);

        // 设置缩放动画
        ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        scaleAnimation.setDuration(1000);
        alphaAnimation.setFillAfter(true);

        // 设置动画集合Set(传tru代表共享一个数学函数)
        AnimationSet animationSet = new AnimationSet(true);
        animationSet.addAnimation(alphaAnimation);
        animationSet.addAnimation(scaleAnimation);

        // 1.创建窗体对象,指定宽高
        mPopupWindow = new PopupWindow(popupView, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, true);

        // 2.设置一个背景
        mPopupWindow.setBackgroundDrawable(new ColorDrawable());

        // 3.指定窗体位置
        mPopupWindow.showAsDropDown(view,50,-view.getHeight());

        // 4.popupView
        popupView.startAnimation(animationSet);

        // 卸载
        tv_uninstall.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mAppInfo.isSystem()){
                    ToastUtil.show(getApplicationContext(),"此应用为系统应用,不能卸载!");
                }else {
                    // 隐式Intent启动卸载功能
                    Intent intent = new Intent("android.intent.action.DELETE");
                    intent.addCategory("android.intent.category.DEFAULT");
                    intent.setData(Uri.parse("package:" + mAppInfo.getPackagename()));
                    startActivity(intent);
                }
                // 点击窗体后消失窗体
                if (mPopupWindow != null){
                    mPopupWindow.dismiss();
                }
            }
        });

        // 启动
        tv_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 通过桌面去启动指定包名应用
                PackageManager packageManager = getPackageManager();
                Intent launchIntentForPackage = packageManager.getLaunchIntentForPackage(mAppInfo.getPackagename());// 开启指定包名
                if(launchIntentForPackage != null){
                    startActivity(launchIntentForPackage);
                }else {
                    ToastUtil.show(getApplicationContext(),"此应用不能被开启!");
                }
                // 点击窗体后消失窗体
                if (mPopupWindow != null){
                    mPopupWindow.dismiss();
                }
            }
        });

        // 分享
        tv_share.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 通过短信应用,向外发送短信(启动短信应用)
                Intent intent = new Intent(Intent.ACTION_SEND);
                intent.putExtra(Intent.EXTRA_TEXT,"分享一个应用,应用名称为:" + mAppInfo.getName());
                intent.setType("text/plain");
                startActivity(intent);
                // 点击窗体后消失窗体
                if (mPopupWindow != null){
                    mPopupWindow.dismiss();
                }
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 重新获取数据
        getData();
    }

    /**
     * 获取数据的方法
     */
    private void getData(){
        new Thread(){
            @Override
            public void run() {
                // 2.准备填充ListView中数据适配器的数据
                mAppInfoList = AppInfoDao.getAppInfoList(getApplicationContext());
                mSystemList = new ArrayList<>();
                mCustomerList = new ArrayList<>();
                // 分割集合
                for (AppInfo appInfo : mAppInfoList) {
                    if (appInfo.isSystem()){
                        mSystemList.add(appInfo);
                    }else {
                        mCustomerList.add(appInfo);
                    }
                }
                // 3.发送空消息进行数据绑定
                mHandler.sendEmptyMessage(0);
            }
        }.start();
    }
}

4.进程管理——布局实现

前面我们完成了“软件管理”模块的编写,现在需要完成“进程管理”模块的编写,如图所示:

在这里插入图片描述

该界面需要显示以下信息:

  • 进程数
  • 使用内存/总共内存
  • 运行中的进程
  • 全选 & 反选 & 一键清理 & 设置

首先修改HomeActivity,修改initData()方法,添加GridView中第四个条目的点击事件,代码如下:

/**
     * 2.初始化数据
     */
    private void initData() {
        // 1.初始化每个图标的标题
        mTitleStrs = new String[]{"手机防盗","通信卫士","软件管理","进程管理","流量统计","手机杀毒","缓存清理","高级工具","设置中心"};
        // 2.初始化每个图标的图像
        mDrawableIds = new int[]{R.drawable.home_safe,R.drawable.home_callmsgsafe,R.drawable.home_apps,R.drawable.home_taskmanager,R.drawable.home_netmanager,R.drawable.home_trojan,R.drawable.home_sysoptimize,R.drawable.home_tools,R.drawable.home_settings};
        // 3.为GridView设置数据适配器
        gv_home.setAdapter(new MyAdapter());
        // 4.注册GridView中单个条目的点击事件
        gv_home.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                switch (position){
                    case 0:
                        // 手机防盗
                        showDialog();
                        break;
                    case 1:
                        // 通信卫士
                        startActivity(new Intent(getApplicationContext(),BlackNumberActivity.class));
                        break;
                    case 2:
                        // 软件管理
                        startActivity(new Intent(getApplicationContext(),AppManagerActivity.class));
                        break;
                    case 3:
                        // 进程管理
                        startActivity(new Intent(getApplicationContext(),ProcessManagerActivity.class));
                        break;
                    case 7:
                        // 高级工具
                        startActivity(new Intent(getApplicationContext(),AToolActivity.class));
                        break;
                    case 8:
                        // 设置中心
                        Intent intent = new Intent(getApplicationContext(), SettingActivity.class);
                        startActivity(intent);
                        break;
                    default:
                        break;
                }
            }
        });
    }

创建一个名为ProcessManagerActivity的Activity,作为进程管理的界面,首先修改其布局文件activity_process_manager.xml,代码如下:

<?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"
    tools:context=".activity.ProcessManagerActivity"
    android:orientation="vertical">

    <TextView
        android:text="进程管理"
        style="@style/TitleStyle"/>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/tv_process_count"
            android:text="进程总数"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

        <TextView
            android:id="@+id/tv_memory_info"
            android:text="剩余/总共"
            android:layout_alignParentRight="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

    </RelativeLayout>

    <!-- ListView默认不占高度 -->
    <ListView
        android:id="@+id/lv_process_list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_all"
            android:layout_width="0dp"
            android:text="全选"
            android:layout_weight="1"
            android:layout_height="wrap_content"/>

        <Button
            android:id="@+id/btn_reverse"
            android:layout_width="0dp"
            android:text="反选"
            android:layout_weight="1"
            android:layout_height="wrap_content"/>

        <Button
            android:id="@+id/btn_clear"
            android:layout_width="0dp"
            android:text="一键清理"
            android:layout_weight="1"
            android:layout_height="wrap_content"/>

        <Button
            android:id="@+id/btn_setting"
            android:layout_width="0dp"
            android:text="设置"
            android:layout_weight="1"
            android:layout_height="wrap_content"/>

    </LinearLayout>

</LinearLayout>

5.进程管理——获取可用内存数 & 总内存数

上一节我们完成了“进程管理”模块中的界面编写,现在需要获取到可用内存和总内存数,并且显示上去。

在dao包下新建ProcessInfoDao,作为提供进程信息的工具类,拥有几个常用的方法,代码如下:

package com.example.mobilesafe.dao;

import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Debug;

import com.example.mobilesafe.R;
import com.example.mobilesafe.domain.ProcessInfo;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class ProcessInfoDao {

    /**
     * 获取进程总数的方法
     * @param context 上下文环境
     * @return
     */
    public static int getProcessCount(Context context){
        // 1.获取ActivityManager对象
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        // 2.获取正在运行的进程的集合
        List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();
        // 3.返回集合的总数
        return runningAppProcesses.size();
    }

    /**
     * 获取可用空间的大小
     * @param context 上下文环境
     * @return 返回可用的内存数,bytes
     */
    public static long getAvailSpace(Context context){
        // 1.获取ActivityManager对象
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        // 2.构建存储可用内存的对象
        ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
        // 3.给MemoryInfo对象赋值(可用内存)
        activityManager.getMemoryInfo(memoryInfo);
        // 4.获取MemoryInfo中相应的可用内存大小
        return memoryInfo.availMem;
    }

    /**
     * 获取所有空间的大小
     * @param context 上下文环境
     * @return 返回可用的内存数,单位为bytes
     */
    @TargetApi(16)
    public static long getTotalSpace(Context context){
        if (Build.VERSION.SDK_INT >= 16){
            // api版本大于16的方式
            // 1.获取ActivityManager对象
            ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
            // 2.构建存储可用内存的对象
            ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
            // 3.给MemoryInfo对象赋值(所有内存)
            activityManager.getMemoryInfo(memoryInfo);
            // 4.获取MemoryInfo中相应的所有内存大小
            return memoryInfo.totalMem;
        }else {
            // api版本小于16的方式
            // 如果你的api版本在16以下,需要读取proc/meminfo文件,读取第一行,获取数字字符,转换成bytes信息返回
            FileReader fileReader = null;
            BufferedReader bufferedReader = null;
            try {
                fileReader = new FileReader("proc/meminfo");
                bufferedReader = new BufferedReader(fileReader);
                String lineOne = bufferedReader.readLine();
                // 将字符串转换成字符数组
                char[] chars = lineOne.toCharArray();
                // 循环遍历每一个字符,如果此字符的ASCII码在0到9的区域内,说明此字符有效
                StringBuffer stringBuffer = new StringBuffer();
                for (char c : chars) {
                    if (c >= '0' && c <= '9'){
                        stringBuffer.append(c);
                    }
                }
                // 将字符数组转化成字符串,解析成long类型,并且乘1024转换成byte
                return Long.parseLong(stringBuffer.toString()) * 1024;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {

                    try {
                        if (fileReader != null && bufferedReader != null) {
                            fileReader.close();
                            bufferedReader.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
            }
        }
        return 0;
    }

    /**
     * 获取进程信息的列表
     * @param context 上下文环境
     * @return 进程信息的列表
     */
    public static List<ProcessInfo> getProcessInfoList(Context context){
        // 获取进程相关信息

        // 0.创建ProcessInfo集合
        List<ProcessInfo> processInfoList = new ArrayList<>();
        // 1.获取ActivityManager对象和PackageManger管理者对象
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        PackageManager packageManager = context.getPackageManager();
        // 2.获取正在运行的进程的集合
        List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();
        // 3.循环遍历上述集合,获取进程相关信息(名称,包名,图标,使用内存大小,是否为系统进程)
        for (ActivityManager.RunningAppProcessInfo runningAppProcess : runningAppProcesses) {
            ProcessInfo processInfo = new ProcessInfo();
            // 4.获取进程名称,即包名
            processInfo.setPackageName(runningAppProcess.processName);
            // 5.获取进程占用的内存大小(传递一个进程对应的pid数组)
            Debug.MemoryInfo[] processMemoryInfo = activityManager.getProcessMemoryInfo(new int[]{runningAppProcess.pid}); // 数组中索引为0的对象为当前线程的内存信息的对象
            Debug.MemoryInfo memoryInfo = processMemoryInfo[0];
            processInfo.setMemSize(memoryInfo.getTotalPrivateDirty() * 1024);
            try {
                ApplicationInfo applicationInfo = packageManager.getApplicationInfo(runningAppProcess.processName, 0);
                // 6.获取应用的名称
                processInfo.setName(applicationInfo.loadLabel(packageManager).toString());
                // 7.获取应用的图标
                processInfo.setIcon(applicationInfo.loadIcon(packageManager));
                // 8.判断是否为启动线程
                if ((applicationInfo.flags & applicationInfo.FLAG_SYSTEM) == applicationInfo.FLAG_SYSTEM){
                    processInfo.setSystem(true);
                }else {
                    processInfo.setSystem(false);
                }
            } catch (PackageManager.NameNotFoundException e) {
                // 需要处理,即非应用的无名称、无图标的进程
                processInfo.setName(runningAppProcess.processName);
                processInfo.setIcon(context.getResources().getDrawable(R.drawable.ic_launcher));
                processInfo.setSystem(true);
                e.printStackTrace();
            }
            processInfoList.add(processInfo);
        }
        return processInfoList;
    }
}

为了将条目信息更好地进行维护,在domain包下新建ProcessInfo,作为封装进程信息的实体类,代码如下:

package com.example.mobilesafe.domain;

import android.graphics.drawable.Drawable;

public class ProcessInfo {

    private String name; // 应用名称

    private Drawable icon; // 应用图标

    private long memSize; // 应用已使用的内存数

    private boolean isCheck; // 应用是否被选中

    private boolean isSystem; // 应用是否为系统应用

    public String packageName; // 如果应用服务没有名称,则将其应用所在的包名作为名称

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Drawable getIcon() {
        return icon;
    }

    public void setIcon(Drawable icon) {
        this.icon = icon;
    }

    public long getMemSize() {
        return memSize;
    }

    public void setMemSize(long memSize) {
        this.memSize = memSize;
    }

    public boolean isCheck() {
        return isCheck;
    }

    public void setCheck(boolean check) {
        isCheck = check;
    }

    public boolean isSystem() {
        return isSystem;
    }

    public void setSystem(boolean system) {
        isSystem = system;
    }

    public String getPackageName() {
        return packageName;
    }

    public void setPackageName(String packageName) {
        this.packageName = packageName;
    }
}

6.进程管理——显示内存使用情况

上一节中我们完成了工具类的编写,现在就是需要使用这个工具类来实现内存情况的可视化管理。

修改ProcessManagerActivity,使用之前编写好的工具类获取可用内存/总内存大小,并且格式化显示到文本控件上,代码如下:

package com.example.mobilesafe.activity;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.text.format.Formatter;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

import com.example.mobilesafe.R;
import com.example.mobilesafe.dao.ProcessInfoDao;

public class ProcessManagerActivity extends AppCompatActivity {

    private TextView tv_process_count;

    private TextView tv_memory_info;

    private ListView lv_process_list;

    private Button btn_all;

    private Button btn_reverse;

    private Button btn_clear;

    private Button btn_setting;

    private int mProcessCount; // 进程总数

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

        // 初始化UI
        initUI();

        // 初始化标题上的信息:进程总数,内存使用情况
        initTitleData();
    }

    /**
     * 初始化UI
     */
    private void initUI() {
        tv_process_count = findViewById(R.id.tv_process_count);
        tv_memory_info = findViewById(R.id.tv_memory_info);
        lv_process_list = findViewById(R.id.lv_process_list);
        btn_all = findViewById(R.id.btn_all);
        btn_reverse = findViewById(R.id.btn_reverse);
        btn_clear = findViewById(R.id.btn_clear);
        btn_setting = findViewById(R.id.btn_setting);

        btn_all.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        btn_reverse.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        btn_clear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        btn_setting.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
    }

    /**
     * 初始化标题上的信息:进程总数,内存使用情况
     */
    private void initTitleData() {
        // 获取进程总数
        mProcessCount = ProcessInfoDao.getProcessCount(this);
        tv_process_count.setText("进程总数:" + mProcessCount);
        // 获取可用内存大小
        long availSpace = ProcessInfoDao.getAvailSpace(this);
        String strAvailSpace = Formatter.formatFileSize(this, availSpace); // 格式化
        // 获取总内存大小
        long totalSpace = ProcessInfoDao.getTotalSpace(this);
        String strTotalSpace = Formatter.formatFileSize(this, totalSpace); // 格式化
        tv_memory_info.setText("剩余/总共" + strAvailSpace + "/" + strTotalSpace);
    }
}

7.进程管理——列表数据填充

前面我们完成了内存使用情况的获取和显示,现在需要将进程信息填充到列表控件中。

修改ProcessManagerActivity,参考之前写过的AppManagerActivity,完善相应逻辑,代码如下:

package com.example.mobilesafe.activity;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.format.Formatter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.example.mobilesafe.R;
import com.example.mobilesafe.dao.ProcessInfoDao;
import com.example.mobilesafe.domain.AppInfo;
import com.example.mobilesafe.domain.ProcessInfo;

import java.util.ArrayList;
import java.util.List;

public class ProcessManagerActivity extends AppCompatActivity {

    private TextView tv_process_count;

    private TextView tv_memory_info;

    private ListView lv_process_list;

    private Button btn_all;

    private Button btn_reverse;

    private Button btn_clear;

    private Button btn_setting;

    private int mProcessCount; // 进程总数

    private List<ProcessInfo> mProcessInfoList;

    private List<ProcessInfo> mSystemList;

    private List<ProcessInfo> mCustomerList;

    private MyAdapter mAdapter;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            mAdapter = new MyAdapter();
            lv_process_list.setAdapter(mAdapter);
        }
    };

    class MyAdapter extends BaseAdapter {

        // 在ListView中多添加一种类型条目,条目总数有2种
        @Override
        public int getViewTypeCount() {
            return super.getViewTypeCount() + 1;
        }

        // 根据索引值决定展示哪种类型的条目
        @Override
        public int getItemViewType(int position) {
            if (position == 0 || position == mCustomerList.size() + 1){
                // 纯文本条目
                return 0;
            }else {
                // 图文条目
                return 1;
            }
        }

        @Override
        public int getCount() {
            return mCustomerList.size() + mSystemList.size() + 2;
        }

        @Override
        public ProcessInfo getItem(int position) {
            if (position == 0 || position == mCustomerList.size() + 1){
                // 纯文本条目
                return null;
            }else {
                // 图文条目
                if (position < mCustomerList.size() + 1){
                    // 用户应用
                    return mCustomerList.get(position - 1);
                }else {
                    // 系统应用
                    return mSystemList.get(position - mCustomerList.size() - 2);
                }
            }
            // return mAppInfoList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // 判断当前索引指向的条目类型状态码
            int itemViewType = getItemViewType(position);
            if (itemViewType == 0){
                // 纯文本条目
                ViewTitleHolder holder = null;
                if (convertView == null){
                    convertView = View.inflate(getApplicationContext(),R.layout.list_app_item_text,null);
                    holder = new ViewTitleHolder();
                    holder.tv_title_des = convertView.findViewById(R.id.tv_title_des);
                    convertView.setTag(holder);
                }else {
                    holder = (ViewTitleHolder) convertView.getTag();
                }
                if (position == 0){
                    holder.tv_title_des.setText("用户进程("+mCustomerList.size()+")");
                }else {
                    holder.tv_title_des.setText("系统进程("+mSystemList.size()+")");
                }
                return convertView;
            }else {
                // 图文条目
                ViewHolder holder = null;
                // 1.判断ConverView是否为空
                if (convertView == null){
                    convertView = View.inflate(getApplicationContext(),R.layout.list_process_item,null);
                    // 2.获取控件实例赋值给ViewHolder
                    holder = new ViewHolder();
                    holder.iv_icon_application = convertView.findViewById(R.id.iv_icon_application);
                    holder.tv_app_name = convertView.findViewById(R.id.tv_app_name);
                    holder.tv_memory = convertView.findViewById(R.id.tv_memory);
                    holder.cb_box = convertView.findViewById(R.id.cb_box);
                    // 3.将Holder放到ConverView上
                    convertView.setTag(holder);
                }else {
                    holder = (ViewHolder) convertView.getTag();
                }
                // 4.获取Holder中的控件实例,赋值
                holder.iv_icon_application.setBackground(getItem(position).getIcon());
                holder.tv_app_name.setText(getItem(position).getName());
                String strMemorySize = Formatter.formatFileSize(getApplicationContext(), getItem(position).getMemSize());
                holder.tv_memory.setText(strMemorySize);
                // 5.本应用无法被选中,所以先讲CheckBox隐藏
                if ((getItem(position).getPackageName()).equals(getPackageName())){
                    holder.cb_box.setVisibility(View.GONE);
                }else {
                    holder.cb_box.setVisibility(View.VISIBLE);
                }
                holder.cb_box.setChecked(getItem(position).isCheck());
                // 6.返回现有条目填充上数据的View对象
                return convertView;
            }
        }
    }

    static class ViewHolder{
        ImageView iv_icon_application;
        TextView tv_app_name;
        TextView tv_memory;
        CheckBox cb_box;
    }

    static class ViewTitleHolder{
        TextView tv_title_des;
    }

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

        // 初始化UI
        initUI();

        // 初始化标题上的信息:进程总数,内存使用情况
        initTitleData();

        // 初始化ListView列表中的数据
        initListData();
    }

    /**
     * 初始化UI
     */
    private void initUI() {
        tv_process_count = findViewById(R.id.tv_process_count);
        tv_memory_info = findViewById(R.id.tv_memory_info);
        lv_process_list = findViewById(R.id.lv_process_list);
        btn_all = findViewById(R.id.btn_all);
        btn_reverse = findViewById(R.id.btn_reverse);
        btn_clear = findViewById(R.id.btn_clear);
        btn_setting = findViewById(R.id.btn_setting);

        btn_all.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        btn_reverse.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        btn_clear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        btn_setting.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
    }

    /**
     * 初始化标题上的信息:进程总数,内存使用情况
     */
    private void initTitleData() {
        // 获取进程总数
        mProcessCount = ProcessInfoDao.getProcessCount(this);
        tv_process_count.setText("进程总数:" + mProcessCount);
        // 获取可用内存大小
        long availSpace = ProcessInfoDao.getAvailSpace(this);
        String strAvailSpace = Formatter.formatFileSize(this, availSpace); // 格式化
        // 获取总内存大小
        long totalSpace = ProcessInfoDao.getTotalSpace(this);
        String strTotalSpace = Formatter.formatFileSize(this, totalSpace); // 格式化
        tv_memory_info.setText("剩余/总共" + strAvailSpace + "/" + strTotalSpace);
    }

    /**
     * 初始化列表中的数据
     */
    private void initListData() {
        getData();
    }

    /**
     * 获取数据的方法
     */
    private void getData(){
        new Thread(){
            @Override
            public void run() {
                // 2.准备填充ListView中数据适配器的数据
                mProcessInfoList = ProcessInfoDao.getProcessInfoList(getApplicationContext());
                mSystemList = new ArrayList<>();
                mCustomerList = new ArrayList<>();
                // 分割集合
                for (ProcessInfo processInfo : mProcessInfoList) {
                    if (processInfo.isSystem()){
                        // 系统进程
                        mSystemList.add(processInfo);
                    }else {
                        // 用户进程
                        mCustomerList.add(processInfo);
                    }
                }
                // 3.发送空消息进行数据绑定
                mHandler.sendEmptyMessage(0);
            }
        }.start();
    }
}

为了更好地显示图文条目,新建一个名为list_process_item.xml的布局文件,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/iv_icon_application"
        android:background="@drawable/ic_launcher"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/tv_app_name"
        android:layout_toRightOf="@id/iv_icon_application"
        android:text="应用名称"
        android:textColor="#000"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/tv_memory"
        android:layout_toRightOf="@id/iv_icon_application"
        android:layout_below="@id/tv_app_name"
        android:text="占用内存大小"
        android:textColor="#000"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <CheckBox
        android:id="@+id/cb_box"
        android:clickable="false"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</RelativeLayout>

8.进程管理——常驻悬浮框

跟“软件管理”模块一样,“进程管理”模块同样需要一个常驻悬浮框的功能。

修改activity_process_manager.xml,同样适用一个帧布局进行包装,代码如下:

<?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"
    tools:context=".activity.ProcessManagerActivity"
    android:orientation="vertical">

    <TextView
        android:text="进程管理"
        style="@style/TitleStyle"/>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/tv_process_count"
            android:text="进程总数"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

        <TextView
            android:id="@+id/tv_memory_info"
            android:text="剩余/总共"
            android:layout_alignParentRight="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

    </RelativeLayout>

    <!-- ListView默认不占高度 -->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
        
        <ListView
            android:id="@+id/lv_process_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

        <TextView
            android:id="@+id/tv_title_type"
            android:background="#ccc"
            android:textColor="#fff"
            android:text="条目类型的说明"
            android:padding="5dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

    </FrameLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_all"
            android:layout_width="0dp"
            android:text="全选"
            android:layout_weight="1"
            android:layout_height="wrap_content"/>

        <Button
            android:id="@+id/btn_reverse"
            android:layout_width="0dp"
            android:text="反选"
            android:layout_weight="1"
            android:layout_height="wrap_content"/>

        <Button
            android:id="@+id/btn_clear"
            android:layout_width="0dp"
            android:text="一键清理"
            android:layout_weight="1"
            android:layout_height="wrap_content"/>

        <Button
            android:id="@+id/btn_setting"
            android:layout_width="0dp"
            android:text="设置"
            android:layout_weight="1"
            android:layout_height="wrap_content"/>

    </LinearLayout>

</LinearLayout>

修改ProcessManagerActivity,完善相应逻辑,代码如下:

package com.example.mobilesafe.activity;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.format.Formatter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.example.mobilesafe.R;
import com.example.mobilesafe.dao.ProcessInfoDao;
import com.example.mobilesafe.domain.ProcessInfo;

import java.util.ArrayList;
import java.util.List;

public class ProcessManagerActivity extends AppCompatActivity {

    private TextView tv_process_count;

    private TextView tv_memory_info;

    private TextView tv_title_type;

    private ListView lv_process_list;

    private Button btn_all;

    private Button btn_reverse;

    private Button btn_clear;

    private Button btn_setting;

    private int mProcessCount; // 进程总数

    private List<ProcessInfo> mProcessInfoList;

    private List<ProcessInfo> mSystemList;

    private List<ProcessInfo> mCustomerList;

    private MyAdapter mAdapter;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            mAdapter = new MyAdapter();
            lv_process_list.setAdapter(mAdapter);
            if (tv_title_type != null && mCustomerList != null ){
                tv_title_type.setText("用户进程("+mCustomerList.size()+")");
            }
        }
    };


    class MyAdapter extends BaseAdapter {

        // 在ListView中多添加一种类型条目,条目总数有2种
        @Override
        public int getViewTypeCount() {
            return super.getViewTypeCount() + 1;
        }

        // 根据索引值决定展示哪种类型的条目
        @Override
        public int getItemViewType(int position) {
            if (position == 0 || position == mCustomerList.size() + 1){
                // 纯文本条目
                return 0;
            }else {
                // 图文条目
                return 1;
            }
        }

        @Override
        public int getCount() {
            return mCustomerList.size() + mSystemList.size() + 2;
        }

        @Override
        public ProcessInfo getItem(int position) {
            if (position == 0 || position == mCustomerList.size() + 1){
                // 纯文本条目
                return null;
            }else {
                // 图文条目
                if (position < mCustomerList.size() + 1){
                    // 用户应用
                    return mCustomerList.get(position - 1);
                }else {
                    // 系统应用
                    return mSystemList.get(position - mCustomerList.size() - 2);
                }
            }
            // return mAppInfoList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // 判断当前索引指向的条目类型状态码
            int itemViewType = getItemViewType(position);
            if (itemViewType == 0){
                // 纯文本条目
                ViewTitleHolder holder = null;
                if (convertView == null){
                    convertView = View.inflate(getApplicationContext(),R.layout.list_app_item_text,null);
                    holder = new ViewTitleHolder();
                    holder.tv_title_des = convertView.findViewById(R.id.tv_title_des);
                    convertView.setTag(holder);
                }else {
                    holder = (ViewTitleHolder) convertView.getTag();
                }
                if (position == 0){
                    holder.tv_title_des.setText("用户进程("+mCustomerList.size()+")");
                }else {
                    holder.tv_title_des.setText("系统进程("+mSystemList.size()+")");
                }
                return convertView;
            }else {
                // 图文条目
                ViewHolder holder = null;
                // 1.判断ConverView是否为空
                if (convertView == null){
                    convertView = View.inflate(getApplicationContext(),R.layout.list_process_item,null);
                    // 2.获取控件实例赋值给ViewHolder
                    holder = new ViewHolder();
                    holder.iv_icon_application = convertView.findViewById(R.id.iv_icon_application);
                    holder.tv_app_name = convertView.findViewById(R.id.tv_app_name);
                    holder.tv_memory = convertView.findViewById(R.id.tv_memory);
                    holder.cb_box = convertView.findViewById(R.id.cb_box);
                    // 3.将Holder放到ConverView上
                    convertView.setTag(holder);
                }else {
                    holder = (ViewHolder) convertView.getTag();
                }
                // 4.获取Holder中的控件实例,赋值
                holder.iv_icon_application.setBackground(getItem(position).getIcon());
                holder.tv_app_name.setText(getItem(position).getName());
                String strMemorySize = Formatter.formatFileSize(getApplicationContext(), getItem(position).getMemSize());
                holder.tv_memory.setText(strMemorySize);
                // 5.本进程无法被选中,所以先将CheckBox隐藏
                if ((getItem(position).getPackageName()).equals(getPackageName())){
                    holder.cb_box.setVisibility(View.GONE);
                }else {
                    holder.cb_box.setVisibility(View.VISIBLE);
                }
                holder.cb_box.setChecked(getItem(position).isCheck());
                // 6.返回现有条目填充上数据的View对象
                return convertView;
            }
        }
    }

    static class ViewHolder{
        ImageView iv_icon_application;
        TextView tv_app_name;
        TextView tv_memory;
        CheckBox cb_box;
    }

    static class ViewTitleHolder{
        TextView tv_title_des;
    }

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

        // 初始化UI
        initUI();

        // 初始化标题上的信息:进程总数,内存使用情况
        initTitleData();

        // 初始化ListView列表中的数据
        initListData();
    }

    /**
     * 初始化UI
     */
    private void initUI() {
        tv_process_count = findViewById(R.id.tv_process_count);
        tv_memory_info = findViewById(R.id.tv_memory_info);
        tv_title_type = findViewById(R.id.tv_title_type);
        lv_process_list = findViewById(R.id.lv_process_list);
        btn_all = findViewById(R.id.btn_all);
        btn_reverse = findViewById(R.id.btn_reverse);
        btn_clear = findViewById(R.id.btn_clear);
        btn_setting = findViewById(R.id.btn_setting);

        // 给ListView注册滚动事件
        lv_process_list.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                // 在滚动过程中调用方法
                if (mSystemList != null && mCustomerList != null){
                    if (firstVisibleItem >= mCustomerList.size() + 1){
                        // 滚动到了系统应用
                        tv_title_type.setText("系统进程("+mSystemList.size()+")");
                    }else {
                        // 滚动到了用户应用
                        tv_title_type.setText("用户进程("+mCustomerList.size()+")");
                    }
                }
            }
        });

        btn_all.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        btn_reverse.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        btn_clear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        btn_setting.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
    }

    /**
     * 初始化标题上的信息:进程总数,内存使用情况
     */
    private void initTitleData() {
        // 获取进程总数
        mProcessCount = ProcessInfoDao.getProcessCount(this);
        tv_process_count.setText("进程总数:" + mProcessCount);
        // 获取可用内存大小
        long availSpace = ProcessInfoDao.getAvailSpace(this);
        String strAvailSpace = Formatter.formatFileSize(this, availSpace); // 格式化
        // 获取总内存大小
        long totalSpace = ProcessInfoDao.getTotalSpace(this);
        String strTotalSpace = Formatter.formatFileSize(this, totalSpace); // 格式化
        tv_memory_info.setText("剩余/总共" + strAvailSpace + "/" + strTotalSpace);
    }

    /**
     * 初始化列表中的数据
     */
    private void initListData() {
        getData();
    }

    /**
     * 获取数据的方法
     */
    private void getData(){
        new Thread(){
            @Override
            public void run() {
                // 2.准备填充ListView中数据适配器的数据
                mProcessInfoList = ProcessInfoDao.getProcessInfoList(getApplicationContext());
                mSystemList = new ArrayList<>();
                mCustomerList = new ArrayList<>();
                // 分割集合
                for (ProcessInfo processInfo : mProcessInfoList) {
                    if (processInfo.isSystem()){
                        // 系统进程
                        mSystemList.add(processInfo);
                    }else {
                        // 用户进程
                        mCustomerList.add(processInfo);
                    }
                }
                // 3.发送空消息进行数据绑定
                mHandler.sendEmptyMessage(0);
            }
        }.start();
    }
}

9.进程管理——点击过程中选中状态切换

修改ProcessManagerActivity,给列表控件注册点击事件,完善相应逻辑,代码如下:

package com.example.mobilesafe.activity;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.format.Formatter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.example.mobilesafe.R;
import com.example.mobilesafe.dao.ProcessInfoDao;
import com.example.mobilesafe.domain.ProcessInfo;

import java.util.ArrayList;
import java.util.List;

public class ProcessManagerActivity extends AppCompatActivity {

    private TextView tv_process_count;

    private TextView tv_memory_info;

    private TextView tv_title_type;

    private ListView lv_process_list;

    private Button btn_all;

    private Button btn_reverse;

    private Button btn_clear;

    private Button btn_setting;

    private int mProcessCount; // 进程总数

    private List<ProcessInfo> mProcessInfoList;

    private List<ProcessInfo> mSystemList;

    private List<ProcessInfo> mCustomerList;

    private MyAdapter mAdapter;

    private ProcessInfo mProcessInfo;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            mAdapter = new MyAdapter();
            lv_process_list.setAdapter(mAdapter);
            if (tv_title_type != null && mCustomerList != null ){
                tv_title_type.setText("用户进程("+mCustomerList.size()+")");
            }
        }
    };


    class MyAdapter extends BaseAdapter {

        // 在ListView中多添加一种类型条目,条目总数有2种
        @Override
        public int getViewTypeCount() {
            return super.getViewTypeCount() + 1;
        }

        // 根据索引值决定展示哪种类型的条目
        @Override
        public int getItemViewType(int position) {
            if (position == 0 || position == mCustomerList.size() + 1){
                // 纯文本条目
                return 0;
            }else {
                // 图文条目
                return 1;
            }
        }

        @Override
        public int getCount() {
            return mCustomerList.size() + mSystemList.size() + 2;
        }

        @Override
        public ProcessInfo getItem(int position) {
            if (position == 0 || position == mCustomerList.size() + 1){
                // 纯文本条目
                return null;
            }else {
                // 图文条目
                if (position < mCustomerList.size() + 1){
                    // 用户应用
                    return mCustomerList.get(position - 1);
                }else {
                    // 系统应用
                    return mSystemList.get(position - mCustomerList.size() - 2);
                }
            }
            // return mAppInfoList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // 判断当前索引指向的条目类型状态码
            int itemViewType = getItemViewType(position);
            if (itemViewType == 0){
                // 纯文本条目
                ViewTitleHolder holder = null;
                if (convertView == null){
                    convertView = View.inflate(getApplicationContext(),R.layout.list_app_item_text,null);
                    holder = new ViewTitleHolder();
                    holder.tv_title_des = convertView.findViewById(R.id.tv_title_des);
                    convertView.setTag(holder);
                }else {
                    holder = (ViewTitleHolder) convertView.getTag();
                }
                if (position == 0){
                    holder.tv_title_des.setText("用户进程("+mCustomerList.size()+")");
                }else {
                    holder.tv_title_des.setText("系统进程("+mSystemList.size()+")");
                }
                return convertView;
            }else {
                // 图文条目
                ViewHolder holder = null;
                // 1.判断ConverView是否为空
                if (convertView == null){
                    convertView = View.inflate(getApplicationContext(),R.layout.list_process_item,null);
                    // 2.获取控件实例赋值给ViewHolder
                    holder = new ViewHolder();
                    holder.iv_icon_application = convertView.findViewById(R.id.iv_icon_application);
                    holder.tv_app_name = convertView.findViewById(R.id.tv_app_name);
                    holder.tv_memory = convertView.findViewById(R.id.tv_memory);
                    holder.cb_box = convertView.findViewById(R.id.cb_box);
                    // 3.将Holder放到ConverView上
                    convertView.setTag(holder);
                }else {
                    holder = (ViewHolder) convertView.getTag();
                }
                // 4.获取Holder中的控件实例,赋值
                holder.iv_icon_application.setBackground(getItem(position).getIcon());
                holder.tv_app_name.setText(getItem(position).getName());
                String strMemorySize = Formatter.formatFileSize(getApplicationContext(), getItem(position).getMemSize());
                holder.tv_memory.setText(strMemorySize);
                // 5.本进程无法被选中,所以先将CheckBox隐藏
                if ((getItem(position).getPackageName()).equals(getPackageName())){
                    holder.cb_box.setVisibility(View.GONE);
                }else {
                    holder.cb_box.setVisibility(View.VISIBLE);
                }
                holder.cb_box.setChecked(getItem(position).isCheck());
                // 6.返回现有条目填充上数据的View对象
                return convertView;
            }
        }
    }

    static class ViewHolder{
        ImageView iv_icon_application;
        TextView tv_app_name;
        TextView tv_memory;
        CheckBox cb_box;
    }

    static class ViewTitleHolder{
        TextView tv_title_des;
    }

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

        // 初始化UI
        initUI();

        // 初始化标题上的信息:进程总数,内存使用情况
        initTitleData();

        // 初始化ListView列表中的数据
        initListData();
    }

    /**
     * 初始化UI
     */
    private void initUI() {
        tv_process_count = findViewById(R.id.tv_process_count);
        tv_memory_info = findViewById(R.id.tv_memory_info);
        tv_title_type = findViewById(R.id.tv_title_type);
        lv_process_list = findViewById(R.id.lv_process_list);
        btn_all = findViewById(R.id.btn_all);
        btn_reverse = findViewById(R.id.btn_reverse);
        btn_clear = findViewById(R.id.btn_clear);
        btn_setting = findViewById(R.id.btn_setting);

        // 给ListView注册滚动事件
        lv_process_list.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                // 在滚动过程中调用方法
                if (mSystemList != null && mCustomerList != null){
                    if (firstVisibleItem >= mCustomerList.size() + 1){
                        // 滚动到了系统应用
                        tv_title_type.setText("系统进程("+mSystemList.size()+")");
                    }else {
                        // 滚动到了用户应用
                        tv_title_type.setText("用户进程("+mCustomerList.size()+")");
                    }
                }
            }
        });

        // 给ListView注册点击事件
        lv_process_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (position == 0 || position == mCustomerList.size() + 1){
                    // 纯文本条目
                    return;
                }else {
                    // 图文条目
                    if (position < mCustomerList.size() + 1){
                        // 用户应用
                        mProcessInfo = mCustomerList.get(position - 1);
                    }else {
                        // 系统应用
                        mProcessInfo = mSystemList.get(position - mCustomerList.size() - 2);
                    }
                    if (mProcessInfo != null){
                        if (!mProcessInfo.getPackageName().equals(getPackageName())){
                            // 选中条目指向的对象和本应用的包名不一致,才需要去取反状态和设置单选框状态
                            // 状态取反
                            mProcessInfo.setCheck(!mProcessInfo.isCheck());
                            // CheckBox显示状态取反
                            // 通过选中条目的view对象,findViewById找到此条目指向的cb_box,然后切换其状态
                            CheckBox cb_box = view.findViewById(R.id.cb_box);
                            cb_box.setChecked(mProcessInfo.isCheck());
                        }
                    }
                }
            }
        });

        btn_all.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        btn_reverse.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        btn_clear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        btn_setting.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
    }

    /**
     * 初始化标题上的信息:进程总数,内存使用情况
     */
    private void initTitleData() {
        // 获取进程总数
        mProcessCount = ProcessInfoDao.getProcessCount(this);
        tv_process_count.setText("进程总数:" + mProcessCount);
        // 获取可用内存大小
        long availSpace = ProcessInfoDao.getAvailSpace(this);
        String strAvailSpace = Formatter.formatFileSize(this, availSpace); // 格式化
        // 获取总内存大小
        long totalSpace = ProcessInfoDao.getTotalSpace(this);
        String strTotalSpace = Formatter.formatFileSize(this, totalSpace); // 格式化
        tv_memory_info.setText("剩余/总共" + strAvailSpace + "/" + strTotalSpace);
    }

    /**
     * 初始化列表中的数据
     */
    private void initListData() {
        getData();
    }

    /**
     * 获取数据的方法
     */
    private void getData(){
        new Thread(){
            @Override
            public void run() {
                // 2.准备填充ListView中数据适配器的数据
                mProcessInfoList = ProcessInfoDao.getProcessInfoList(getApplicationContext());
                mSystemList = new ArrayList<>();
                mCustomerList = new ArrayList<>();
                // 分割集合
                for (ProcessInfo processInfo : mProcessInfoList) {
                    if (processInfo.isSystem()){
                        // 系统进程
                        mSystemList.add(processInfo);
                    }else {
                        // 用户进程
                        mCustomerList.add(processInfo);
                    }
                }
                // 3.发送空消息进行数据绑定
                mHandler.sendEmptyMessage(0);
            }
        }.start();
    }
}

10.进程管理——全选 & 反选

上一节中我们完成了选择某个条目时CheckBox控件发生变化的效果,现在需要完成全选 & 反选整个条目的功能。

修改ProcessManagerActivity,完善之前注册的按钮点击事件,主要添加selectAll()和selectReverse()方法,并完善相应逻辑,代码如下:

package com.example.mobilesafe.activity;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.format.Formatter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.example.mobilesafe.R;
import com.example.mobilesafe.dao.ProcessInfoDao;
import com.example.mobilesafe.domain.ProcessInfo;

import java.util.ArrayList;
import java.util.List;

public class ProcessManagerActivity extends AppCompatActivity {

    private TextView tv_process_count;

    private TextView tv_memory_info;

    private TextView tv_title_type;

    private ListView lv_process_list;

    private Button btn_all;

    private Button btn_reverse;

    private Button btn_clear;

    private Button btn_setting;

    private int mProcessCount; // 进程总数

    private List<ProcessInfo> mProcessInfoList;

    private List<ProcessInfo> mSystemList;

    private List<ProcessInfo> mCustomerList;

    private MyAdapter mAdapter;

    private ProcessInfo mProcessInfo;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            mAdapter = new MyAdapter();
            lv_process_list.setAdapter(mAdapter);
            if (tv_title_type != null && mCustomerList != null ){
                tv_title_type.setText("用户进程("+mCustomerList.size()+")");
            }
        }
    };


    class MyAdapter extends BaseAdapter {

        // 在ListView中多添加一种类型条目,条目总数有2种
        @Override
        public int getViewTypeCount() {
            return super.getViewTypeCount() + 1;
        }

        // 根据索引值决定展示哪种类型的条目
        @Override
        public int getItemViewType(int position) {
            if (position == 0 || position == mCustomerList.size() + 1){
                // 纯文本条目
                return 0;
            }else {
                // 图文条目
                return 1;
            }
        }

        @Override
        public int getCount() {
            return mCustomerList.size() + mSystemList.size() + 2;
        }

        @Override
        public ProcessInfo getItem(int position) {
            if (position == 0 || position == mCustomerList.size() + 1){
                // 纯文本条目
                return null;
            }else {
                // 图文条目
                if (position < mCustomerList.size() + 1){
                    // 用户应用
                    return mCustomerList.get(position - 1);
                }else {
                    // 系统应用
                    return mSystemList.get(position - mCustomerList.size() - 2);
                }
            }
            // return mAppInfoList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // 判断当前索引指向的条目类型状态码
            int itemViewType = getItemViewType(position);
            if (itemViewType == 0){
                // 纯文本条目
                ViewTitleHolder holder = null;
                if (convertView == null){
                    convertView = View.inflate(getApplicationContext(),R.layout.list_app_item_text,null);
                    holder = new ViewTitleHolder();
                    holder.tv_title_des = convertView.findViewById(R.id.tv_title_des);
                    convertView.setTag(holder);
                }else {
                    holder = (ViewTitleHolder) convertView.getTag();
                }
                if (position == 0){
                    holder.tv_title_des.setText("用户进程("+mCustomerList.size()+")");
                }else {
                    holder.tv_title_des.setText("系统进程("+mSystemList.size()+")");
                }
                return convertView;
            }else {
                // 图文条目
                ViewHolder holder = null;
                // 1.判断ConverView是否为空
                if (convertView == null){
                    convertView = View.inflate(getApplicationContext(),R.layout.list_process_item,null);
                    // 2.获取控件实例赋值给ViewHolder
                    holder = new ViewHolder();
                    holder.iv_icon_application = convertView.findViewById(R.id.iv_icon_application);
                    holder.tv_app_name = convertView.findViewById(R.id.tv_app_name);
                    holder.tv_memory = convertView.findViewById(R.id.tv_memory);
                    holder.cb_box = convertView.findViewById(R.id.cb_box);
                    // 3.将Holder放到ConverView上
                    convertView.setTag(holder);
                }else {
                    holder = (ViewHolder) convertView.getTag();
                }
                // 4.获取Holder中的控件实例,赋值
                holder.iv_icon_application.setBackground(getItem(position).getIcon());
                holder.tv_app_name.setText(getItem(position).getName());
                String strMemorySize = Formatter.formatFileSize(getApplicationContext(), getItem(position).getMemSize());
                holder.tv_memory.setText(strMemorySize);
                // 5.本进程无法被选中,所以先将CheckBox隐藏
                if ((getItem(position).getPackageName()).equals(getPackageName())){
                    holder.cb_box.setVisibility(View.GONE);
                }else {
                    holder.cb_box.setVisibility(View.VISIBLE);
                }
                holder.cb_box.setChecked(getItem(position).isCheck());
                // 6.返回现有条目填充上数据的View对象
                return convertView;
            }
        }
    }

    static class ViewHolder{
        ImageView iv_icon_application;
        TextView tv_app_name;
        TextView tv_memory;
        CheckBox cb_box;
    }

    static class ViewTitleHolder{
        TextView tv_title_des;
    }

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

        // 初始化UI
        initUI();

        // 初始化标题上的信息:进程总数,内存使用情况
        initTitleData();

        // 初始化ListView列表中的数据
        initListData();
    }

    /**
     * 初始化UI
     */
    private void initUI() {
        tv_process_count = findViewById(R.id.tv_process_count);
        tv_memory_info = findViewById(R.id.tv_memory_info);
        tv_title_type = findViewById(R.id.tv_title_type);
        lv_process_list = findViewById(R.id.lv_process_list);
        btn_all = findViewById(R.id.btn_all);
        btn_reverse = findViewById(R.id.btn_reverse);
        btn_clear = findViewById(R.id.btn_clear);
        btn_setting = findViewById(R.id.btn_setting);

        // 给ListView注册滚动事件
        lv_process_list.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                // 在滚动过程中调用方法
                if (mSystemList != null && mCustomerList != null){
                    if (firstVisibleItem >= mCustomerList.size() + 1){
                        // 滚动到了系统应用
                        tv_title_type.setText("系统进程("+mSystemList.size()+")");
                    }else {
                        // 滚动到了用户应用
                        tv_title_type.setText("用户进程("+mCustomerList.size()+")");
                    }
                }
            }
        });

        // 给ListView注册点击事件
        lv_process_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (position == 0 || position == mCustomerList.size() + 1){
                    // 纯文本条目
                    return;
                }else {
                    // 图文条目
                    if (position < mCustomerList.size() + 1){
                        // 用户应用
                        mProcessInfo = mCustomerList.get(position - 1);
                    }else {
                        // 系统应用
                        mProcessInfo = mSystemList.get(position - mCustomerList.size() - 2);
                    }
                    if (mProcessInfo != null){
                        if (!mProcessInfo.getPackageName().equals(getPackageName())){
                            // 选中条目指向的对象和本应用的包名不一致,才需要去取反状态和设置单选框状态
                            // 状态取反
                            mProcessInfo.setCheck(!mProcessInfo.isCheck());
                            // CheckBox显示状态取反
                            // 通过选中条目的view对象,findViewById找到此条目指向的cb_box,然后切换其状态
                            CheckBox cb_box = view.findViewById(R.id.cb_box);
                            cb_box.setChecked(mProcessInfo.isCheck());
                        }
                    }
                }
            }
        });

        btn_all.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 全选
                selectAll();
            }
        });

        btn_reverse.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 反选
                selectReverse();
            }
        });

        btn_clear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        btn_setting.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
    }

    /**
     * “全选”按钮的功能
     */
    private void selectAll() {
        // 1.将所有集合中的对象上的isCheck字段设置为true代表全选(除了手机卫士自己)
        for (ProcessInfo processInfo : mCustomerList){
            if (processInfo.getPackageName().equals(getPackageName())){
                continue;
            }
            processInfo.setCheck(true);
        }
        for (ProcessInfo processInfo : mSystemList){
            processInfo.setCheck(true);
        }
        // 2.通知数据适配器刷新
        if (mAdapter != null){
            mAdapter.notifyDataSetChanged();
        }
    }

    /**
     * “反选”按钮的功能
     */
    private void selectReverse() {
        // 1.将所有集合中的对象上的isCheck字段设置为true代表全选(除了手机卫士自己)
        for (ProcessInfo processInfo : mCustomerList){
            if (processInfo.getPackageName().equals(getPackageName())){
                continue;
            }
            processInfo.setCheck(!processInfo.isCheck());
        }
        for (ProcessInfo processInfo : mSystemList){
            processInfo.setCheck(!processInfo.isCheck());
        }
        // 2.通知数据适配器刷新
        if (mAdapter != null){
            mAdapter.notifyDataSetChanged();
        }
    }

    /**
     * 初始化标题上的信息:进程总数,内存使用情况
     */
    private void initTitleData() {
        // 获取进程总数
        mProcessCount = ProcessInfoDao.getProcessCount(this);
        tv_process_count.setText("进程总数:" + mProcessCount);
        // 获取可用内存大小
        long availSpace = ProcessInfoDao.getAvailSpace(this);
        String strAvailSpace = Formatter.formatFileSize(this, availSpace); // 格式化
        // 获取总内存大小
        long totalSpace = ProcessInfoDao.getTotalSpace(this);
        String strTotalSpace = Formatter.formatFileSize(this, totalSpace); // 格式化
        tv_memory_info.setText("剩余/总共" + strAvailSpace + "/" + strTotalSpace);
    }

    /**
     * 初始化列表中的数据
     */
    private void initListData() {
        getData();
    }

    /**
     * 获取数据的方法
     */
    private void getData(){
        new Thread(){
            @Override
            public void run() {
                // 2.准备填充ListView中数据适配器的数据
                mProcessInfoList = ProcessInfoDao.getProcessInfoList(getApplicationContext());
                mSystemList = new ArrayList<>();
                mCustomerList = new ArrayList<>();
                // 分割集合
                for (ProcessInfo processInfo : mProcessInfoList) {
                    if (processInfo.isSystem()){
                        // 系统进程
                        mSystemList.add(processInfo);
                    }else {
                        // 用户进程
                        mCustomerList.add(processInfo);
                    }
                }
                // 3.发送空消息进行数据绑定
                mHandler.sendEmptyMessage(0);
            }
        }.start();
    }
}

11.进程管理——清理内存

上一节中我们完成了全选 & 反选整个条目的功能,现在需要完成一键清理内存的功能。

修改ProcessManagerActivity,为“清理内存”的按钮注册点击事件,完善相应逻辑,代码如下:

package com.example.mobilesafe.activity;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.format.Formatter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.example.mobilesafe.R;
import com.example.mobilesafe.dao.ProcessInfoDao;
import com.example.mobilesafe.domain.ProcessInfo;
import com.example.mobilesafe.utils.ToastUtil;

import java.util.ArrayList;
import java.util.List;

public class ProcessManagerActivity extends AppCompatActivity {

    private TextView tv_process_count;

    private TextView tv_memory_info;

    private TextView tv_title_type;

    private ListView lv_process_list;

    private Button btn_all;

    private Button btn_reverse;

    private Button btn_clear;

    private Button btn_setting;

    private int mProcessCount; // 进程总数

    private List<ProcessInfo> mProcessInfoList;

    private List<ProcessInfo> mSystemList;

    private List<ProcessInfo> mCustomerList;

    private MyAdapter mAdapter;

    private ProcessInfo mProcessInfo;

    private long mAvailSpace;

    private long mTotalSpace;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            mAdapter = new MyAdapter();
            lv_process_list.setAdapter(mAdapter);
            if (tv_title_type != null && mCustomerList != null ){
                tv_title_type.setText("用户进程("+mCustomerList.size()+")");
            }
        }
    };

    class MyAdapter extends BaseAdapter {

        // 在ListView中多添加一种类型条目,条目总数有2种
        @Override
        public int getViewTypeCount() {
            return super.getViewTypeCount() + 1;
        }

        // 根据索引值决定展示哪种类型的条目
        @Override
        public int getItemViewType(int position) {
            if (position == 0 || position == mCustomerList.size() + 1){
                // 纯文本条目
                return 0;
            }else {
                // 图文条目
                return 1;
            }
        }

        @Override
        public int getCount() {
            return mCustomerList.size() + mSystemList.size() + 2;
        }

        @Override
        public ProcessInfo getItem(int position) {
            if (position == 0 || position == mCustomerList.size() + 1){
                // 纯文本条目
                return null;
            }else {
                // 图文条目
                if (position < mCustomerList.size() + 1){
                    // 用户应用
                    return mCustomerList.get(position - 1);
                }else {
                    // 系统应用
                    return mSystemList.get(position - mCustomerList.size() - 2);
                }
            }
            // return mAppInfoList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // 判断当前索引指向的条目类型状态码
            int itemViewType = getItemViewType(position);
            if (itemViewType == 0){
                // 纯文本条目
                ViewTitleHolder holder = null;
                if (convertView == null){
                    convertView = View.inflate(getApplicationContext(),R.layout.list_app_item_text,null);
                    holder = new ViewTitleHolder();
                    holder.tv_title_des = convertView.findViewById(R.id.tv_title_des);
                    convertView.setTag(holder);
                }else {
                    holder = (ViewTitleHolder) convertView.getTag();
                }
                if (position == 0){
                    holder.tv_title_des.setText("用户进程("+mCustomerList.size()+")");
                }else {
                    holder.tv_title_des.setText("系统进程("+mSystemList.size()+")");
                }
                return convertView;
            }else {
                // 图文条目
                ViewHolder holder = null;
                // 1.判断ConverView是否为空
                if (convertView == null){
                    convertView = View.inflate(getApplicationContext(),R.layout.list_process_item,null);
                    // 2.获取控件实例赋值给ViewHolder
                    holder = new ViewHolder();
                    holder.iv_icon_application = convertView.findViewById(R.id.iv_icon_application);
                    holder.tv_app_name = convertView.findViewById(R.id.tv_app_name);
                    holder.tv_memory = convertView.findViewById(R.id.tv_memory);
                    holder.cb_box = convertView.findViewById(R.id.cb_box);
                    // 3.将Holder放到ConverView上
                    convertView.setTag(holder);
                }else {
                    holder = (ViewHolder) convertView.getTag();
                }
                // 4.获取Holder中的控件实例,赋值
                holder.iv_icon_application.setBackground(getItem(position).getIcon());
                holder.tv_app_name.setText(getItem(position).getName());
                String strMemorySize = Formatter.formatFileSize(getApplicationContext(), getItem(position).getMemSize());
                holder.tv_memory.setText(strMemorySize);
                // 5.本进程无法被选中,所以先将CheckBox隐藏
                if ((getItem(position).getPackageName()).equals(getPackageName())){
                    holder.cb_box.setVisibility(View.GONE);
                }else {
                    holder.cb_box.setVisibility(View.VISIBLE);
                }
                holder.cb_box.setChecked(getItem(position).isCheck());
                // 6.返回现有条目填充上数据的View对象
                return convertView;
            }
        }
    }

    static class ViewHolder{
        ImageView iv_icon_application;
        TextView tv_app_name;
        TextView tv_memory;
        CheckBox cb_box;
    }

    static class ViewTitleHolder{
        TextView tv_title_des;
    }

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

        // 初始化UI
        initUI();

        // 初始化标题上的信息:进程总数,内存使用情况
        initTitleData();

        // 初始化ListView列表中的数据
        initListData();
    }

    /**
     * 初始化UI
     */
    private void initUI() {
        tv_process_count = findViewById(R.id.tv_process_count);
        tv_memory_info = findViewById(R.id.tv_memory_info);
        tv_title_type = findViewById(R.id.tv_title_type);
        lv_process_list = findViewById(R.id.lv_process_list);
        btn_all = findViewById(R.id.btn_all);
        btn_reverse = findViewById(R.id.btn_reverse);
        btn_clear = findViewById(R.id.btn_clear);
        btn_setting = findViewById(R.id.btn_setting);

        // 给ListView注册滚动事件
        lv_process_list.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                // 在滚动过程中调用方法
                if (mSystemList != null && mCustomerList != null){
                    if (firstVisibleItem >= mCustomerList.size() + 1){
                        // 滚动到了系统应用
                        tv_title_type.setText("系统进程("+mSystemList.size()+")");
                    }else {
                        // 滚动到了用户应用
                        tv_title_type.setText("用户进程("+mCustomerList.size()+")");
                    }
                }
            }
        });

        // 给ListView注册点击事件
        lv_process_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (position == 0 || position == mCustomerList.size() + 1){
                    // 纯文本条目
                    return;
                }else {
                    // 图文条目
                    if (position < mCustomerList.size() + 1){
                        // 用户应用
                        mProcessInfo = mCustomerList.get(position - 1);
                    }else {
                        // 系统应用
                        mProcessInfo = mSystemList.get(position - mCustomerList.size() - 2);
                    }
                    if (mProcessInfo != null){
                        if (!mProcessInfo.getPackageName().equals(getPackageName())){
                            // 选中条目指向的对象和本应用的包名不一致,才需要去取反状态和设置单选框状态
                            // 状态取反
                            mProcessInfo.setCheck(!mProcessInfo.isCheck());
                            // CheckBox显示状态取反
                            // 通过选中条目的view对象,findViewById找到此条目指向的cb_box,然后切换其状态
                            CheckBox cb_box = view.findViewById(R.id.cb_box);
                            cb_box.setChecked(mProcessInfo.isCheck());
                        }
                    }
                }
            }
        });

        btn_all.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 全选
                selectAll();
            }
        });

        btn_reverse.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 反选
                selectReverse();
            }
        });

        btn_clear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                clearAll();
            }
        });

        btn_setting.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
    }

    /**
     * "一键清理"按钮的功能
     */
    private void clearAll() {
        // 0.创建一个记录释放了多大空间的变量
        long totalReleaseSpace = 0;
        // 1.创建一个记录需要杀死的进程的集合
        List<ProcessInfo> killProcessList = new ArrayList<>();
        // 2.获取选中进程
        for (ProcessInfo processInfo : mCustomerList){
            if (processInfo.getPackageName().equals(getPackageName())){
                continue;
            }
            if (processInfo.isCheck()){
                // 3.记录被选中的用户进程(即需要杀死)
                killProcessList.add(processInfo);
            }
        }
        for (ProcessInfo processInfo : mSystemList){
            if (processInfo.isCheck()){
                // 4.记录被选中的系统进程(即需要杀死)
                killProcessList.add(processInfo);
            }
        }
        // 5.循环遍历killProcessList,然后移除mCustomerList和mSystemList中的对象
        for (ProcessInfo processInfo : killProcessList) {
            // 6.判断当前进程再哪个集合中,从所在集合中移除
            if (mCustomerList.contains(processInfo)){
                mCustomerList.remove(processInfo);
            }
            if (mSystemList.contains(processInfo)){
                mSystemList.remove(processInfo);
            }
            // 7.杀死记录在killProcessList中的进程
            ProcessInfoDao.killProcess(this,processInfo);
            // 8.记录释放控件的总大小
            totalReleaseSpace += processInfo.getMemSize();
        }
        // 9.在集合改变后,需要通知数据适配器刷新
        if (mAdapter != null){
            mAdapter.notifyDataSetChanged();
        }
        // 10.更新进程总数
        mProcessCount -= killProcessList.size();
        // 11.更新可用剩余空间(释放空间 + 原有剩余空间 = 当前剩余空间)
        mAvailSpace += totalReleaseSpace;
        // 12.根据进程总数和剩余空间大小更新控件
        tv_process_count.setText("进程总数:"+mProcessCount);
        tv_memory_info.setText("剩余/总共" + Formatter.formatFileSize(this,mAvailSpace) + "/" + Formatter.formatFileSize(this,mTotalSpace));
        // 13.通过Toast告知用户,释放了多少空间,杀死多少进程(也可以使用C语言的占位符)
        ToastUtil.show(getApplicationContext(),"杀死了" + killProcessList.size() + "个进程,释放了" + Formatter.formatFileSize(this,totalReleaseSpace));
    }

    /**
     * “全选”按钮的功能
     */
    private void selectAll() {
        // 1.将所有集合中的对象上的isCheck字段设置为true代表全选(除了手机卫士自己)
        for (ProcessInfo processInfo : mCustomerList){
            if (processInfo.getPackageName().equals(getPackageName())){
                continue;
            }
            processInfo.setCheck(true);
        }
        for (ProcessInfo processInfo : mSystemList){
            processInfo.setCheck(true);
        }
        // 2.通知数据适配器刷新
        if (mAdapter != null){
            mAdapter.notifyDataSetChanged();
        }
    }

    /**
     * “反选”按钮的功能
     */
    private void selectReverse() {
        // 1.将所有集合中的对象上的isCheck字段设置为true代表全选(除了手机卫士自己)
        for (ProcessInfo processInfo : mCustomerList){
            if (processInfo.getPackageName().equals(getPackageName())){
                continue;
            }
            processInfo.setCheck(!processInfo.isCheck());
        }
        for (ProcessInfo processInfo : mSystemList){
            processInfo.setCheck(!processInfo.isCheck());
        }
        // 2.通知数据适配器刷新
        if (mAdapter != null){
            mAdapter.notifyDataSetChanged();
        }
    }

    /**
     * 初始化标题上的信息:进程总数,内存使用情况
     */
    private void initTitleData() {
        // 获取进程总数
        mProcessCount = ProcessInfoDao.getProcessCount(this);
        tv_process_count.setText("进程总数:" + mProcessCount);
        // 获取可用内存大小
        mAvailSpace = ProcessInfoDao.getAvailSpace(this);
        String strAvailSpace = Formatter.formatFileSize(this, mAvailSpace); // 格式化
        // 获取总内存大小
        mTotalSpace = ProcessInfoDao.getTotalSpace(this);
        String strTotalSpace = Formatter.formatFileSize(this, mTotalSpace); // 格式化
        tv_memory_info.setText("剩余/总共" + strAvailSpace + "/" + strTotalSpace);
    }

    /**
     * 初始化列表中的数据
     */
    private void initListData() {
        getData();
    }

    /**
     * 获取数据的方法
     */
    private void getData(){
        new Thread(){
            @Override
            public void run() {
                // 2.准备填充ListView中数据适配器的数据
                mProcessInfoList = ProcessInfoDao.getProcessInfoList(getApplicationContext());
                mSystemList = new ArrayList<>();
                mCustomerList = new ArrayList<>();
                // 分割集合
                for (ProcessInfo processInfo : mProcessInfoList) {
                    if (processInfo.isSystem()){
                        // 系统进程
                        mSystemList.add(processInfo);
                    }else {
                        // 用户进程
                        mCustomerList.add(processInfo);
                    }
                }
                // 3.发送空消息进行数据绑定
                mHandler.sendEmptyMessage(0);
            }
        }.start();
    }
}

为了方便进程的删除,修改ProcessInfoDao,添加killProcess(),作为杀死进程的方法,代码如下:

/**
     * 杀死进程的方法
     * @param context 上下文环境
     * @param processInfo 传递进来的进程信息
     */
    public static void killProcess(Context context,ProcessInfo processInfo) {
        // 1.获取ActivityManager对象
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        // 2.杀死指定包名进程(需要声明权限)
        activityManager.killBackgroundProcesses(processInfo.getPackageName());
    }

注意,由于涉及到后台权限的删除,所以需要在清单文件中声明相应权限,代码如下:

<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赈川

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值