23、高级工具--程序锁界面设计

本文介绍了一款程序锁应用的设计与实现过程,包括UI界面布局、应用程序信息获取、数据库操作等功能模块。

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

界面效果图:


在加载安装的应用程序列表时,显示进度条:


布局文件:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView style="@style/title_center_text"
        android:text="程序锁"/>
    <View style="@style/splitter_view"/>

    <RelativeLayout
        android:layout_height="fill_parent"
        android:layout_width="fill_parent">
        <LinearLayout
            android:id="@+id/ll_applock_loading"
            android:gravity="center"
            android:orientation="vertical"
            android:visibility="invisible"
            android:layout_height="fill_parent"
            android:layout_width="fill_parent">
            <ProgressBar
                android:layout_height="wrap_content"
                android:layout_width="wrap_content" />
            <TextView style="@style/content_text"
                android:text="正在加载程序信息……"/>
        </LinearLayout>
        <ListView
            android:fastScrollEnabled="true"
            android:id="@+id/lv_applock"
            android:layout_height="match_parent"
            android:layout_width="match_parent"/>
    </RelativeLayout>
</LinearLayout>
实际上在加载过程中进度控件是覆盖掉ListView的,当加载完毕后发送消息通知,消息处理过程隐藏掉进度控件即可。

ListView的每一个item的布局:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/iv_applock_icon"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_alignParentLeft="true"/>
    <TextView style="@style/content_text"
        android:id="@+id/iv_applock_name"
        android:layout_toRightOf="@+id/iv_applock_icon"/>
    <ImageView
        android:id="@+id/iv_applock_status"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_alignParentRight="true"/>
</RelativeLayout>
用来显示程序图标的ImageView,显示应用程序名的TextView,和锁定状态的ImageView。


界面在加载时先获取已安装的程序列表,保存应用程序的信息用一个AppInfo类来表示:

package com.example.mobilesafe.engine;

import android.graphics.drawable.Drawable;

/**
 * Created by sing on 14-1-15.
 * desc:
 */
public class AppInfo {

    private static final String TAG = "AppInfo";

    //包名
    private String packname;

    //应用程序版本号
    private String version;

    //应用程序名
    private String appname;

    //应用程序图标
    private Drawable appicon;

    //标识是否是用户层应用
    private boolean userpp;

    public String getPackname() {
        return packname;
    }

    public void setPackname(String packname) {
        this.packname = packname;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getAppname() {
        return appname;
    }

    public void setAppname(String appname) {
        this.appname = appname;
    }

    public Drawable getAppicon() {
        return appicon;
    }

    public void setAppicon(Drawable appicon) {
        this.appicon = appicon;
    }

    public boolean isUserpp() {
        return userpp;
    }

    public void setUserpp(boolean userpp) {
        this.userpp = userpp;
    }
}
获取安装的应用程序列表:

package com.example.mobilesafe.engine;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;

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

/**
 * Created by sing on 14-1-15.
 * desc:
 */
public class AppInfoProvider {
    private static final String TAG = "AppInfoProvider";

    private PackageManager pm;

    public AppInfoProvider(Context context) {
        pm = context.getPackageManager();
    }

    public List<AppInfo> getInstalledApps() {
        List<PackageInfo> packageInfos = pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
        List<AppInfo> appInfos = new ArrayList<AppInfo>();

        for (PackageInfo info : packageInfos) {
            AppInfo appinfo = new AppInfo();
            appinfo.setPackname(info.packageName);
            appinfo.setVersion(info.versionName);
            appinfo.setAppname(info.applicationInfo.loadLabel(pm).toString());
            appinfo.setAppicon(info.applicationInfo.loadIcon(pm));
            appinfo.setUserpp(filterApp(info.applicationInfo));
            appInfos.add(appinfo);
            appinfo = null;
        }

        return appInfos;
    }

    public boolean filterApp(ApplicationInfo info) {
        if ((info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
            return false;
        } else if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
            return true;
        }

        return false;
    }
}

用户点击ListView的某一个item时,应进行锁定或解锁,锁定时将应用程序的包名存入到数据库中,以备后面监控使用。

操作数据库的类:

package com.example.mobilesafe.db;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

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

/**
 * Created by sing on 14-1-15.
 * desc:对于锁定的app包名存储在数据库中
 */
public class AppLockDao {
    private static final String TAG = "AppLockDao";

    private AppLockDBOpenHelper helper;

    public AppLockDao(Context context) {
        helper = new AppLockDBOpenHelper(context);
    }

    /**
     * 查找指定的包名程序是否被锁定
     * @param packname
     * @return
     */
    public boolean find(String packname) {
        boolean result = false;

        SQLiteDatabase db = helper.getReadableDatabase();
        if (db.isOpen()) {
            Cursor cursor = db.rawQuery("select * from applock where packname=?", new String[]{packname});
            if (cursor.moveToFirst()) {
                result = true;
            }
            cursor.close();
            db.close();
        }
        return result;
    }

    /**
     * 数据库中添加一个包名,也就是对这个包名程序进行锁定
     * @param packname
     * @return
     */
    public boolean add(String packname) {
        if (find(packname)) {
            return false;
        }

        SQLiteDatabase db = helper.getWritableDatabase();
        if (db.isOpen()) {
            db.execSQL("insert into applock (packname) values (?)", new String[]{packname});
            db.close();
        }

        return find(packname);
    }

