手机卫士day11
day11
- 系統進程顯示和隱藏- 創建進程管理設置頁面:ProcessManagerSettingActivity- 編寫設置頁面布局文件- 監聽Checkbox的勾選事件,更新本地SharePreference// 根據本地記錄,更新checkbox狀態boolean showSystem = mPrefs.getBoolean("show_system_process", true);if (showSystem) {cbShowSystem.setChecked(true);cbShowSystem.setText("顯示系統進程");} else {cbShowSystem.setChecked(false);cbShowSystem.setText("不顯示系統進程");}// 設置狀態勾選監聽cbShowSystem.setOnCheckedChangeListener(new OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {if (isChecked) {cbShowSystem.setText("顯示系統進程");mPrefs.edit().putBoolean("show_system_process", true).commit();} else {cbShowSystem.setText("不顯示系統進程");mPrefs.edit().putBoolean("show_system_process", false).commit();}}});- 根據sp記錄的是否顯示系統進程,更新listview的顯示個數@Overridepublic int getCount() {// 通過判斷是否顯示系統進程,更新list的數量boolean showSystem = mPrefs.getBoolean("show_system_process", true);if (showSystem) {return 1 + mUserProcessList.size() + 1 + mSystemProcessList.size();} else {return 1 + mUserProcessList.size();}}- 保證勾選框改變后,listview可以立即刷新public void setting(View view) {startActivityForResult(new Intent(this,ProcessManagerSettingActivity.class), 0);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {// 當從設置頁面回跳回來之后,刷新listviewmAdapter.notifyDataSetChanged();}- 鎖屏清理- 演示金山進程管理效果- 后臺啟動服務,監聽廣播//判斷鎖屏清理的廣播是否正在運行boolean serviceRunning = ServiceStatusUtils.isServiceRunning("com.itheima.mobilesafeteach.service.AutoKillService", this);if (serviceRunning) {cbLockClear.setChecked(true);cbLockClear.setText("當前狀態:鎖屏清理已經開啟");} else {cbLockClear.setChecked(false);cbLockClear.setText("當前狀態:鎖屏清理已經關閉");}cbLockClear.setOnCheckedChangeListener(new OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {Intent intent = new Intent(ProcessManagerSettingActivity.this,AutoKillService.class);if (isChecked) {// 啟動鎖屏清理的服務startService(intent);cbLockClear.setText("當前狀態:鎖屏清理已經開啟");} else {// 關閉鎖屏清理的服務stopService(intent);cbLockClear.setText("當前狀態:鎖屏清理已經關閉");}}});-------------------------------------/*** 鎖屏清理進程的服務* * @author Kevin* */public class AutoKillService extends Service {private InnerScreenOffReceiver mReceiver;@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();//監聽屏幕關閉的廣播, 注意,該廣播只能在代碼中注冊,不能在清單文件中注冊mReceiver = new InnerScreenOffReceiver();IntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_SCREEN_OFF);registerReceiver(mReceiver, filter);}@Overridepublic void onDestroy() {super.onDestroy();unregisterReceiver(mReceiver);mReceiver = null;}/*** 鎖屏關閉的廣播接收者* * @author Kevin* */class InnerScreenOffReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {System.out.println("屏幕關閉...");// 殺死后臺所有運行的進程ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);List<RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses();for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses) {// 跳過手機衛士的服務if (runningAppProcessInfo.processName.equals(ctx.getPackageName())) {return;}am.killBackgroundProcesses(runningAppProcessInfo.processName);}}}}- 定時器清理(介紹)// 在AutoKillService的onCreate中啟動定時器,定時清理任務mTimer = new Timer();mTimer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("5秒運行一次!");}}, 0, 5000);@Overrideprotected void onDestroy() {super.onDestroy();mTimer.cancel();mTimer = null;}桌面Widget(窗口小部件)
- widget介紹(Android, 瑞星,早期word)
- widget谷歌文檔查看(API Guide->App Components->App Widget)
widget開發流程
1. 在com.itheima.mobilesafe.receiver目錄下創建MyWidget并且繼承AppWidgetProvider 2. 在功能清單文件注冊,參照文檔<receiver android:name=".receiver.MyWidget" ><intent-filter><action android:name="android.appwidget.action.APPWIDGET_UPDATE" /></intent-filter><meta-dataandroid:name="android.appwidget.provider"android:resource="@xml/appwidget_info" /></receiver>3. 在res/xml/創建文件example_appwidget_info.xml拷貝文檔內容<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="294dp" android:minHeight="72dp"//能被調整的最小寬高,若大于minWidth minHeight 則忽略 android:updatePeriodMillis="86400000"//更新周期,毫秒,最短默認半小時 android:previewImage="@drawable/preview"//選擇部件時 展示的圖像,3.0以上使用,默認是ic_launcher android:initialLayout="@layout/example_appwidget"//布局文件android:configure="com.example.android.ExampleAppWidgetConfigure"//添加widget之前,先跳轉到配置的activity進行相關參數配置,這個我們暫時用不到 android:resizeMode="horizontal|vertical"//widget可以被拉伸的方向。horizontal表示可以水平拉伸,vertical表示可以豎直拉伸android:widgetCategory="home_screen|keyguard"//分別在屏幕主頁和鎖屏狀態也能顯示(4.2+系統才支持)android:initialKeyguardLayout="@layout/example_keyguard"//鎖屏狀態顯示的樣式(4.2+系統才支持)></appwidget-provider>4. 精簡example_appwidget_info.xml文件,最終結果:<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"android:minWidth="294dp" android:minHeight="72dp"android:updatePeriodMillis="1800000"android:initialLayout="@layout/appwidget"></appwidget-provider>5. widget布局文件:appwidget.xml<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><TextViewandroid:id="@+id/textView1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="#f00"android:text="我是widget,哈哈哈"android:textSize="30sp" /></LinearLayout>簡單演示,高低版本對比
仿照金山widget效果, apktool反編譯,抄金山布局文件(業內抄襲成風)
1. 反編譯金山apk使用apktool,可以查看xml文件內容apktool d xxx.apk 2. 在金山清單文件中查找 APPWIDGET_UPDATE, 找到widget注冊的代碼 3. 拷貝金山widget的布局文件process_widget_provider.xml到自己的項目中 4. 從金山項目中拷貝相關資源文件,解決報錯 5. 運行,查看效果widget生命周期
/*** 窗口小部件widget* * @author Kevin* */ public class MyWidget extends AppWidgetProvider {/*** widget的每次變化都會調用onReceive*/@Overridepublic void onReceive(Context context, Intent intent) {super.onReceive(context, intent);System.out.println("MyWidget: onReceive");}/*** 當widget第一次被添加時,調用onEnable*/@Overridepublic void onEnabled(Context context) {super.onEnabled(context);System.out.println("MyWidget: onEnabled");}/*** 當widget完全從桌面移除時,調用onDisabled*/@Overridepublic void onDisabled(Context context) {super.onDisabled(context);System.out.println("MyWidget: onDisabled");}/*** 新增widget時,或者widget更新時,調用onUpdate* 更新時間取決于xml中配置的時間,最短為半小時*/@Overridepublic void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) {super.onUpdate(context, appWidgetManager, appWidgetIds);System.out.println("MyWidget: onUpdate");}/*** 刪除widget時,調onDeleted*/@Overridepublic void onDeleted(Context context, int[] appWidgetIds) {super.onDeleted(context, appWidgetIds);System.out.println("MyWidget: onDeleted");}/*** 當widget大小發生變化時,調用此方法*/@Overridepublic void onAppWidgetOptionsChanged(Context context,AppWidgetManager appWidgetManager, int appWidgetId,Bundle newOptions) {System.out.println("MyWidget: onAppWidgetOptionsChanged");}}定時更新widget
問題: 我們需要通過widget實時顯示當前進程數和可用內存,但widget最短也得半個小時才會更新一次, 如何才能間隔比較短的時間來及時更新?查看金山日志:當桌面有金山widget時, 金山會在后臺啟動service:ProcessService,并定時輸出如下日志: 03-29 08:43:03.070: D/MoSecurity.ProcessService(275): updateWidget該日志在鎖屏狀態下也一直輸出.解決辦法: 后臺啟動service,UpdateWidgetService, 并在service中啟動定時器來控制widget的更新更新widget方法
/*** 定時更新widget的service* * @author Kevin* */ public class UpdateWidgetService extends Service {private Timer mTimer;private AppWidgetManager mAWM;@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();mAWM = AppWidgetManager.getInstance(this);// 啟動定時器,每個5秒一更新mTimer = new Timer();mTimer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("更新widget啦!");updateWidget();}}, 0, 5000);}/*** 更新widget*/private void updateWidget() {// 初始化遠程的view對象RemoteViews views = new RemoteViews(getPackageName(),R.layout.process_widget);views.setTextViewText(R.id.tv_running_processes, "正在運行的軟件:"+ ProcessInfoProvider.getRunningProcessNum(this));views.setTextViewText(R.id.tv_memory_left,"可用內存:"+ Formatter.formatFileSize(this,ProcessInfoProvider.getAvailMemory(this)));// 初始化組件ComponentName provider = new ComponentName(this, MyWidget.class);// 更新widgetmAWM.updateAppWidget(provider, views);}@Overridepublic void onDestroy() {super.onDestroy();mTimer.cancel();mTimer = null;} }-----------------------------啟動和銷毀service的時機分析widget的聲明周期,在onEnabled和onUpdate中啟動服務, 在onDisabled中結束服務注意: APK安裝在sd卡上,widget在窗口小部件列表里無法顯示。 android:installLocation=”preferExternal”, 修改過來后,需要卸載,再去安裝widget才生效;
點擊事件處理
// 初始化延遲意圖,pending是等待的意思 Intent intent = new Intent(this, HomeActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,intent, PendingIntent.FLAG_UPDATE_CURRENT);// 當點擊widget布局時,跳轉到主頁面 views.setOnClickPendingIntent(R.id.ll_root, pendingIntent);//當一鍵清理被點擊是,發送廣播,清理內存 Intent btnIntent = new Intent(); btnIntent.setAction("com.itheima.mobilesafeteach.KILL_ALL"); PendingIntent btnPendingIntent = PendingIntent.getBroadcast(this, 0,btnIntent, PendingIntent.FLAG_UPDATE_CURRENT); views.setOnClickPendingIntent(R.id.btn_clear, btnPendingIntent);--------------------------- /*** 殺死后臺進程的廣播接受者* 清單文件中配置action="com.itheima.mobilesafeteach.KILL_ALL"* * @author Kevin* */ public class KillAllReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {System.out.println("kill all...");// 殺死后臺所有運行的進程ProcessInfoProvider.killAll(context);} }---------------------------<receiver android:name=".receiver.KillAllReceiver" ><intent-filter><action android:name="com.itheima.mobilesafeteach.KILL_ALL" /></intent-filter></receiver>做一個有情懷的程序員, 拒絕耗電!
當鎖屏關閉時,停止widget定時器的更新UpdateWidgetService:// 注冊屏幕開啟和關閉的廣播接受者 mReceiver = new InnerScreenReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); registerReceiver(mReceiver, filter);/*** 屏幕關閉和開啟的廣播接收者* * @author Kevin* */ class InnerScreenReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (Intent.ACTION_SCREEN_OFF.equals(action)) {// 屏幕關閉if (mTimer != null) {// 停止定時器mTimer.cancel();mTimer = null;}} else {// 屏幕開啟startTimer();}} }
程序鎖
- 高級工具中添加程序鎖入口
- 新建程序鎖頁面 AppLockActivity
程序鎖頁面布局文件實現
activity_app_lock.xml<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:orientation="horizontal" ><TextViewandroid:id="@+id/tv_unlock"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/tab_left_pressed"android:gravity="center"android:text="未加鎖"android:textColor="#fff" /><TextViewandroid:id="@+id/tv_locked"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/tab_right_default"android:gravity="center"android:text="已加鎖"android:textColor="#fff" /></LinearLayout><LinearLayoutandroid:id="@+id/ll_unlock"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="未加鎖軟件:x個"android:textColor="#000" /><ListViewandroid:id="@+id/lv_unlock"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout><LinearLayoutandroid:id="@+id/ll_locked"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:visibility="gone" ><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="已加鎖軟件:x個"android:textColor="#000" /><ListViewandroid:id="@+id/lv_locked"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout></LinearLayout>點擊標簽切換頁面
@Override public void onClick(View v) {switch (v.getId()) {case R.id.tv_unlock:// 展示未加鎖頁面,隱藏已加鎖頁面llLocked.setVisibility(View.GONE);llUnlock.setVisibility(View.VISIBLE);tvUnlock.setBackgroundResource(R.drawable.tab_left_pressed);tvLocked.setBackgroundResource(R.drawable.tab_right_default);break;case R.id.tv_locked:// 展示已加鎖頁面,隱藏未加鎖頁面llUnlock.setVisibility(View.GONE);llLocked.setVisibility(View.VISIBLE);tvUnlock.setBackgroundResource(R.drawable.tab_left_default);tvLocked.setBackgroundResource(R.drawable.tab_right_pressed);break;default:break;} }應用列表信息展現(展現全部應用列表數據)
使用數據庫保存已加鎖的軟件
AppLockOpenHelper.java// 創建表, 兩個字段,_id, packagename(應用包名) db.execSQL("create table applock (_id integer primary key autoincrement, packagename varchar(50))");----------------------------------AppLockDao.java(邏輯和黑名單列表類似)/*** 增加程序鎖應用*/ public void add(String packageName) {SQLiteDatabase db = mHelper.getWritableDatabase();ContentValues values = new ContentValues();values.put("packagename", packageName);db.insert("applock", null, values);db.close(); }/*** 刪除程序鎖應用* * @param number*/ public void delete(String packageName) {SQLiteDatabase db = mHelper.getWritableDatabase();db.delete("applock", "packagename=?", new String[] { packageName });db.close(); }/*** 查找程序鎖應用* * @param number* @return*/ public boolean find(String packageName) {SQLiteDatabase db = mHelper.getWritableDatabase();Cursor cursor = db.query("applock", null, "packagename=?",new String[] { packageName }, null, null, null);boolean result = false;if (cursor.moveToFirst()) {result = true;}cursor.close();db.close();return result; }/*** 查找已加鎖列表* * @return*/ public ArrayList<String> findAll() {SQLiteDatabase db = mHelper.getWritableDatabase();Cursor cursor = db.query("applock", new String[] { "packagename" },null, null, null, null, null);ArrayList<String> list = new ArrayList<String>();while (cursor.moveToNext()) {String packageName = cursor.getString(0);list.add(packageName);}cursor.close();db.close();return list; }監聽list item點擊事件,向數據庫添加一些數據
lvUnLock.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {AppInfo info = mUnlockList.get(position);mDao.add(info.packageName);} });已加鎖和未加鎖數據設置
private ArrayList<AppInfo> mLockedList;// 已加鎖列表集合 private ArrayList<AppInfo> mUnlockList;// 未加鎖列表集合private Handler mHandler = new Handler() {public void handleMessage(android.os.Message msg) {// 設置未加鎖數據mUnlockAdapter = new AppLockAdapter(false);lvUnLock.setAdapter(mUnlockAdapter);// 設置已加鎖數據mLockedAdapter = new AppLockAdapter(true);lvLocked.setAdapter(mLockedAdapter);}; };/*** 初始化應用列表數據*/ private void initData() {new Thread() {@Overridepublic void run() {mList = AppInfoProvider.getAppInfos(AppLockActivity.this);mLockedList = new ArrayList<AppInfo>();mUnlockList = new ArrayList<AppInfo>();for (AppInfo info : mList) {boolean isLocked = mDao.find(info.packageName);if (isLocked) {mLockedList.add(info);} else {mUnlockList.add(info);}}mHandler.sendEmptyMessage(0);}}.start(); }界面效果完善
點擊鎖子圖標后, 實現加鎖和去加鎖的邏輯, 界面跟著更新class AppLockAdapter extends BaseAdapter {private boolean isLocked;//true表示已加鎖數據public AppLockAdapter(boolean isLocked) {this.isLocked = isLocked;}@Overridepublic int getCount() {if (isLocked) {return mLockedList.size();} else {return mUnlockList.size();}}@Overridepublic AppInfo getItem(int position) {if (isLocked) {return mLockedList.get(position);} else {return mUnlockList.get(position);}}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(final int position, View convertView,ViewGroup parent) {ViewHolder holder;if (convertView == null) {convertView = View.inflate(AppLockActivity.this,R.layout.list_applock_item, null);holder = new ViewHolder();holder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);holder.tvName = (TextView) convertView.findViewById(R.id.tv_name);holder.ivLock = (ImageView) convertView.findViewById(R.id.iv_lock);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}final AppInfo info = getItem(position);holder.ivIcon.setImageDrawable(info.icon);holder.tvName.setText(info.name);if(isLocked) {holder.ivLock.setImageResource(R.drawable.unlock);}else {holder.ivLock.setImageResource(R.drawable.lock);}holder.ivLock.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if (isLocked) {mDao.delete(info.packageName);// 從數據庫刪除記錄mLockedList.remove(info);// 從已加鎖集合刪除元素mUnlockList.add(info);// 給未加鎖集合添加元素} else {mDao.add(info.packageName);// 向數據庫添加記錄mLockedList.add(info);// 給已加鎖集合添加元素mUnlockList.remove(info);// 從未加鎖集合刪除元素}// 刷新listviewmLockedAdapter.notifyDataSetChanged();mUnlockAdapter.notifyDataSetChanged();}});return convertView;} }更新已加鎖/未加鎖數量
/*** 更新已加鎖和未加鎖數量*/ private void updateAppNum() {tvUnLockNum.setText("未加鎖軟件:" + mUnlockList.size() + "個");tvLockedNum.setText("已加鎖軟件:" + mLockedList.size() + "個"); }// 每次刷新listview前都會調用getCount方法,可以在這里更新數量 @Override public int getCount() {updateAppNum();if (isLocked) {return mLockedList.size();} else {return mUnlockList.size();} }動畫實現
- 解決動畫移動問題導致的原因,動畫沒有開始播放,界面就刷新了。 動畫播放需要時間的,動畫沒有播就變成了新的View對象。就播了新的View對象, 讓動畫播放完后,再去更新頁面;public AppLockAdapter(boolean isLocked) {this.isLocked = isLocked;// 右移mLockAnim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0f,Animation.RELATIVE_TO_SELF, 1f, Animation.RELATIVE_TO_SELF,0, Animation.RELATIVE_TO_SELF, 0);mLockAnim.setDuration(500);// 左移mUnLockAnim = new TranslateAnimation(Animation.RELATIVE_TO_SELF,0f, Animation.RELATIVE_TO_SELF, -1f,Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,0);mUnLockAnim.setDuration(500); }holder.ivLock.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if (isLocked) {view.startAnimation(mUnLockAnim);mUnLockAnim.setAnimationListener(new AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationRepeat(Animation animation) {}//監聽動畫結束事件@Overridepublic void onAnimationEnd(Animation animation) {mDao.delete(info.packageName);// 從數據庫刪除記錄mLockedList.remove(info);// 從已加鎖集合刪除元素mUnlockList.add(info);// 給未加鎖集合添加元素// 刷新listviewmLockedAdapter.notifyDataSetChanged();mUnlockAdapter.notifyDataSetChanged();}});} else {view.startAnimation(mLockAnim);mLockAnim.setAnimationListener(new AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationRepeat(Animation animation) {}//監聽動畫結束事件@Overridepublic void onAnimationEnd(Animation animation) {mDao.add(info.packageName);// 向數據庫添加記錄mLockedList.add(info);// 給已加鎖集合添加元素mUnlockList.remove(info);// 從未加鎖集合刪除元素// 刷新listviewmLockedAdapter.notifyDataSetChanged();mUnlockAdapter.notifyDataSetChanged();}});}} });
總結
- 上一篇: MySQL update正在执行中突然断
- 下一篇: 设置电脑眼睛保护色_百度经验