Android - 页面切换,动画播放,程序锁,Activity启动模式,利用内容观察者同步数据库变化

本文详细介绍了程序锁的设计实现,包括界面切换、动画播放注意事项、监听应用开启、非Activity启动Activity的方法、Activity启动模式等。此外,还深入探讨了程序锁的工作原理及优化技巧,如减少数据库查询次数、利用内容观察者同步数据库变化等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明出处:https://blog.youkuaiyun.com/mythmayor/article/details/72900511

1.两个页面切换的实现

  1. 可以使用Fragment,调用FragmentTransaction的hide和show方法
  2. 可以使用两个布局,设置visibility的VISIABLE和INVISIABLE

2.已加锁、未加锁界面数据的获取思路

  1. 获取所有的应用
  2. 这些应用只可能是未加锁或者已加锁
  3. 根据数据库中存储的已加锁的情况,将所有数据分别装到已加锁和未加锁两个集合中

3.动画播放需要注意什么

  1. 动画的播放是非阻塞式的,相当于开启了一个子线程定期的刷新UI
  2. 如果想在动画播完之后执行一些操作,需要设置监听器

    ta.setAnimationListener(new AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
            //动画开始播放了。。。
        }
    
        @Override
        public void onAnimationRepeat(Animation animation) {
            //动画重复播放了。
        }
    
        @Override
        public void onAnimationEnd(Animation animation) {
            //动画播放完毕了。
            //从当前页面把应用程序条目给移除
            unlockPackinfos.remove(position);
            unlockItemsAdapter.notifyDataSetChanged();
            //把数据加入到已加锁的列表里面
            lockedPackinfos.add(packInfo);
            lockedItemsAdapter.notifyDataSetChanged();
        }
    });
    

4.程序锁的工作原理

  1. 开启一个服务一直去监听最新开启的应用
  2. 判断新开启的应用是已加锁的应用
  3. 如果是已加锁应用,弹出输入密码对话框

  4. 获取正在运行的应用,需要权限

    //获取到当前手机的任务栈
    List<RunningTaskInfo> infos = am.getRunningTasks(1000);
    //获取任务栈最上面的Activity
    String packname = infos.get(0).topActivity.getPackageName();
    System.out.println("正在运行:"+packname);
    

5.非Activity里启动Activity有什么要注意的

需要设置flag————Intent.FLAG_ACTIVITY_NEW_TASK

Intent intent = new Intent(WatchDogService.this,EnterPasswordActivity.class);
intent.putExtra("packname", packname);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

6.如何监听返回键,打开桌面

@Override
public void onBackPressed() {
    //       <action android:name="android.intent.action.MAIN" />
    //       <category android:name="android.intent.category.HOME" />
    //       <category android:name="android.intent.category.DEFAULT" />
    Intent intent = new Intent();
    intent.setAction("android.intent.action.MAIN");
    intent.addCategory("android.intent.category.HOME");
    intent.addCategory("android.intent.category.DEFAULT");
    startActivity(intent);
}

7.Activity的启动模式

(1)standard:每次激活Activity时(startActivity),都创建Activity实例,并放入任务栈;
这里写图片描述

(2)singleTop:如果某个Activity自己激活自己,即任务栈栈顶就是该Activity,则不需要创建,其余情况都要创建Activity实例;
这里写图片描述

(3)singleTask:如果要激活的那个Activity在任务栈中存在该实例,则不需要创建,只需要把此Activity放入栈顶,并把该Activity以上的Activity实例都pop;
这里写图片描述

(4)singleInstance:会单独创建一个Activity栈;
这里写图片描述