    /**
     * 删除某包名,下次不再对其锁定
     * @param packname
     */
    public void delete(String packname) {
        SQLiteDatabase db = helper.getWritableDatabase();
        if (db.isOpen()) {
            db.execSQL("delete from applock where packname=?", new String[]{packname});
            db.close();
        }
    }

    /**
     * 查询所有被锁定的应用程序包名
     * @return
     */
    public List<String> findAll() {
        List<String> packnames = new ArrayList<String>();
        SQLiteDatabase db = helper.getReadableDatabase();
        if (db.isOpen()) {
            Cursor cursor = db.rawQuery("select packname from applock", null);
            while (cursor.moveToNext()) {
                packnames.add(cursor.getString(0));
            }
            cursor.close();
            db.close();
        }

        return packnames;
    }
}
其中AppLockDBOpenHelper:

package com.example.mobilesafe.db;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

/**
 * Created by sing on 14-1-15.
 * desc:
 */
public class AppLockDBOpenHelper extends SQLiteOpenHelper {
    private static final String TAG = "AppLockDBOpenHelper";

    public AppLockDBOpenHelper(Context context) {
        //参数一:应用上下文,参数二:数据库名称
        //参数三:游标工厂对象,null表示使用系统默认的游标工厂对象,参数四:版本号
        super(context, "applock.db", null, 1);
    }

    /**
     * 数据库第一次被创建的时候执行该方法
     * 在该方法中,一般用于指定数据库的表结构
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        //创建程序锁的表 (表中包含_id,包名 )
        db.execSQL("create table applock (_id integer primary key autoincrement, packname varchar(20))");
    }

    /**
     * 当数据库的版本号 发生增加的时候调用的方法.
     * 一般用于升级程序后,更新数据库的表结构.
     */
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i2) {

    }
}

至此,提供功能的类全部编写完毕,主activity:AppLockerActivity的代码:

package com.example.mobilesafe;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.example.mobilesafe.R;
import com.example.mobilesafe.db.AppLockDao;
import com.example.mobilesafe.engine.AppInfo;
import com.example.mobilesafe.engine.AppInfoProvider;

import java.util.List;

/**
 * Created by sing on 14-1-10.
 * desc:
 */
public class AppLockerActivity extends Activity {

    public static final String TAG = "AppLockerActivity";

    private ListView lv_applock;
    private View ll_loading;

    private AppInfoProvider provider;
    private List<AppInfo> appInfos;
    private AppLockDao dao;
    private List<String> lockedPacknames;

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            ll_loading.setVisibility(View.INVISIBLE);
            lv_applock.setAdapter(new AppLockAdapter());
        }
    };

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.applockeractivity_layout);

        lv_applock = (ListView) findViewById(R.id.lv_applock);
        ll_loading = findViewById(R.id.ll_applock_loading);

        provider = new AppInfoProvider(this);
        dao = new AppLockDao(this);
        lockedPacknames = dao.findAll();

        ll_loading.setVisibility(View.VISIBLE);
        new Thread(){
            public void run() {
                appInfos = provider.getInstalledApps();
                handler.sendEmptyMessage(0);
            }
        }.start();

        lv_applock.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                AppInfo appInfo = (AppInfo) lv_applock.getItemAtPosition(i);
                String packname = appInfo.getPackname();
                ImageView iv = (ImageView) view.findViewById(R.id.iv_applock_status);
                TranslateAnimation ta = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0,
                        Animation.RELATIVE_TO_SELF, 0.2f,
                        Animation.RELATIVE_TO_SELF, 0,
                        Animation.RELATIVE_TO_SELF, 0);
                ta.setDuration(200);
                if (lockedPacknames.contains(packname)) {
                    dao.delete(packname);
                    iv.setImageResource(R.drawable.unlock);
                    lockedPacknames.remove(packname);
                }else {
                    dao.add(packname);
                    iv.setImageResource(R.drawable.lock);
                    lockedPacknames.add(packname);
                }
                view.startAnimation(ta);
            }
        });
    }

    private class AppLockAdapter extends BaseAdapter {
        @Override
        public int getCount() {
            return appInfos.size();
        }

        @Override
        public Object getItem(int i) {
            return appInfos.get(i);
        }

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

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            View v;
            ViewHolder holder;

            if (view==null) {
                v = View.inflate(getApplicationContext(), R.layout.app_lock_item, null);
                holder = new ViewHolder();
                holder.iv_icon = (ImageView) v.findViewById(R.id.iv_applock_icon);
                holder.iv_status = (ImageView) v.findViewById(R.id.iv_applock_status);
                holder.tv_name = (TextView) v.findViewById(R.id.iv_applock_name);
                v.setTag(holder);
            }else{
                v = view;
                holder = (ViewHolder)view.getTag();
            }

            AppInfo appInfo = appInfos.get(i);
            holder.iv_icon.setImageDrawable(appInfo.getAppicon());
            holder.tv_name.setText(appInfo.getAppname());
            if (lockedPacknames.contains(appInfo.getPackname())) {
                holder.iv_status.setImageResource(R.drawable.lock);
            }else{
                holder.iv_status.setImageResource(R.drawable.unlock);
            }

            return v;
        }
    }

    public static class ViewHolder {
        ImageView iv_icon;
        ImageView iv_status;
        TextView tv_name;
    }
}

这里使用了一个动画效果,当点击时相对左移一定距离,效果图:







评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

asmcvc

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

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

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

打赏作者

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

抵扣说明:

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

余额充值