现在的位置: 首页 > 综合 > 正文

第六天:进程管理

2018年05月17日 ⁄ 综合 ⁄ 共 14603字 ⁄ 字号 评论关闭
为什么需要进程管理,因为它不自动去关闭后台进程。它是一个多任务的,
你退出后,留下一个空进程,不过这些做,在你再次打开的时间就比较快了
这些多个应用切换的时间就比较快了。

activity的Tittle管理(customertitle)。
setText()不以设置为int类型,必须转化成字符串,因为
这是一个重载的方法,如果你传过去一个int类型,它会认为
你传过去的是一个资源的引用,所以你要把它转化成字符串
它会用另外一个重载方法去处理它。

ActivityManger太强大了,能得到任务栈,进程,内存等。。

获取总内存信息是没有API可以得到的。我们已经得到的剩余内存,可以通过加上已用的算出总内存。

安卓中重要的类:Build

自定义activityTitle:
super.onCreate(savedInstanceState);
//1.隐藏掉系统的title 然后自己的layout的布局 上面做出来一个类似title效果
//2.请求系统的服务,让系统的title 使用我们定义的样式
boolean flag = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);

//请求系统使用自定义的title, 这一句代码一定要写到setcontentView之前
setContentView(R.layout.task_manager);

if (flag) {
	getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.task_manager_title);
}

tv_task_count = (TextView) this.findViewById(R.id.tv_task_count);
tv_avail_memory = (TextView) this.findViewById(R.id.tv_avail_memory);

思考所有布局的根本方法,先不要想什么细节,而是直接把大块给划分好。先把块一分好,确定大块的布局即可。
不会说谁会覆盖谁,如果是这样,你就想的太多了。因为可以设置它。

如果ListView控件过多,定义一个静态类,专门去存储它。

对ListView进行分组。复杂的ListView再复杂的就是在getView里面做的复杂的业务逻辑。

package cn.itcast.mobilesafe.ui;

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

import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.MemoryInfo;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import cn.itcast.mobilesafe.R;
import cn.itcast.mobilesafe.domain.TaskInfo;
import cn.itcast.mobilesafe.engine.TaskInfoProvider;
import cn.itcast.mobilesafe.util.TextFormater;

public class TaskManagerActivity extends Activity{
	private TextView tv_task_count;
	private TextView tv_avail_memory;
	private ActivityManager am;//它很强大,可以得到任务栈,内存,进程等。
	private List<RunningAppProcessInfo> runingappinfos;//所以正在运行的进程信息
	
	private ListView lv_task_manager;//用来装内容 的
	private LinearLayout ll_task_manager_loading;//模态图标
	private TaskInfoProvider taskInfoprovider;//
	
	private List<TaskInfo> listtaskinfos;//所有任务信息列表 
	private List<TaskInfo> usertaskinfos;//用户信息列表
	private List<TaskInfo> systemtaskinfos;//系统信息列表
	
	private TaskInfoAdapter adapter;
	
	private long totalused = 0;// 所有程序占用的内存信息 kb
	
	private Handler handler = new Handler(){
		@Override
		public void handleMessage(android.os.Message msg) {
			ll_task_manager_loading.setVisibility(View.INVISIBLE);
			long totalmemoryinfo = totalused*1024 + getAvailMemoryInfo();//占用的内存加上可用的内存等于总内存
			String strtotalmemory = TextFormater.getDataSize(totalmemoryinfo);
			String text = tv_avail_memory.getText().toString() + "总内存:"+ strtotalmemory;
			tv_avail_memory.setText(text);
			adapter = new TaskInfoAdapter();
			lv_task_manager.setAdapter(adapter);
			
		};
		
	};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		
		super.onCreate(savedInstanceState);
		//1.隐藏掉系统的title 然后自己的layout的布局 上面做出来一个类似title效果
        //2.请求系统的服务,让系统的title 使用我们定义的样式
		boolean flag = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
		
		//请求系统使用自定义的title, 这一句代码一定要写到setcontentView之前
		setContentView(R.layout.task_manager);
		
