- 浏览: 2186955 次
文章分类
最新评论
android动态壁纸--美女报时
主要功能就是: 每分钟更换一张背景图片达到报时的功能,提前30S准备壁纸 每到一分钟时画图。
本打算用多线程实现但是貌似多线程调度出现了点问题,所以改用单线程实现(因为这个壁纸程序比较简单只是每分钟更换一下壁纸没有其他特效单线程实现应该问题不大)
1.首先壁纸程序配置 AndroidManifest.xml
功能:告诉系统设置壁纸时启动的service 和壁纸程序settingActivity的配置文件wallpaper.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.clock" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="10" /> <!--添加权限--> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.GET_TASKS" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <!-- 壁纸程序配置service --> <service android:name="com.clock.PicService" android:permission="android.permission.BIND_WALLPAPER" > <intent-filter> <action android:name="android.service.wallpaper.WallpaperService" /> </intent-filter> <meta-data android:name="android.service.wallpaper" android:resource="@xml/wallpaper" /> </service> <!-- 壁纸程序配置activity --> <activity android:name=".MmClockActivity" android:label="@string/app_name" android:launchMode="singleTask"> <intent-filter> <action android:name="android.intent.action.MAIN" /> </intent-filter> </activity> </application> </manifest>2.接下来建立一个xml文件夹 建立wallpaper.xml
功能:配置点击settingActivity时启动的Activity
<?xml version="1.0" encoding="utf-8"?> <wallpaper xmlns:android="http://schemas.android.com/apk/res/android" android:thumbnail="@drawable/icon" android:description="@string/hello" android:settingsActivity="com.clock.MmClockActivity" />3.壁纸程序设置时的activity界面布局文件main.xml
功能:界面内容 显示声明 可编辑文本框和一个“设置路径”按钮点击时弹出一个Dialog选择路径
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:weightSum="1"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" android:layout_weight="0.04" android:textSize="20dp"/> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/statement" android:layout_weight="0.27" android:textSize="20dp"/> <RelativeLayout android:layout_width="match_parent" android:id="@+id/relativeLayout1" android:layout_height="wrap_content"> <EditText android:layout_height="wrap_content" android:layout_width="fill_parent" android:id="@+id/editText1" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_toLeftOf="@+id/setImgPath"></EditText> <Button android:id="@+id/setImgPath" android:layout_width="wrap_content" android:text="@string/setPath" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignParentRight="true"></Button> </RelativeLayout> </LinearLayout>4.设置页面中点击“设置路径”按钮时弹出的对话框布局文件dialog.xml
功能:很简单只有一个listActivity
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:weightSum="1"> <ListView android:id="@+id/listView1" android:layout_height="fill_parent" android:layout_width="fill_parent" android:layout_alignParentTop="true" android:layout_alignParentLeft="true"></ListView> </RelativeLayout>5.壁纸程序的配置activity类 MmClockActivity.class
功能:显示声明 弹出Dialog遍历文件夹(单击进入遍历子文件夹 ,长按设置路径关闭Dialog)把路径写入配置文件
package com.clock; import java.io.File; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.EditTextPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceActivity; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import android.widget.ListView; /** * 显示声明和设置图片路径 * @author Administrator * */ public class MmClockActivity extends Activity { private Button setBtn;//设置路径按钮 private EditText editText;// private File currentDirectory = new File("/");//当前路径 private ListView m_ListView;//显示列表 private Dilg dlg;//对话框 private List<String> pathList;//路径列表 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);//布局文件 setBtn=(Button) findViewById(R.id.setImgPath); editText=(EditText)findViewById(R.id.editText1); setBtn.setOnClickListener(new btnListener()); // editText.setText("/sdcard/time");//默认值 readSharedPreferences();//读取配置文件 } @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); /* 按返回键时保存数据 */ SharedPreferences uiState = getSharedPreferences("pathConfig", MODE_WORLD_READABLE); SharedPreferences.Editor editor = uiState.edit();// 取得编辑对象 editor.putString("imgPath",editText.getText().toString());// 添加值 editor.commit();// 提交保存 PicService.mHandler.sendEmptyMessage(31);//向主线程发送消息通知壁纸路径已经更改 } /** * 读取配置文件 */ public void readSharedPreferences(){ SharedPreferences settings = getSharedPreferences("pathConfig", MODE_WORLD_READABLE); editText.setText(settings.getString("imgPath", "/")); if( editText.getText().toString().equals("/")) editText.setText("/sdcard/time"); } /** * 继承对话框类 * @author Administrator * */ class Dilg extends Dialog{ public Dilg(Context context) { super(context); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); pathList=new ArrayList<String>(); setContentView(R.layout.dialog); m_ListView=(ListView)this.findViewById(R.id.listView1); m_ListView.setAdapter(new ArrayAdapter<String>(this.getContext(), android.R.layout.simple_expandable_list_item_1,pathList)); //添加点击监听(点击进入下一目录) m_ListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { if(arg2==0){ upOneLevel();//返回上一目录 }else{ File clickedFile = null; if(currentDirectory.getAbsolutePath().toString().endsWith("/")) clickedFile = new File(currentDirectory.getAbsolutePath()+pathList.get(arg2)); else{ clickedFile = new File(currentDirectory.getAbsolutePath()+"/"+pathList.get(arg2)); } if(clickedFile != null) browseTo(clickedFile);//浏览点击文件夹的子目录 } } }); //添加长按点击监听(长按设置路径,关闭对话框) m_ListView.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { if(arg2!=0){ if(currentDirectory.getAbsolutePath().toString().endsWith("/")) editText.setText(currentDirectory.getAbsolutePath()+pathList.get(arg2));//显示当前路径 else{ editText.setText(currentDirectory.getAbsolutePath()+"/"+pathList.get(arg2)); } dlg.dismiss();//关闭对话框 } return false; } }); } } class btnListener implements OnClickListener{ @Override public void onClick(View arg0) { dlg=new Dilg(MmClockActivity.this); dlg.show();//显示对话框 browseToRoot();//浏览根目录 } } //浏览文件系统的根目录 private void browseToRoot() { browseTo(new File("/")); } //返回上一级目录 private void upOneLevel() { if(this.currentDirectory.getParent() != null) this.browseTo(this.currentDirectory.getParentFile()); } //浏览指定的目录,如果是文件则进行打开操作 private void browseTo(final File file) { if(dlg!=null){ dlg.setTitle(file.getAbsolutePath()); } if (file.isDirectory()) { this.currentDirectory = file; fill(file.listFiles());//遍历file的子列表 } } //这里可以理解为设置ListActivity的源 private void fill(File[] files) { List<String> pathListTemp=null;//路径列表(临时) if(pathList.size()>0){ pathListTemp=pathList;//保存到临时缓存 pathList.removeAll(pathList); pathList.add("../返回上一层"); } try { for (File currentFile : files) { //判断是一个文件夹还是一个文件 if (currentFile.isDirectory()) { if(!currentFile.isHidden())//不是隐藏文件夹 pathList.add(currentFile.getName()); } }//重新设置适配器(更新ListView显示内容) } catch (Exception e) { pathList=pathListTemp;//出错赋值回去 Toast.makeText(getApplicationContext(), "没有权限打开这个文件夹", Toast.LENGTH_SHORT).show(); e.printStackTrace(); } m_ListView.setAdapter(new ArrayAdapter<String>(dlg.getContext(), android.R.layout.simple_expandable_list_item_1,pathList)); } }6.接下来是壁纸程序的重点Service类PicService.clsass
功能:读取配置文件中设置的图片路径,30S初始化图片 1分钟显示图片 DiceEngine为自定义壁纸引擎画图及控制时间线程(实际是一个线程)都是在这个壁纸引擎类中完成的是壁纸程序的核心。public void onVisibilityChanged(boolean visible)方法是壁纸显示状态改变时的回调函数,利用此函数控制时间线程(diceThread不是真正的启动一个线程
,从打印出的线程id就可以看出。本来想新开一个时间线程但是有点问题就是壁纸程序二次启动时holder.lockCanvas()得不到Canvs总是null因为某些原因不能再研究这个程序了,等有时间在研究吧!!希望高人能够解决这个问题真正做到多线程)
package com.clock; import java.io.InputStream; import java.util.Calendar; import com.clock.util.ReadImage; import android.content.Context; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Rect; import android.os.Handler; import android.os.Message; import android.service.wallpaper.WallpaperService; import android.util.DisplayMetrics; import android.view.SurfaceHolder; /** * 画壁纸 调度时间线程 * @author Administrator * */ public class PicService extends WallpaperService{ private Context mContext = PicService.this;//上下文环境 public static String hour="0";//小时 public static int min=0;//分钟 public static int second=0;//秒 public static Handler mHandler;//处理线程间的消息 private static ReadImage readImage;//读取图片工具 private static int screenHigh=0;//屏幕高度 private static int screenWidth=0;//屏幕宽度 private static String imgPath="";//图片路径 private static Bitmap backBmp;//背景图片 @Override public Engine onCreateEngine() { return new DiceEngine(); } @Override public void onCreate() { super.onCreate(); DisplayMetrics dm2 = getResources().getDisplayMetrics(); screenHigh=dm2.heightPixels; screenWidth=dm2.widthPixels;//取屏幕宽度 readImage=new ReadImage(); readSharedPreferences(); } /** * 读取配置文件 */ public void readSharedPreferences(){ SharedPreferences settings = getSharedPreferences("pathConfig", MODE_WORLD_READABLE); imgPath=settings.getString("imgPath", "/"); if(imgPath.equals("/")) imgPath="/sdcard/time"; } /** * 重写壁纸引擎类 * @author Administrator * */ public class DiceEngine extends Engine{ private float xoffset=0;//壁纸滑动时的偏移量 private String picName="";//图片名称 private Boolean isCreate=true;//时间线程是不是刚创建的 //handler和线程,这个线程主要用来画图 private Handler mHandler2 = new Handler(getMainLooper()); private Thread diceThread = new Thread(){ private int createTime;//创建时间 private int currnetMin;//当前取到的分钟 private int currentHour;//当前的小时 public void run(){ Calendar c=Calendar.getInstance(); currentHour=c.get(Calendar.HOUR_OF_DAY); if(currentHour<10){ PicService.hour="0"+currentHour; }else{ PicService.hour=currentHour+""; } currnetMin=c.get(Calendar.MINUTE); PicService.second=c.get(Calendar.SECOND); if(isCreate){//第一次运行 System.out.println("启动时的秒数 "+PicService.second+"----启动id=="+Thread.currentThread().getId()); createTime=PicService.second;//记录线程创建时的秒数 PicService.min=currnetMin; initBack(0); draw(); }else{ if(PicService.second==30){//提前30秒准备下一张壁纸 System.out.println("TimeThread-->"+Thread.currentThread().getId()); PicService.min=currnetMin; initBack(30); } if(createTime>=30&&currnetMin!=PicService.min){//线程启动时>30秒的情况 PicService.min=currnetMin; initBack(0); draw(); createTime=0; }else if(currnetMin!=PicService.min){//一分钟了 PicService.min=currnetMin; draw(); } } isCreate=false;//运行过一次了 mHandler2.postDelayed(diceThread, 1000);//延时1000毫秒加入到队列 } }; //构造 public DiceEngine(){ registMessage();//实例化Handler } /** * 实例化本线程的Handler监听发送过来的消息 */ public void registMessage(){ mHandler = new Handler() { @Override public void handleMessage(Message msg) {//收到线程消息时的回到函数 switch(msg.what){ case 31://读取配置文件得到配置路径 readSharedPreferences();//读取配置文件 break; } } }; } /** * 初始化背景图片 * */ public void initBack(int state){ int tempMin;//临时变量用存放30秒时的下一分钟 if(backBmp != null){ if (!backBmp.isRecycled()){ backBmp.recycle(); } } if(state==30){ if(min==59) tempMin=0;//30秒提前准备下一分钟的壁纸 else{ tempMin=min+1; } if(tempMin<10){ picName=hour+"0"+tempMin; }else{ picName=hour+tempMin; } System.out.println("30s准备------id="+Thread.currentThread().getId()); }else{//不是30秒的情况 if(min<10){ picName=hour+"0"+min; }else{ picName=hour+min; } System.out.println("即时准备------id="+Thread.currentThread().getId()); } backBmp = readBmp(readImage.getPicture(picName+".jpg", imgPath)); } /** * 优化内存 读取图片 * */ public Bitmap readBmp(InputStream is){ BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inPreferredConfig = Bitmap.Config.RGB_565; opt.inPurgeable = true; opt.inInputShareable = true; //获取资源图片 if(is==null) is =mContext.getResources().openRawResource(R.drawable.bg); return BitmapFactory.decodeStream(is,null,opt); } /** * 所有在屏幕上画图的操作都是在这个方法中完成 * */ public void draw(){ Rect rect=new Rect();//图片剪裁区 rect.top=0;rect.left=100; rect.right=518; rect.bottom=450; Rect dest=new Rect();//屏幕剪裁区 dest.top=0;dest.left=0; dest.right=screenWidth; dest.bottom=screenHigh; System.out.println("画图---id---id== "+Thread.currentThread().getId()); SurfaceHolder holder = getSurfaceHolder(); Canvas canvas = holder.lockCanvas(); canvas.drawBitmap(backBmp, rect, dest, null);//画图 holder.unlockCanvasAndPost(canvas); } @Override public void onVisibilityChanged(boolean visible) { // TODO Auto-generated method stub super.onVisibilityChanged(visible); if(visible){ //System.out.println("显示。。"); isCreate=true; mHandler2.postDelayed(diceThread, 50);//延时50毫秒加入到队列 }else{ //System.out.println("隐藏。。"); mHandler2.removeCallbacks(diceThread); releaseRes(); } } /** * 释放资源 * */ public void releaseRes(){ if (!backBmp.isRecycled()) { backBmp.recycle(); } } } }7.读取图片的工具类ReadImage.class
package com.clock.util; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; public class ReadImage { /** * 通过指定目录返回图片输入流 * @param path * @return */ public InputStream getPicture(String fileName,String path){ //File.separator是文件分隔符 File file=new File(path + File.separator +fileName); if(file.exists()) try { return new FileInputStream(file); } catch (FileNotFoundException e) { e.printStackTrace(); return null; } else return null; } }8.strings.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">minClock</string> <string name="setPath">设置路径</string> <string name="hello">一分钟换一个背景图片,实现报时功能</string> <string name="statement">程序仅供学习交流,图片资源来自互联网如有违法请删除</string> </resources>OK 基本是所有代码了 程序比较简单 欢迎和初学android的同学交流共同进步!
源码下载地址:点击打开链接
相关推荐
导入eclipse即可运行,程序功能一分钟更换一张壁纸实现报时功能。用到的知识点 壁纸引擎 线程间通信 配置文件读写 遍历文件夹等。注释详细适合android初学者。欢迎讨论学习!
动态壁纸报时程序,项目完整注释详细导入eclipse即可运行用到的技术 壁纸引擎 线程通信 文件目录等。适合学习,android2.3版本 真机测试通过没有问题。
android动态壁纸android源码学习zhiliao开发
android-gif-drawable支持fig显示的view.zip
King's Girls 采用 RXJava Retrofit OKHttp Material Design Base Glide构建,是一款以瀑布流的形式展示美女福利的App。 Gif展示 下载 扫描二维码下载 下载地址:https://fir.im/KingsGirls 鸣谢 干货集中营 提供...
Android应用源码开发Demo,主要用于毕业设计学习。
美女视屏动态壁纸
手把手完成一个android真实实例,每一个步骤都用图示写得非常详细。
美女 CASA(高清) 写真图库每日更新,为您的 Android 装置提供 60,000 张高质素美女桌布。 特点: - 浏览超过 60,000张高清美女明星壁纸和背景 - 高清壁纸可以下载至您的 SD Card - 可按日期或下载次数排序 - ...
一个定时更新美女报时的小程序源码,一个定时更新美女报时的小程序源码,一个定时更新美女报时的小程序源码
Android美女拼图游戏
4K-8K美女车模模特动漫壁纸爬虫 4K-8K美女车模模特动漫壁纸爬虫
商业编程-源码-美女入门投票系统源码.zip
美女mm语音桌面报时,能报年月日时间,时刻提醒你下班了,注意休息的好助手.双击电脑右下角的时钟图标,即可发出悦耳的美女报时
日本最近有一个超火的美女报时网站 Bijin-tokei(美人時計),按照一天1440分钟(60×24)计算,每分钟该网站都会自动刷新, 然后不同的美女举牌报时的图片就会显示出来。短短一个月内,该网站就引来了超过2亿4千万...
古装美女壁纸20张0-20
android美女电子相册
古装美女壁纸20张20-40
多模板采集图片源码 1.内附几个不同的模板(文件夹0到3都是模板,可将任意的模板...3.GIF动态福利图片数据资源(成人福利动态图片带模板) 4.手机高清壁纸图片数据采集 5.可以做成API即可使用,内附大量图片数据资源
这个整点报时是2012年2月4日最新修改版,修改了一些冗余的软件,添加了一些新的功能