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

第五天:程序锁和进程管理

2018年05月17日 ⁄ 综合 ⁄ 共 6019字 ⁄ 字号 评论关闭

/**************************************************************************/
分享还是很重要的,不过主要是系统完成的,你有新浪,QQ等它会自动找出来让其分享,
让用户选择。

想要实现异步刷新那个listView,第一,把新的值赋值给适配器,第二,适配器调用notify......

如何保存页面在加载时间,用户点击界面不会出错,因为这个时间数据还没有过来,用户一直在
点击的话,很可能报空针异常,现在我们引入一个变量去判断,极其好的方法,是非常通用的方法。

经测试果断分享可以分享给微博等。(分享源码)
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "分享");
shareIntent.putExtra(Intent.EXTRA_TEXT,"推荐你使用一个程序" + item.getAppName());
startActivity(shareIntent);

上面说过了,最致使的一点,当一个数据在加载的过程中,有那个ProgressBar在加载,你乱点一气,
触发了一些事件,而这些事件里面的数据还没有加载过来,那么马上会报错,这就模态要面临的一个大问题。


/**在适配器里面的方法。
 * 这个方法十分 重要,你想要动态更改它的值 ,并且不刷新 ,那么你就要通知适配器,你的最新数据是什么,
 * 然后再用adapter.notifyDataSetChanged();用异步刷新 。
 * @param appInfos
 */
public void setAppInfos(List<AppInfo> appInfos){
	this.list = appInfos;
}

activity中的应用(异步刷新):
adapter.setAppInfos(userAppInfos);
adapter.notifyDataSetChanged();

这个应用程序管理器里面包含的一些思想十分重要。
第一、listView优化:
//如果你不做成静态的,每次它都会栈内存中new出一个新引用 。 静态这个东西是我的弱点 。
private static ImageView iv;
private static TextView tv;

/**
 * View convertView (转化view对象 ,历史view对象的缓存) convertview 就是拖动的时候被回收掉的view对象
 * 每个条目每次显示的时间都会调用这个方法,所以每次都会生成不同的convertView,当某个已经生成的条目再次调用它的时间如果
 * 发现这个convertView是存在的,那么肯定是与之对应的那个,所以用缓存中的convertView即可。
 */
@Override
public View getView(int position, View convertView, ViewGroup parent) {
	AppInfo  appInfo = new AppInfo();
	appInfo = list.get(position);
	View view ;
	//如果发现当前条目的convertView为空,我们可以判定,这个条目一定还没有显示过
	if (convertView == null) {
		Log.i(TAG,"通过资源文件 创建view对象");
		//这个是通过反射等生成的非常消耗内存,每个条目调用 一次就行了。
		view = View.inflate(context, R.layout.app_item, null);
	}else {
		Log.i(TAG,"使用历史缓存view对象");
		view = convertView;
	}
	iv = (ImageView) view.findViewById(R.id.iv_app_icon);
	tv = (TextView) view.findViewById(R.id.tv_app_name);
	iv.setImageDrawable(appInfo.getIcon());
	tv.setText(appInfo.getAppName());
	return view;
}
第二、设置一个变量,在加载数据的时间所有的事件都不可点击,加载完毕以后才可以点击(否则肯定空针异常),肯定是结合了消息机制来做的。
第三、在切换的时间做的比较好。

程序锁功能 :
1. 用户要开启的这个应用是哪一个应用.
   寻找系统里面是不是这样的广播事件,如果这样直接注册一个广播接收者。不过有的应用不行,所以排除 。
   我们发现每个应用程序打开的时间ActivityManager都会暴露出来一段Log.
2. 判断这个应用的包名 程序名 是否是要锁定的应用名字一致


ActvityManager里面有个方法可以得到最近应用,与长按Home键盘
得到的东西是一致的。特别好用的。可以得到当前正在运行的
任务栈里面的信息。
 
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningTaskInfo>  infos = manager.getRunningTasks(2);
for (RunningTaskInfo info : infos) {
	System.out.println("tt  "+info.topActivity.getPackageName());
}