		if (flag) {
			getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.task_manager_title);
		}
		
		//获取am进程服务
		am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
		
		tv_task_count = (TextView) this.findViewById(R.id.tv_task_count);
		tv_avail_memory = (TextView) this.findViewById(R.id.tv_avail_memory);
		lv_task_manager = (ListView) this.findViewById(R.id.lv_task_manager);
		ll_task_manager_loading = (LinearLayout) this.findViewById(R.id.ll_task_manager_loading);
		taskInfoprovider = new TaskInfoProvider(this);
		
		
		//填充listview的数据
		fillData();
		
	}
	//填充listview的数据
	private void fillData() {
		//设置title的数据
		setTitleData();
		
		//先让其处于可见状态 
		ll_task_manager_loading.setVisibility(View.VISIBLE);
		//起一个线程,找到所有的任务信息
		new Thread(){
			@Override
			public void run() {
				listtaskinfos = taskInfoprovider.getAllTasks(runingappinfos);
				
				totalused = 0; // 所有程序占用的内存信息 kb
				for(TaskInfo taskInfo : listtaskinfos){
					totalused += taskInfo.getMemorysize();
				}
				// 通知界面更新数据
				handler.sendEmptyMessage(0);
			};
		}.start();
		
	}

	/**
	 * 设置title的数据
	 */
	private void setTitleData() {
		tv_task_count.setText("进程数目: " + getProcessCount());
		tv_avail_memory.setText("剩余内存"
				+ TextFormater.getDataSize(getAvailMemoryInfo()));
	}
	/**
	 * 获取当前正在运行的进程的数目
	 * @return
	 */
	private int getProcessCount(){
		runingappinfos = am.getRunningAppProcesses();
		return runingappinfos.size();
	}
	/**
	 * 获取当前系统的剩余的可用内存信息 byte long
	 */
	private long getAvailMemoryInfo(){
		MemoryInfo outInfo = new ActivityManager.MemoryInfo();
		am.getMemoryInfo(outInfo);
		return outInfo.availMem;
	}
	/**
	 * 
	 * @author chen
	 * 无论 多么复杂的业务逻辑都是通过在getView里面复杂的业务判断出来的。
	 */
	private class TaskInfoAdapter extends BaseAdapter{
		/**
		 * 在构造方法里面完成了用户列表和系统程序列表的区分
		 */
		public TaskInfoAdapter() {
			usertaskinfos = new ArrayList<TaskInfo>();
			systemtaskinfos = new ArrayList<TaskInfo>();
			
			for(TaskInfo taskInfo : listtaskinfos){
				if (taskInfo.isSystemapp()) {
					systemtaskinfos.add(taskInfo);
				}else {
					usertaskinfos.add(taskInfo);
				}
			}
		}
		
		
		
		@Override
		public int getCount() {
			return listtaskinfos.size() + 2;//因为显示出来的
		}

		@Override
		public Object getItem(int position) {
			if (position == 0) {
				return 0;
			}else if (position <= usertaskinfos.size()) {
				return usertaskinfos.get(position - 1);
			}else if (position == usertaskinfos.size()+1) {
				return position;
			}else if (position <= listtaskinfos.size()+2) {
				return systemtaskinfos.get(position-usertaskinfos.size() -2);
			}else {
				return position;
			}
		}

		@Override
		public long getItemId(int position) {
			if (position == 0) {
				return -1;//这只是一个标识,标识这里面显示的TextView,
			}else if (position <= usertaskinfos.size()) {
				return position - 1;
			}else if (position == usertaskinfos.size()+1) {
				return -1;
			}else if (position <= listtaskinfos.size()+2) {
				return position-usertaskinfos.size() -2;
			}else {
				return -1;
			}
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			// 把这些条目信息 做一下分类 系统进程和用户进程区分出来
			if (position == 0) {
				TextView tv_userapp = new TextView(TaskManagerActivity.this);
				tv_userapp.setTextSize(22);
				tv_userapp.setText("用户进程 "+usertaskinfos.size()+"个");
				return tv_userapp;
			}else if (position <= usertaskinfos.size()) {
				int currentpositon = position - 1;
				TaskInfo taskInfo = usertaskinfos.get(currentpositon);
				View view = View.inflate(TaskManagerActivity.this, R.layout.task_manager_item, null);
				
				ViewHolder holder = new ViewHolder();
				holder.iv = (ImageView) view.findViewById(R.id.iv_app_icon);
				holder.tv_name = (TextView) view.findViewById(R.id.tv_app_name);
				holder.tv_memory_size = (TextView) view
						.findViewById(R.id.tv_app_memory_size);
				holder.cb_task_checked = (CheckBox) view
						.findViewById(R.id.cb_task_checked);
				String packname = taskInfo.getPackname();
				System.out.println("包名:"+packname);
				System.out.println("appname " + taskInfo.getAppname());
				//如果是以下三个程序 是不可以被清理的
				if ("360safe".equals(taskInfo.getAppname())) {
					holder.cb_task_checked.setVisibility(View.INVISIBLE);

				} else {
					holder.cb_task_checked.setVisibility(View.VISIBLE);
				}
				holder.iv.setImageDrawable(taskInfo.getAppicon());
				holder.tv_name.setText(taskInfo.getAppname());
				holder.tv_memory_size.setText("内存占用: "
						+ TextFormater.getKBDataSize(taskInfo.getMemorysize()));
				holder.cb_task_checked.setChecked(taskInfo.isIschecked());
				return view;
			}else if (position == usertaskinfos.size()+1) {
				TextView tv_systemapp = new TextView(TaskManagerActivity.this);
				tv_systemapp.setText("系统进程 " + systemtaskinfos.size() + "个");
				tv_systemapp.setTextSize(22);
				return tv_systemapp;
			}else if (position <= listtaskinfos.size() + 2) {
				int systemposition = position - usertaskinfos.size() - 2;
				TaskInfo taskInfo = systemtaskinfos.get(systemposition);
				View view = View.inflate(TaskManagerActivity.this, R.layout.task_manager_item, null);
				ViewHolder holder = new ViewHolder();
				holder.iv = (ImageView) view.findViewById(R.id.iv_app_icon);
				holder.tv_name = (TextView) view.findViewById(R.id.tv_app_name);
				holder.tv_memory_size = (TextView) view
						.findViewById(R.id.tv_app_memory_size);
				holder.cb_task_checked = (CheckBox) view
						.findViewById(R.id.cb_task_checked);
				String packname = taskInfo.getPackname();
				//如果是以下三个程序 是不可以被清理的
				if ("cn.itcast.mobilesafe".equals(packname)
						|| "system".equals(packname)
						|| "android.process.media".equals(packname)) {
					holder.cb_task_checked.setVisibility(View.INVISIBLE);

				} else {
					holder.cb_task_checked.setVisibility(View.VISIBLE);
				}
				holder.iv.setImageDrawable(taskInfo.getAppicon());
				holder.tv_name.setText(taskInfo.getAppname());
				holder.tv_memory_size.setText("内存占用: "
						+ TextFormater.getKBDataSize(taskInfo.getMemorysize()));
				holder.cb_task_checked.setChecked(taskInfo.isIschecked());
				return view;
			}else {
				// 肯定不会执行
				return null;
			}
		}
		
	}
	/**
	 * @author chen
	 * 用于ListView优化。
	 */
	static class ViewHolder {
		public ImageView iv;
		public TextView tv_name;
		public TextView tv_memory_size;
		public CheckBox cb_task_checked;
	}
}