8.程序锁的优化

  1. 将while循环里每次都创建的变量放到循环外面,只创建一次

    //修改前
    while(flag){
        List<RunningTaskInfo> infos = am.getRunningTasks(1000);
        String packname = infos.get(0).topActivity.getPackageName();
    
    //修改后
    List<RunningTaskInfo> infos;
    String packname;
    while(flag){
        infos = am.getRunningTasks(1000);
        packname = infos.get(0).topActivity.getPackageName();
    
  2. 获取正在运行的应用时,只需要获取到第一个就可以了,将集合大小设置为1

    //修改前
    infos = am.getRunningTasks(1000);
    
    //修改后
    infos = am.getRunningTasks(1);
    
  3. 每次都查询数据库比较耗时,将数据库的内容都查询出来,放到一个集合里,以后查询的时候就去查询内存中的集合数据

    //修改前
    if(dao.find(packname)){//每次都查询数据库
    
    //修改后
    1.在ApplockDao中添加一个查询所有已加锁应用的方法
    public List<String> findAll() {
        List<String> lockedPacknames = new ArrayList<String>();
        SQLiteDatabase db = helper.getReadableDatabase();
        Cursor cursor = db.rawQuery("select packname from lockinfo", null);
        while (cursor.moveToNext()) {
            lockedPacknames.add(cursor.getString(0));
        }
        cursor.close();
        db.close();
        return lockedPacknames;
    }
    2.声明一个成员变量,onCreate方法中将所有数据查询出来
    private List<String> lockedPacknames;
    
    @Override
    public void onCreate() {
        ...
        ...
        //获取的是数据库锁定的全部的包名 
        lockedPacknames = dao.findAll();
        ...
        ...
    }
    
    3.查询的时候直接去查询内存中的数据
    if(lockedPacknames.contains(packname)){//查询内存
    

9. 如何利用内容观察者同步数据库变化

  1. 在AppLockDao中的add和delete方法中,加入修改数据库的通知

    //添加或删除一条记录
    Uri uri = Uri.parse("content://com.mythmayor.project.applockdb");
    context.getContentResolver().notifyChange(uri, null);
    
  2. 在WatchDogService中注册内容观察者

    //注册内容观察者观察数据库内容的变化
    Uri uri = Uri.parse("content://com.mythmayor.project.applockdb");
    observer = new MyObserver(new Handler());
    getContentResolver().registerContentObserver(uri, true, observer);
    
    //内容观察者
    private class MyObserver extends ContentObserver{
    
        public MyObserver(Handler handler) {
            super(handler);
        }
    
        //内容观察者观察到数据变化调用的方法
        @Override
        public void onChange(boolean selfChange) {
            Log.i(TAG,"看门狗里面的内容观察者观察到了数据库变化。。。。");
            lockedPacknames = dao.findAll();
            super.onChange(selfChange);
        }
    
    }
    

上面的方式在观察到数据库的变化时,又重新查询了所有的数据,还是不够优化,实际上我们在add或者delete时只是对一条数据进行了操作,可以利用uri将add或者delete的数据通知出来

  1. 在AppLockDao中的add和delete方法中,加入修改数据库的通知,通知时带出操作和所操作的包名

    //添加数据
    Uri uri = Uri.parse("content://com.mythmayor.project.applockdb?add="+packname);
    context.getContentResolver().notifyChange(uri, null);
    
    //删除数据
    Uri uri = Uri.parse("content://com.mythmayor.project.applockdb?delete="+packname);
    context.getContentResolver().notifyChange(uri, null);
    
  2. 在WatchDogService中注册内容观察者,根据不同的uri,做出不同的操作

    private class MyObserver extends ContentObserver{
    
        public MyObserver(Handler handler) {
            super(handler);
        }
    
        @Override
        public void onChange(boolean selfChange, Uri uri) {
            // TODO Auto-generated method stub
            String query = uri.getQuery();
            Log.i(TAG, "query--->"+query);
    
            Set<String> names = uri.getQueryParameterNames();
            for(String name : names){
                Log.i(TAG, "name--->"+name);
                List<String> parameters = uri.getQueryParameters(name);
                for(String parameter : parameters){
                    Log.i(TAG, "parameter--->"+parameter);
                }
            }
            super.onChange(selfChange);
        }
    
    }
    
    //对应的log
    query--->add=com.android.calculator2
    name--->add
    parameter--->com.android.calculator2
    

10. 接收屏幕锁屏和亮起的广播

Intent.ACTION_SCREEN_ON
Intent.ACTION_SCREEN_OFF
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值