想要调用同一个进程里面服务里的方法,要绑定这个服务。
想要跨进程访问,就用AIDL。

之所以绑定服务能够调用服务里面的方法,主要是因为
在onBinder方法里面能够返回一个IBinder对象。

先自己做试验,常规的。
如果是绑定,同生共死的,如果你退出activity会
出错。
先开启,后绑定方式。

一个服务也只能被解除绑定一次,多次会出异常。

服务总结:
1、startService()开启的服务会长期运行在后台与服务调用者无关,
调用者结束,服务不会结束,不能调用服务里面的方法。
2、bindService()服务和调用者绑定在一起,如果调用者挂掉了,服务
也会终止,调用者可以访问服务里面的方法。
如果我们既要服务长期在后台运行,又要去调用服务里面的方法。
那么,1、startService()保证服务长期在后台运行,2、bindService()
把服务绑定,调用服务里面的方法。
那么这种如何结束服务呢,首先解绑服务,然后再stop服务这样就结束了。

在单独使用绑定服务的时间,如果调用者关了,但是服务没有停止 ,这样
会报出异常,如果你该服务你已经解除绑定过了,再次解绑还会出错。
针对第一种调用者关了,那么应该在调用者的activity里面重写onDestory()
方法,并且在里面调用 unbind()方法,这样当调用者退出时间,它也会自动
退出。

复习一下相对布局。

再次证明,使用模态就用帧布局。

复杂动画用AnimationSet.

其实Oncreate()相当于main,所有的方法都 要写在里面。否则就相当于它没有被调用 ,除了回调函数。

动画,位移动画,安卓中,好看的东西,无非是动画和背景两种。

TranslateAnimation ta = new TranslateAnimation(
		Animation.RELATIVE_TO_SELF, 0.0f,
		Animation.RELATIVE_TO_SELF, 0.5f,
		Animation.RELATIVE_TO_SELF, 0.0f,
		Animation.RELATIVE_TO_SELF, 0.0f);
ta.setDuration(500);

没有把频繁访问数据库的操作放在getView里面,而是而先把数据库里面
的数据放到 一个集合里面,让集合去判断它存在不存在,然后当再有数据库
的添加和删除时间,再动态往这个集合里面存 ,放数据。

AppInfo appInfo = infos.get(position);
//出现问题了,原来listview只是第一屏显示是新创建的,其它用的都是缓存,你锁后,那个东西存储到缓存中,当下面的再调用这个布局的时间,直接默认它是这样。
//所以我们在这里面动态设置一把即可。还有你在这绝对不能用数据库判断,而是放在 一个集合里面。
iv_lock_status = (ImageView) view.findViewById(R.id.iv_app_lock_status);
iv = (ImageView) view.findViewById(R.id.iv_app_icon);
tv_appName = (TextView) view.findViewById(R.id.tv_app_name);
tv_packName = (TextView) view.findViewById(R.id.tv_app_packname);
if (lockappinfos.contains(appInfo.getPackName())) {
	iv_lock_status.setImageResource(R.drawable.lock);
}else {
	iv_lock_status.setImageResource(R.drawable.unlock);
}
iv.setImageDrawable(infos.get(position).getIcon());
tv_appName.setText(infos.get(position).getAppName());
tv_packName.setText(infos.get(position).getPackName());

//如果发现已锁定,则让它不锁定,否则让它锁定 
if (lockAppDao.find(appName)) {
	imageView.setImageResource(R.drawable.unlock);
	lockAppDao.delete(appName);
	lockappinfos.remove(appName);
}else {
	lockAppDao.insert(appName);
	imageView.setImageResource(R.drawable.lock);
	lockappinfos.add(appName);
}