CheckBox的二个属性应该都写成false,交给程序员来控制。
android:focusable="false"
android:clickable="false"

杀死进程的方法。

自定义Toast.
/**
 *自定义Toast,皆因一切有setView(View view)方法
 * @author chen
 */
public class MyToast {
	public static void showToast(Context context,int iconid,String text){
		View view = View.inflate(context, R.layout.my_toast, null);
		TextView tv = (TextView) view.findViewById(R.id.tv_my_toast);
		ImageView iv = (ImageView) view.findViewById(R.id.iv_my_toast);
		iv.setImageResource(iconid);
		tv.setText(text);
		Toast toast = new Toast(context);
		toast.setDuration(0);
		toast.setView(view);
		toast.show();
	}
}

在setting里面有一个应用程序界面。
里面有所有应用程序的详细信息。

有一些类谷歌给屏蔽了,不过我们可以在运行时得到它,就是用反射。
 
悬浮对话框的形式显示主题。而且还要无标题,所以我们必须要自定义主题。

layout_weight.权重
当下最为流行的0px设置法,一个极为重要的布局。
所有控件默认权重都是0,所以你相应设置就行了。
	
serializable--序列化到磁盘上
parcalable--序列化到内存上,这个效率高一些。
不过这两种方法比较麻烦。
其实安卓中的每个东西都有上下文,四大组件都是运行在
application上下文中。所以我们创建整个应用程序的上下文。

