本节书摘来自异步社区《精通Android 5 多媒体开发》一书中的第22章,第22.3节开发一个屏保程序,作者 王石磊,更多章节内容可以访问云栖社区“异步社区”公众号查看

22.3 开发一个屏保程序
精通Android 5 多媒体开发
了解了在Android系统中开发屏保程序的基本原理后,在本节的内容中,将通过一个具体实例的实现流程,来详细讲解开发Android屏保程序的基本流程。本实例的源代码保存在“daima22pingbao”中,下面开始讲解本实例的具体实现流程。

22.3.1 准备素材图片
在本实例中,设置屏保程序轮换显示5幅图片,图片的大小是320×480。本实例的素材图片保存在“resdrawable”目录下,效果如图22-1所示。


22.3.2 编写布局文件
本实例的布局文件是main.xml,在里面分别插入了一个ImageView控件、一个TextView和一个EditText,主要代码如下所示。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:background="@drawable/white"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><ImageViewandroid:id="@+id/myImageView1" android:layout_width="wrap_content" android:layout_height="wrap_content"android:scaleType="fitCenter" android:layout_gravity="center" /><TextViewandroid:id="@+id/myTextView1"android:layout_width="fill_parent" android:layout_height="wrap_content"android:textColor="@drawable/blue"android:visible="true"android:text="@string/str_set_pwd"/><EditTextandroid:id="@+id/myEditText1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text=""/>
</LinearLayout>

22.3.3 编写主程序文件
本实例的主程序文件是example.java,其具体实现流程如下所示。

(1)先引入相关class类,然后设置LayoutInflater对象作为新建的AlertDialog,具体代码如下所示:

package irdc.example;import irdc.example.R;import java.util.Date;import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;public class example extends Activity
{private TextView mTextView01;private ImageView mImageView01;/* LayoutInflater对象作为新建AlertDialog之用 */private LayoutInflater mInflater01;
(2)定义mView01,用于输入解锁的View。通过menu选项identifier,用以识别对应的事件,具体代码如下所示。/* 输入解锁的View */
private View mView01;
private EditText mEditText01,mEditText02;/* menu选项identifier,用以识别事件 */
static final private int MENU_ABOUT = Menu.FIRST;
static final private int MENU_EXIT = Menu.FIRST+1;
private Handler mHandler01 = new Handler();
private Handler mHandler02 = new Handler();
private Handler mHandler03 = new Handler();
private Handler mHandler04 = new Handler();
(3)分别定义控制User静止与否的Counter,控制FadeIn与Fade Out的Counter,控制循序替换背景图ID的Counter,具体代码如下所示。/* 控制User静止与否的Counter */
private int intCounter1, intCounter2;
/* 控制FadeIn与Fade Out的Counter */
private int intCounter3, intCounter4;
/* 控制循序替换背景图ID的Counter */
private int intDrawable=0;
(4)设置timePeriod,设置当静止超过<em>n</em>秒将自动进入屏幕保护,具体代码如下所示。/* 上一次User有动作的Time Stamp */
private Date lastUpdateTime;
/* 计算User共几秒没有动作 */
private long timePeriod;
/* 静止超过n秒将自动进入屏幕保护 */
private float fHoldStillSecond = (float) 5;
private boolean bIfRunScreenSaver;
private boolean bFadeFlagOut, bFadeFlagIn = false;
private long intervalScreenSaver = 1000;
private long intervalKeypadeSaver = 1000;
private long intervalFade = 100;
private int screenWidth, screenHeight;
(5)设置每5秒置换一次图片,并设置使用Screen Saver保存需要用到的背景图,具体代码如下所示。/* 每n秒置换图片 */
private int intSecondsToChange = 5;/* 设置Screen Saver需要用到的背景图 */
private static int[] screenDrawable = new int[]
{R.drawable.pingbao1,R.drawable.pingbao 2,R.drawable.pingbao 3,R.drawable.pingbao 4,R.drawable.pingbao 5
};
(6)设置在setContentView之前调用全屏幕显示,通过lastUpdateTime初始取得User用户触碰手机的时间,并用recoverOriginalLayout()来初始化Layout屏幕上的Widget可见性,具体代码如下所示。@Override
public void onCreate(Bundle savedInstanceState)
{super.onCreate(savedInstanceState);/* 必须在setContentView之前调用全屏幕显示 */requestWindowFeature(Window.FEATURE_NO_TITLE);getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);setContentView(R.layout.main);/* onCreate all Widget */mTextView01 = (TextView)findViewById(R.id.myTextView1);mImageView01 = (ImageView)findViewById(R.id.myImageView1);mEditText01 = (EditText)findViewById(R.id.myEditText1);/* 初始取得User触碰手机的时间 */lastUpdateTime = new Date(System.currentTimeMillis());/* 初始化Layout上的Widget可见性 */recoverOriginalLayout();
}
(7)设置Menu群组ID,然后通过menu.add创建具有SubMenu的Menu,最后创建退出Menu,具体代码如下所示。@Override
public boolean onCreateOptionsMenu(Menu menu)
{// TODO Auto-generated method stub/* Menu群组ID */int idGroup1 = 0;/* The order position of the item */int orderMenuItem1 = Menu.NONE;int orderMenuItem2 = Menu.NONE+1;/* 创建具有SubMenu的Menu */menu.add(idGroup1, MENU_ABOUT, orderMenuItem1, R.string.app_about);/* 创建退出Menu */menu.add(idGroup1, MENU_EXIT, orderMenuItem2, R.string.str_exit);menu.setGroupCheckable(idGroup1, true, true);return super.onCreateOptionsMenu(menu);
}
(8)根据用户选择的Menu,显示对应的AlertDialog提示框,具体代码如下所示。@Override
public boolean onOptionsItemSelected(MenuItem item)
{// TODO Auto-generated method stubswitch(item.getItemId()){case (MENU_ABOUT):new AlertDialog.Builder(example.this).setTitle(R.string.app_about).setIcon(R.drawable.hippo).setMessage(R.string.app_about_msg).setPositiveButton(R.string.str_ok,new DialogInterface.OnClickListener(){public void onClick(DialogInterface dialoginterface, int i){}}).show();break;case (MENU_EXIT):/* 离开程序 */finish();break;}return super.onOptionsItemSelected(item);
}
(9)用mTasks01监控User没有动作的运行线程,通过timePeriod计算User静止不动的时间间距,如果静止不懂查过设置的5秒,则运行对应的线程,具体代码如下所示。/* 监控User没有动作的运行线程 */
private Runnable mTasks01 = new Runnable()
{public void run() {intCounter1++;Date timeNow = new Date(System.currentTimeMillis());/* 计算User静止不动的时间间距 */timePeriod =(long)timeNow.getTime() - (long)lastUpdateTime.getTime();float timePeriodSecond = ((float)timePeriod/1000);/* 如果超过时间静止不动 */if(timePeriodSecond>fHoldStillSecond){/* 静止超过时间第一次的标记 */if(bIfRunScreenSaver==false){/* 启动运行线程2 */mHandler02.postDelayed(mTasks02, intervalScreenSaver);/* Fade Out*/if(intCounter1%(intSecondsToChange)==0){bFadeFlagOut=true;mHandler03.postDelayed(mTasks03, intervalFade);}else{/* 在Fade Out后立即Fade In */if(bFadeFlagOut==true){bFadeFlagIn=true;mHandler04.postDelayed(mTasks04, intervalFade);}else{bFadeFlagIn=false;intCounter4 = 0;mHandler04.removeCallbacks(mTasks04);}intCounter3 = 0;bFadeFlagOut = false;}bIfRunScreenSaver = true;}else{/* screen saver 正在运行中 *//* Fade Out*/if(intCounter1%(intSecondsToChange)==0){bFadeFlagOut=true;mHandler03.postDelayed(mTasks03, intervalFade);}else{/* 在Fade Out后立即Fade In */if(bFadeFlagOut==true){bFadeFlagIn=true;mHandler04.postDelayed(mTasks04, intervalFade);}else{bFadeFlagIn=false;intCounter4 = 0;mHandler04.removeCallbacks(mTasks04);}intCounter3 = 0;bFadeFlagOut=false;}}}else{/* 当User没有动作的间距未超过时间 */bIfRunScreenSaver = false;/* 恢复原来的Layout Visible*/recoverOriginalLayout();}/* 以LogCat监看User静止不动的时间间距 */Log.i("HIPPO","Counter1:"+Integer.toString(intCounter1)+"/"+Float.toString(timePeriodSecond));/* 反复运行运行线程1 */mHandler01.postDelayed(mTasks01, intervalKeypadeSaver);}
};
(10)定义mTasks02,设置每1秒运行一次屏保程序,并隐藏原有Layout上面的Widget,并调用ScreenSaver()加载图片,即轮换显示预设的5幅图片,具体代码如下所示。/* Screen Saver Runnable */
private Runnable mTasks02 = new Runnable()
{public void run() {if(bIfRunScreenSaver==true){intCounter2++;hideOriginalLayout();showScreenSaver();//Log.i("HIPPO", "Counter2:"+Integer.toString(intCounter2));mHandler02.postDelayed(mTasks02, intervalScreenSaver);}else{mHandler02.removeCallbacks(mTasks02);}}
};
(11)定义mTasks03,通过setAlpha设置ImageView的透明度渐暗下去,具体代码如下所示。/* Fade Out特效Runnable */
private Runnable mTasks03 = new Runnable()
{public void run() {if(bIfRunScreenSaver==true && bFadeFlagOut==true){intCounter3++;/* 设置ImageView的透明度渐暗下去 */mImageView01.setAlpha(255-intCounter3*28);Log.i("HIPPO", "Fade out:"+Integer.toString(intCounter3));mHandler03.postDelayed(mTasks03, intervalFade);}else{mHandler03.removeCallbacks(mTasks03);}}
};
(12)定义mTasks03,通过setAlpha设置设置ImageView的透明度渐亮起来,具体代码如下所示。/* Fade In特效Runnable */
private Runnable mTasks04 = new Runnable()
{public void run() {if(bIfRunScreenSaver==true && bFadeFlagIn==true){intCounter4++;/* 设置ImageView的透明度渐亮起来 */mImageView01.setAlpha(intCounter4*28);mHandler04.postDelayed(mTasks04, intervalFade);Log.i("HIPPO", "Fade In:"+Integer.toString(intCounter4));}else{mHandler04.removeCallbacks(mTasks04);}}
};
(13)先定义recoverOriginalLayout()方法,用于恢复原有的Layout可视性;然后定义hideOriginalLayout()方法,用于隐藏原有应用程序里的布局配置组件,具体代码如下所示。/* 恢复原有的Layout可视性 */
private void recoverOriginalLayout()
{mTextView01.setVisibility(View.VISIBLE);mEditText01.setVisibility(View.VISIBLE);mImageView01.setVisibility(View.GONE);
}
/* 隐藏原有应用程序里的布局配置组件 */
private void hideOriginalLayout()
{/* 将欲隐藏的Widget写在此 */mTextView01.setVisibility(View.INVISIBLE);mEditText01.setVisibility(View.INVISIBLE);
}/* 开始ScreenSaver */
private void showScreenSaver()
{/* 屏幕保护之后要做的事件写在此*/if(intDrawable>4){intDrawable = 0;}DisplayMetrics dm=new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(dm);screenWidth = dm.widthPixels;screenHeight = dm.heightPixels;Bitmap bmp=BitmapFactory.decodeResource(getResources(),screenDrawable[intDrawable]);
(14)通过Matrix设置比例,使用Matrix.postScale设置维度ReSize,通过resizedBitmap对象设置图文件至屏幕分辨率,新建Drawable对象myNewBitmapDrawable用于放大图文件至全屏幕,通过setVisibility(View.VISIBLE)使ImageView可见,具体代码如下所示。/* Matrix比例 */ float scaleWidth = ((float) screenWidth) / bmp.getWidth();float scaleHeight = ((float) screenHeight) / bmp.getHeight() ;Matrix matrix = new Matrix(); /* 使用Matrix.postScale设置维度ReSize */ matrix.postScale(scaleWidth, scaleHeight);/* ReSize图文件至屏幕分辨率 */Bitmap resizedBitmap = Bitmap.createBitmap(bmp,0,0,bmp.getWidth(),bmp.getHeight(),matrix,true);/* 新建Drawable放大图文件至全屏幕 */BitmapDrawable myNewBitmapDrawable = new BitmapDrawable(resizedBitmap); mImageView01.setImageDrawable(myNewBitmapDrawable);/* 使ImageView可见 */mImageView01.setVisibility(View.VISIBLE);/* 每间隔设置秒数置换图片ID,于下一个runnable2才会生效 */if(intCounter2%intSecondsToChange==0){intDrawable++;}
}
(15)定义方法onUserWakeUpEvent(),实现解锁和加密处理,具体代码如下所示。public void onUserWakeUpEvent()
{if(bIfRunScreenSaver==true){try{/* LayoutInflater.from取得此Activity的context */mInflater01 = LayoutInflater.from(example.this);/* 创建解锁密码使用View的Layout */mView01 = mInflater01.inflate(R.layout.securescreen, null);/* 于对话框中唯一的EditText等待输入解锁密码 */mEditText02 =(EditText) mView01.findViewById(R.id.myEditText2);/* 创建AlertDialog */new AlertDialog.Builder(this).setView(mView01).setPositiveButton("OK",new DialogInterface.OnClickListener(){public void onClick(DialogInterface dialog, int whichButton){/* 比较输入的密码与原Activity里的设置是否相符 */if(mEditText01.getText().toString().equals(mEditText02.getText().toString())){/* 当密码正确才解锁屏幕保护装置 */resetScreenSaverListener();}}}).show();}catch(Exception e){e.printStackTrace();}}}
(16)定义方法updateUserActionTime(),用于统计用户单击键盘或屏幕的时间间隔,具体实现流程如下所示。第一步:取得单击按键事件时的系统Time Millis。
第二步:重新计算单击按键距离上一次静止的时间间距。
方法updateUserActionTime()的具体代码如下所示。public void updateUserActionTime()
{/* 取得单击按键事件时的系统Time Millis */Date timeNow = new Date(System.currentTimeMillis());/* 重新计算单击按键距离上一次静止的时间间距 */timePeriod =(long)timeNow.getTime() - (long)lastUpdateTime.getTime();lastUpdateTime.setTime(timeNow.getTime());
}
(17)定义方法resetScreenSaverListener()来重新设置屏幕,具体实现流程如下所示。第一步:删除现有的Runnable。
第二步:取得单击按键事件时的系统Time Millis。
第三步:重新计算单击按键距离上一次静止的时间间距。
第四步:通过bIfRunScreenSaver取消屏保。
第五步:恢复原来的Layout Visible。
方法resetScreenSaverListener()的具体代码如下所示。public void resetScreenSaverListener()
{/* 删除现有的Runnable */mHandler01.removeCallbacks(mTasks01);mHandler02.removeCallbacks(mTasks02);/* 取得单击按键事件时的系统Time Millis */Date timeNow = new Date(System.currentTimeMillis());/* 重新计算单击按键距离上一次静止的时间间距 */timePeriod =(long)timeNow.getTime() - (long)lastUpdateTime.getTime();lastUpdateTime.setTime(timeNow.getTime());/* for Runnable2,取消屏幕保护 */bIfRunScreenSaver = false;/* 重置Runnable1与Runnable1的Counter */intCounter1 = 0;intCounter2 = 0;/* 恢复原来的Layout Visible*/recoverOriginalLayout();/* 重置postDelayed()的Runnable */mHandler01.postDelayed(mTasks01, intervalKeypadeSaver);
}
(18)定义onKeyDown(int keyCode, KeyEvent event),用于监听用户的触摸单击事件,具体代码如下所示。@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{// TODO Auto-generated method stubif(bIfRunScreenSaver==true && keyCode!=4){/* 当屏幕保护程序正在运行中,触动解除屏幕保护程序 */onUserWakeUpEvent();}else{/* 更新User未触动手机的时间戳记 */updateUserActionTime();}return super.onKeyDown(keyCode, event);
}
@Override
public boolean onTouchEvent(MotionEvent event)
{// TODO Auto-generated method stubif(bIfRunScreenSaver==true){/* 当屏幕保护程序正在运行中,触动解除屏幕保护程序 */onUserWakeUpEvent();}else{/* 更新User未触动手机的时间戳记 */updateUserActionTime();}return super.onTouchEvent(event);
}@Override
protected void onResume()
{// TODO Auto-generated method stubmHandler01.postDelayed(mTasks01, intervalKeypadeSaver);super.onResume();
}
(19)定义方法onPause()来删除正在运行中的运行线程mHandler01、mHandler02、mHandler03和mHandler01,具体代码如下所示。@Overrideprotected void onPause(){// TODO Auto-generated method stubtry{/* 删除运行中的运行线程 */mHandler01.removeCallbacks(mTasks01);mHandler02.removeCallbacks(mTasks02);mHandler03.removeCallbacks(mTasks03);mHandler04.removeCallbacks(mTasks04);}catch(Exception e){e.printStackTrace();}super.onPause();}
}

至此,整个实例介绍完毕。执行后如果超过5秒不动键盘或屏幕,则会进入屏保状态,如图22-2所示。可以设置屏保密码,当输入正确的密码后才能解除屏保,如图22-3所示。

在本实例的实现代码中,声明的4个Runnable是整个程序的重点,这4个Runnable的具体说明如下所示。

mTasks01:设置每1秒检查一次timePeriod,并监视是否超过5秒未触发。超过5秒则将blRunScreenSaver这个flag更改为true,并启动mTasks02。
mTasks02:设置每1秒运行一次屏保程序,并隐藏原有Layout上面的Widget,并调用ScreenSaver()加载图片,即轮换显示预设的5幅图片。
mTasks03:是Fade-Out特效使用的Runable,每0.1秒运行一个scale。
mTasks04:是Fade-In特效使用的Runable,每0.1秒运行一个scale。

《精通Android 5 多媒体开发》——第22章,第22.3节开发一个屏保程序相关推荐

  1. From .1:从屏保到Win平台开发 - 一个可运行的C#屏保程序

    有一天在微信里看见了微软的Fluent Design系统(腾讯翻译为浸流设计系统)界面设计的一张图片,觉得非常好看,顿时想,这么好看的界面,如果能是一个屏保该有多好.这样的话,用户坐在电脑前也不会忍心 ...

  2. 用python开发一个背单词软件-python实现屏保程序(适用于背单词)

    今天要给大家分享的是一款自己写的屏保程序,大学大家最头疼的就是四六级的考试了,上次考试做阅读的时候,情不自禁的发呆,想着如果我能在电脑上写一个屏保程序,那么就可以天天记单词了! 开始 首先:我们使用的 ...

  3. 《精通Android 5 多媒体开发》——第6章,第6.1节视频系统结构

    本节书摘来自异步社区<精通Android 5 多媒体开发>一书中的第6章,第6.1节视频系统结构,作者 王石磊,更多章节内容可以访问云栖社区"异步社区"公众号查看 6. ...

  4. 《精通Android 5 多媒体开发》——第6章,第6.2节分析硬件抽象层

    本节书摘来自异步社区<精通Android 5 多媒体开发>一书中的第6章,第6.2节分析硬件抽象层,作者 王石磊,更多章节内容可以访问云栖社区"异步社区"公众号查看 6 ...

  5. 《精通Android 5 多媒体开发》——第1章,第1.1节智能手机系统介绍

    本节书摘来自异步社区<精通Android 5 多媒体开发>一书中的第1章,第1.1节1.1 智能手机系统介绍,作者 王石磊,更多章节内容可以访问云栖社区"异步社区"公众 ...

  6. 《精通Android 5 多媒体开发》——第6章,第6.3节实现Overlay硬件抽象层

    本节书摘来自异步社区<精通Android 5 多媒体开发>一书中的第6章,第6.3节实现Overlay硬件抽象层,作者 王石磊,更多章节内容可以访问云栖社区"异步社区" ...

  7. 《Unity 3D 游戏开发技术详解与典型案例》——1.3节第一个Unity 3D程序

    本节书摘来自异步社区<Unity 3D 游戏开发技术详解与典型案例>一书中的第1章,第1.3节第一个Unity 3D程序,作者 吴亚峰 , 于复兴,更多章节内容可以访问云栖社区" ...

  8. Android下屏保程序的开发

    2019独角兽企业重金招聘Python工程师标准>>> 有时候,需要在程序中实现屏保相关的功能,如指定一段时间后,显示自定义的屏保画面,网上查了很多资料,大多讲得不详细,或者说不完整 ...

  9. Android Framework 电源子系统(05)核心方法updatePowerStateLocked分析-3 更新屏保  发送通知  更新wakelock

    该系列文章总纲链接:专题分纲目录 Android Framework 电源子系统 本章关键点总结 & 说明: 本章节主要关注➕ updatePowerStateLocked 方法中 更新屏保 ...

最新文章

  1. Hadoop集群中增加与ElasticSearch连接的操作
  2. Codeforces-868C. Qualification Rounds(状压)
  3. ▲教你如何轻易的做linux计划任务▲——小菜一碟
  4. Win10_MySQL环境搭建以及Navicat的使用全解
  5. 在html中横坐标是纵坐标,excel 作图中次横坐标及次纵坐标的调试,以及excel自定义轴标签的步骤方法...
  6. android sqlite更改数据,更新现有的sqlite数据库中的列,但没有任何更改android
  7. my eclipse 类似dreamweaver编辑html,8款替代Dreamweaver的开源网页开发工具
  8. KubeEdge 1.3.0 部署
  9. 95-190-028-源码-window-Window介绍与使用md
  10. vue webapp滑动事件_js_监听移动端web触屏事件_滑动响应
  11. 高数叔c语言课件,高数叔网课资源合集 高数上下、线代、模电、物理、复变合集...
  12. matlab 画散点图后添加趋势线
  13. ab并发测试post请求传参
  14. 在ios10+的safair中实现视频的自动播放
  15. 程序员离职后跳槽到国企,每天主动加班到10点,结果试用期没过?
  16. python图片保存_Python中读取,显示,保存图片的方法
  17. MySQL学习笔记:过滤数据+数据过滤
  18. visio中如何画线条或箭头
  19. lightoj1219Mafia
  20. 软件可靠性分析方法有失效模式影响分析法、严酷度分析法、故障树分析法、事件树分析法、潜在线路分析法

热门文章

  1. 新零售是什么?新零售电商平台如何选择?
  2. 【CSS 网格布局 (Grid Layout )】
  3. 鼎捷T100事务控制
  4. 一语道破天机 三国中十句最精辟的话
  5. Web字体(【iconfont.cn】引用在线字体)@font-face属性的使用以及字体格式详解
  6. 环信3.0添加聊天表情包
  7. java毕业设计——基于java+TCP+UDP的局域网聊天室系统设计与实现(毕业论文+程序源码)——局域网聊天室系统
  8. MySql基础知识、存储引擎与常用数据类型
  9. docker安装Elasticsearch-7.6.1
  10. 收集那些一生难忘的记忆片段