看门狗的逻辑:
看门狗服务第一创建出的时间,应该去找任务栈中的应用是否在
锁定状态(访问数据库知道)
太厉害了,让一个服务一直反复监听执行,原来是用循环。

服务里面激活任务栈:


在安卓中数据通信就两点,
一是跟后台持久化的东西,
二是前台各个控件之间通信。
掌握到这两点即可。

结束当前activity,finish()、

操,后台开启一个服务,弄一个死循环,一直在获取当前运行的
activity是不是在锁定表中,如果是果断弹出相应的输入密码界面。

stopService(iservic) 会调用服务中的ondestory()方法。

其实这个看门狗非常简单,就是在发现被锁定的程序运行时间,赶紧自己
弹出一个输入密码的activity去在当前任务栈中新加一个,但是,如果
用户按后退的时间就挂了,会回去要打开的程序中,所以屏蔽后退按钮。

todo:

1. 用户输入密码正确. 通知看门狗 临时的停止对这个程序的保护 
就需要调用服务里面的方法 。

2. 更新完毕数据库之后 通知看门狗 更新lockapp集合里面的内容




// 判断当前前台进程的包名 是否与luncher的包名 相同 
// 清空temp集合
activity之所以能够调用服务里面的方法就是因为onBind()方法能够
返回IBinder的对象。
凡是你在一个Acitivity里面绑定了一个服务就一定不要忘记了在activity
里面的ondestory()里面把unbindSerivce()解除绑定。
有一个问题,打开的activity,LockScreenActivity这个会加入到
360safe的这个软件的栈顶,当你打开360safe的时间会把LockScreenActivity
显示出来,所以我们应该把这个LockScreenActivity设置启动模式为单例。

第二个问题是不是把获取所有应用的操作放在子线程里面,太浪费性能了,
要用内容提供者。然后在activity写一个内容观察者,可以观察到数据的变化,
那岂不很好。当数据改变的时间,再去更新lockapps集合里面的内容。

发现了一个天大的秘密,原来只要涉及数据库频繁操作的,一般情况下都不直接
和它交互,因为这样太浪费感情了,如果只是取的比较多,那么把它放在一个
集合里面,用contains这个方法,判断,只需要从数据库读取一次,还有一个就是
你在过程中GRUD可能会有,这个时间应该把这个对数据库的操作写成一个内容提供
者,然后在activity里面写一个内容观察者,当数据发生变化的时间才去改变它。

原来第一个问题是这样解决的,如果输入密码正确,则往服务里面的一个临时集合里面
加一个数据,在判断的时间加上集合中有没有这个,有的话此次打开 ,并不是非要说
把数据库给改变,此方法是多么的好呀。

第二个问题是,我们不能每次都从数据库里面读取最新的数据吧,所以我们用一个把它封装
成一个内容提供者,当内容改变的时间才去更新。
这个东西要好好 看看的。
<!-- 被锁程序读取数据库的内容提供者 -->
<provider android:name=".provider.AppLockProvider" android:authorities="cn.itcast.applockprovider"></provider>
写好以后,再调用GRUD时间
getContentResolver().delete(Uri.parse("content://cn.itcast.applockprovider/delete"), null, new String[]{appName});
第二个作用就是可以为其注册一个内容观察者,当数据变化的时间才触发onChange事件。

//注册内容观察者
getContentResolver().registerContentObserver(Uri.parse("content://cn.itcast.applockprovider"),
		true, new MyObserver(new Handler()));
		
守护进程。

//输入密码后,再次进入的三种做法 。
做法1> 当用户回到桌面应用后 ,下一次在进入计算器 需要输入密码

做法2> 倒计时60秒 , 60过后 需要再次输入密码
// 开启一个子线程 60秒后清空这个temp集合

做法3> 当用户关闭手机屏幕后,下一次进入程序的时候 需要输入密码 (360的做法)



读log的方式开发的程序锁.
耗电量 低一些 
效率低.






抱歉!评论已关闭.