注意,有两种上下文,你可以把数据存储到activity上下中,
也可以存储到application上下文中。

非常重要:
一、自定义activity
二、layout_weight的使用
三、全局上下文的使用

 <!-- 应用详细信息界面  这个activity是一个悬浮对话框 -->
 我们知道有对话框这种activty的主题android:theme="@android:style/Theme.Dialog",
 但是我们需要把它的对话框的连title都没有,所以我们还是要自定义。
<!-- 自定义悬浮的acitvity对话框,并且无标题 -->
<style name="activity_float_no_title" parent="@android:style/Theme.Dialog">
	<item name="android:windowNoTitle">true</item>
</style>

两种上下文就相当于WEB中的intent上下文相当于Session,
全局的application上下文与WEB中的全局上下文也是一致的。
在安卓中的,所有的组件都运行在application上下文中。所以
你如果把信息存储到application中,那么所有组件都可以去存 ,取。

import cn.itcast.mobilesafe.domain.TaskInfo;
import android.app.Application;

public class MyApplication extends Application{
	
	public TaskInfo taskInfo;

}

再配置一把就对了:
<application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" android:name="MyApplication">
</application>
	
lv_task_manager.setOnItemLongClickListener(new OnItemLongClickListener() {
		@Override
		public boolean onItemLongClick(AdapterView<?> parent, View view,
				int position, long id) {
			Intent intent = new Intent(TaskManagerActivity.this,AppDetailActivity.class);
			//得到全局上下文对象
			MyApplication myApp = (MyApplication) getApplication();
			Object obj = lv_task_manager.getItemAtPosition(position);
			//为什么要判断,因为它有两个表示 ,用户和系统的条目,如果是这两个条目就不是进程信息对象了。
			if (obj instanceof TaskInfo) {
				TaskInfo taskInfo = (TaskInfo) obj;
				//把数据存储到里面全局上下文里面
				myApp.taskInfo = taskInfo;
				startActivity(intent);
			}
			return false;
		}
	});
	
//获取全局上下文对象 
MyApplication myApplication = (MyApplication) getApplication();
TaskInfo taskInfo = myApplication.taskInfo;
String packName = taskInfo.getPackname();
tv_app_detail_packname.setText(packName);
tv_app_detail_name.setText(taskInfo.getAppname());
//利用反射获取权限,因为安卓没有提供这个API,但是我们知道它一定要手机中,所以我们在运行时间获取,利用反射。
 try {
		Class clazz = getClass().getClassLoader().loadClass("android.widget.AppSecurityPermissions");
	
		Constructor constructor = clazz.getConstructor(new Class[]{Context.class,String.class});
		
		Object object = constructor.newInstance(new Object[]{this,packName});
		
		Method method = clazz.getDeclaredMethod("getPermissionsView", new Class[]{});

		View view =	(View) method.invoke(object, new Object[]{});
		
		sv_app_detail.addView(view);
	
	} catch (Exception e) {
		e.printStackTrace();
	}
//完结后我们把全局上下文的内容清空,提高效率。
myApplication.taskInfo = null;	

操 ,我不得不说,这跟WEB的设计思路几乎一模一样。
session---Intent上下文
application --- application全局上下文。
它只是一个东西在程序中的作用域问题。

又有一个大问题,我们如果想要在返回上一个页面时间刷新这个页面,如果做,
进程设置里面,我们做了显示全部进程,返回时间应该重新刷新这个界面。
也就是说从上个页面返回到这个页面的时间如何让这个页面进行刷新,如果在WEB
中,我们可以在返回按钮上写一个action,或者在页面加载完毕时间进行ajax请求。
但是在安卓中,没有这个东西,有startActivityForResult(intent, 1);
表示当你再返回的时间如果你想执行什么操作,有相应的回调方法可任你调用。

我必须要记录下来:(把activity之间的请求看作WEB之间的页面请求和跳转就会简单很多)
/**
	 * 进入程序设置界面
	 * @param view
	 */
	public void appSetting(View view){
		Intent intent = new Intent(TaskManagerActivity.this,TaskSettingActivity.class);
//		startActivity(intent);
		startActivityForResult(intent, 1);//这相当于给另外一个页面发起请求。
	}
	
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	super.onActivityResult(requestCode, resultCode, data);
	if (requestCode == 1 && resultCode == 200) {
		fillData();//重新刷新页面
	}
}

//另外一个页面响应这种请求(类似于HTTP请求,返回相应的码)
setResult(200);//返回值是200。相当于对一个页面请求。在那边的回调方法里面可通过这个判断。对不同的页面,进行不同的处理,太好了。


在用户锁屏的时间清理进程。


桌面小控件的开发。
它继承了广播接收者,所以它也是四大组件之一,应该在配置文件里面配置。
看帮助文档。


如果你看到哪个布局好,不用自己想怎么写,直接抄别人怎么写,反编译别人的源码。

反编译的话,它会把id前面的加号给去了。所以自己要加上。

其实,你首先要明白,这个widget是显示在别人的进程里面的,就现在的
安卓系统来说,有几十种桌面的应用,不尽相同。


Widgets主要参看文档。
First, declare the AppWidgetProvider class in your application's AndroidManifest.xml file. For example:
<receiver android:name="ExampleAppWidgetProvider" >
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data android:name="android.appwidget.provider"
               android:resource="@xml/example_appwidget_info" />
</receiver>

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="294dp"
    android:minHeight="72dp"
    android:updatePeriodMillis="1800000"
    android:initialLayout="@layout/main"
>
</appwidget-provider>


/**
 * 根据配置文件 每隔固定的时间 更新一下界面 
 * 最小值 半个小时 1800000毫秒
 * onRecevie - > onUpdate
 * 
 * 
 * 注意 widget这个组件不是在我们的应用程序里面
 * 显示在桌面的应用程序 
 * 不同的桌面 他们的widget的创建和销毁对应的 回调的事件可能会有不同
 * android luncher / htc sence / 米ui / 360桌面/awt /qq桌面/....
 * 
 *
 */
public class MyWidget extends AppWidgetProvider {

	@Override
	public void onReceive(Context context, Intent intent) {
		super.onReceive(context, intent);
		System.out.println("onReceive");
	}

	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
			int[] appWidgetIds) {
		System.out.println("onUpdate");
		super.onUpdate(context, appWidgetManager, appWidgetIds);
	}

	@Override
	public void onDeleted(Context context, int[] appWidgetIds) {
		System.out.println("onDeleted");
		super.onDeleted(context, appWidgetIds);
		//当某一个widget被删除的时候 会执行ondelete方法
	}

	@Override
	public void onEnabled(Context context) {
		System.out.println("onEnabled");
		
		// widget第一次创建的时候 执行的方法 
		//可以做 初始化widget数据的操作,开启以后后台 
		super.onEnabled(context);
	}

	@Override
	public void onDisabled(Context context) {
		super.onDisabled(context);
		System.out.println("onDisabled");
		// 当所有的widget都被删除的时候 执行 ondisable();
		// 停止我们开启的服务
		// 删除垃圾文件 临时文件
	}

}

虽然说onupdate 和 onreceiver这两个方法在不同的
平台上略有不同,不过相同的是onEnabled会在第一次
创建的时间执行,它只执行一次,以后只会执行onupdate
和onreceiver方法,当这个widget删除的时间才执行ondeled
方法,当所有桌面小控件都删除的时间才执行ondisabled.
方法,当所有桌面小控件都删除的时间才执行

public class ProcessWidget extends AppWidgetProvider  extends BroadcastReceiver{};
所以它本质上是一个广播接收者

做这个东西,记清楚一件事,就是它永远是在这里面去调用后台的服务的,这是最基本的思路,
因为它所有的各种东西是在生命周期里面调用的.这是一条主线.
/**
 * 它在不同的生命周期里面只需要调用不同的方法即可。
 * @author chen
 */
public class ProcessWidget extends AppWidgetProvider {
	 Intent intent ;
	
	@Override
	public void onDeleted(Context context, int[] appWidgetIds) {
		super.onDeleted(context, appWidgetIds);
		intent = new Intent(context,UpdateWidgetService.class);
		context.stopService(intent);
	}
	
	
	@Override
	public void onEnabled(Context context) {
		super.onEnabled(context);
		intent = new Intent(context,UpdateWidgetService.class);
		context.startService(intent);
	}
}

	
	
	
	
	
	
	
	
	
	

抱歉!评论已关闭.