Android开发之自动更换壁纸
Posted CrazyCodeBoy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android开发之自动更换壁纸相关的知识,希望对你有一定的参考价值。
本程序主要实现了:
1.使用AssetManager将assets目录中的文件复制到SD卡的指定位置
2.使用AlarmManager全局定时器,周期性的启动指定组件切换壁纸
3.使用SharedPreferences,将用户个性化的设置保存到手机(例如壁纸切换频率)
4.使用自定义标题栏
5.使用了GestureDetector手势检测器,允许用户滑动切屏
6.使用了overridePendingTransition,在切屏的时候有动画效果
程序运行效果图:
程序代码:
ChangeWallpaper.java:
package com.jph.changewallpaper;
import java.io.File;
import com.jph.util.Const;
import com.jph.util.CopyFolder;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.OnGestureListener;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.CompoundButton;
import android.widget.ImageButton;
import android.widget.Toast;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ToggleButton;
/**
* Describe:</br>
* </br>帮你换壁纸
* </br>本程序主要实现了:
* </br>1.使用AssetManager将assets目录中的文件复制到SD卡的指定位置
* </br>2.使用AlarmManager全局定时器,周期性的启动指定组件切换壁纸
* </br>3.使用SharedPreferences,将用户个性化的设置保存到手机(例如壁纸切换频率)
* </br>4.使用自定义标题栏
* </br>5.使用了GestureDetector手势检测器,允许用户滑动切屏
* </br>6.使用了overridePendingTransition,在切屏的时候有动画效果
* </br>@author jph
* </br>Date:2014.08.05 *
* */
public class ChangeWallpaper extends Activity implements OnGestureListener
//定义手势检测器实例
GestureDetector detector;
// 定义AlarmManager对象
AlarmManager alarmManager;
ToggleButton btnSwitch;
ImageButton btnSetting;
Intent intent;
PendingIntent pi;
//表示是不是第一次使用该应用
boolean isFirstUse;
//是不开启了自动切换壁纸
boolean isLaunch;
//壁纸切换别的频率
int frequency;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
//设置自定义标题栏标志 ,该语句必须放在setContentView之前
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.main);
//设置自定义标题栏,改句必须放在setContentView之后
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.title);
btnSwitch=(ToggleButton)findViewById(R.id.btnSwitch);
btnSetting=(ImageButton)findViewById(R.id.btnSetting);
btnSetting.setOnClickListener(listener);
//初始化手势检测器
detector=new GestureDetector(this,this);
// 指定启动ChangeService组件
intent = new Intent(ChangeWallpaper.this,ChangeService.class);
// 创建PendingIntent对象
pi=PendingIntent.getService(ChangeWallpaper.this, 0, intent, 0);
//获取系统的AlarmManager对象
alarmManager=(AlarmManager)getSystemService(Service.ALARM_SERVICE);
//初始化程序配置
iniApp();
btnSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener()
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
// TODO Auto-generated method stub
isLaunch=isChecked;
if (isChecked)
launchChangeService();
else
// 取消对pi的调度
alarmManager.cancel(pi);
);
//启动切换壁纸
protected void launchChangeService()
// TODO Auto-generated method stub
// 设置每隔5秒执行pi代表的组件一次
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP
, 0, frequency, pi);
Toast.makeText(ChangeWallpaper.this, "壁纸定时更换启动成功啦",
Toast.LENGTH_SHORT).show();
OnClickListener listener=new OnClickListener()
@Override
public void onClick(View v)
// TODO Auto-generated method stub
switch (v.getId())
case R.id.btnSetting:
showSetting();
break;
default:
break;
;
//初始化应用,如果第一次使用,则将asset下的壁纸拷贝到SD卡上
private void iniApp()
// TODO Auto-generated method stub
//获取系统的SharedPreferences对象
SharedPreferences preferences=getSharedPreferences("config", MODE_PRIVATE);
//获取配置文件中的isFirstUse
isFirstUse=preferences.getBoolean("isFirstUse", true);
//获取配置文件中的frequency切换频率,默认五秒
frequency=preferences.getInt(Const.SETING_FREQUENCY_Str, 5000);
if (isFirstUse) //如果第一次使用,则将asset下的壁纸拷贝到SD卡上
//如果手机插入了SD卡,且程序有读取SD卡的权限
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
//获取手机SD卡的目录
File sdCardDir=Environment.getExternalStorageDirectory();
String path=null;
try
path=sdCardDir.getCanonicalPath()+File.separator+"wallpaper";
catch (Exception e)
// TODO Auto-generated catch block
e.printStackTrace();
CopyFolder cf=new CopyFolder(ChangeWallpaper.this, "wpics", path);
cf.start();//启动线程
//显示程序设置界面
protected void showSetting()
// TODO Auto-generated method stub
//启动设置界面
Intent intent=new Intent(ChangeWallpaper.this, SettingActivity.class);
startActivityForResult(intent,Const.REQUESTCODE_FOR_SETTING);
//设置切换动画,从右边进入,左边退出
overridePendingTransition(R.anim.right_in, R.anim.left_out);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
// TODO Auto-generated method stub
switch (requestCode)
case Const.REQUESTCODE_FOR_SETTING://如果从设置界面返回
if (isLaunch) //如果已经启动了自动且换壁纸
//获取配置信息
iniApp();
launchChangeService();
break;
default:
break;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
// TODO Auto-generated method stub
switch (keyCode)
case KeyEvent.KEYCODE_MENU://当按下菜单键跳转到设置界面
showSetting();
break;
default:
break;
return super.onKeyDown(keyCode, event);
@Override
public boolean onCreateOptionsMenu(Menu menu)
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.change_wallpaper, menu);
return true;
@Override
public boolean onTouchEvent(MotionEvent event)
// TODO Auto-generated method stub
//将触碰事件交给GestureDetector处理
return detector.onTouchEvent(event);
@Override
public boolean onDown(MotionEvent e)
// TODO Auto-generated method stub
return false;
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY)
// TODO Auto-generated method stub
//如果想右滑动的距离大于50mm
if (e1.getX()-e2.getX()>50)
showSetting();
return false;
@Override
public void onLongPress(MotionEvent e)
// TODO Auto-generated method stub
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY)
// TODO Auto-generated method stub
return false;
@Override
public void onShowPress(MotionEvent e)
// TODO Auto-generated method stub
@Override
public boolean onSingleTapUp(MotionEvent e)
// TODO Auto-generated method stub
return false;
ChangeService.java(ChangeService切换壁纸类):
package com.jph.changewallpaper;
import java.io.File;
import java.util.ArrayList;
import com.jph.util.CopyFolder;
import android.app.Service;
import android.app.WallpaperManager;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.IBinder;
import android.widget.Toast;
/**
* Describe:</br>
* </br>ChangeService切换壁纸类
* </br>获取SD卡的指定指定目录下的图片
* </br>使用WallpaperManager来更换当前壁纸
* </br>@author jph
* </br>Date:2014.08.05 *
* */
public class ChangeService extends Service
//定义一个存放图片名的数组
String []fileNames;
//定义一个存放图片路径的集合
ArrayList<String>picPaths=new ArrayList<String>();
// 定义系统的壁纸管理服务
WallpaperManager wManager;
// 定义当前所显示的壁纸
int current = 0,flag=0;
//创建一个CopyFolder类的对象
CopyFolder cf=null;
public ChangeService()
// TODO Auto-generated constructor stub
super();
@Override
public void onCreate()
// TODO Auto-generated method stub
super.onCreate();
//初始化WallpaperManager
wManager = WallpaperManager.getInstance(this);
if (picPaths.isEmpty()) //如果picPaths中还没有照片
getPicPath();
flag++;
Toast.makeText(ChangeService.this, "flag:"+flag,Toast.LENGTH_SHORT).show();
System.out.println("==========================");
System.out.println( "flag:"+flag);
@Override
public int onStartCommand(Intent intent, int flags, int startId)
// TODO Auto-generated method stub
System.out.println("==========================");
System.out.println( "onStartCommand:"+flag);
// 如果到了最后一张,系统重新开始
if(current >picPaths.size())
current = 0;
try
//将指定路径的图片转换成bitmap
Bitmap bitmap=BitmapFactory.decodeFile(picPaths.get(current++).toString());
// 改变壁纸
wManager.setBitmap(bitmap);
catch (Exception e)
e.printStackTrace();
return START_STICKY;
//从SD卡的根目录下的wallpaper文件夹中读出图片路径到picPaths集合中
public void getPicPath()
System.out.println("==========================");
System.out.println( "getPicPath:"+flag);
//如果手机插入了SD卡,且程序有读取SD卡的权限
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
//获取手机SD卡的目录
File sdCardDir=Environment.getExternalStorageDirectory();
String path=null;
try
path=sdCardDir.getCanonicalPath()+File.separator+"wallpaper";
catch (Exception e)
// TODO Auto-generated catch block
e.printStackTrace();
File file=new File(path);
fileNames=file.list();
//如果wallpaper目录不存在或为空则将assets目录下的壁纸复制到wallpaper目录下
if (fileNames==null||fileNames.length==0)
if (cf==null)
cf=new CopyFolder(ChangeService.this, "wpics", path);
cf.start();//启动线程
picPaths.clear();//清空集合中的数据
for (String picName:fileNames)
if (isPicture(picName))
//将图片的完整路径添加到picPaths中
picPaths.add(path+File.separator+picName);
/**
* 判断文件类型是否为图片
* @param fileName String 用于判断的文件名
* @return boolean
* */
public boolean isPicture(String fileName)
//存放图片格式的数组
String []limit=new String[]".png",".jpg",".gif",".jpeg" +
".bmp",".PNG",".JPG",".GIF",".JPEG",".BMP";
for (String str:limit)
if (fileName.endsWith(str)) //如果指定文件名为以上其中一种格式则返回true
return true;
return false;
@Override
public IBinder onBind(Intent intent)
// TODO Auto-generated method stub
return null;
SettingActivity.java(设置菜单界面类)
package com.jph.changewallpaper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.jph.util.Const;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.view.GestureDetector.OnGestureListener;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleAdapter;
/**
* Describe:</br>
* </br>设置菜单界面类
* </br>将用户个性化的设置保存到SharedPreferences中
* </br>@author jph
* </br>Date:2014.08.05
* */
public class SettingActivity extends Activity implements OnGestureListener
private AlertDialog dialog;
private AlertDialog.Builder builder;
ListView list;
//设置菜单标题
String []itemTitles;
//设置菜单图标
int []itemIcos;
//壁纸切换频率
String frequencyString;
//定义手势检测器实例
GestureDetector detector;
@Override
protected void onCreate(Bundle savedInstanceState)
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.setting);
//初始化手势检测器
detector=new GestureDetector(this,this);
list=(ListView)findViewById(R.id.list);
//初始化ListView
initList();
private void initList()
// TODO Auto-generated method stub
//获取itemTitles.xml中的选项标题和图标
itemTitles=getResources().getStringArray(R.array.itemTitles);
itemIcos=new int[]R.drawable.setting_fre,R.drawable.setting_fs
,R.drawable.setting_redefault,R.drawable.setting_abuot;
List<Map<String,Object>>listItems=new ArrayList<Map<String,Object>>();
for (int i = 0; i < itemTitles.length; i++)
Map<String, Object>listItem=new HashMap<String, Object>();
listItem.put("imgItemIco", itemIcos[i]);
listItem.put("txtItemTitle", itemTitles[i]);
listItems.add(listItem);
SimpleAdapter adapter=new SimpleAdapter(SettingActivity.this,listItems,
R.layout.line, new String[]"imgItemIco","txtItemTitle",
new int[]R.id.imgItemIco,R.id.txtItemTitle);
list.setAdapter(adapter);
list.setOnItemClickListener(new OnItemClickListener()
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id)
// TODO Auto-generated method stub
switch (position)
case 0:
//设置壁纸切换的屏幕
setFrequency();
break;
case 1:
displayPattern();
break;
case 2:
break;
case 3:
about();
break;
default:
break;
);
//设置壁纸的显示方式
protected void displayPattern()
// TODO Auto-generated method stub
final String item[]=new String[]"平铺","拉伸","裁切","默认";
DialogInterface.OnClickListener sListener=new DialogInterface.OnClickListener()
public void onClick(DialogInterface dialog, int which)
frequencyString=item[which];
;
builder=new AlertDialog.Builder(this);
builder.setSingleChoiceItems(item, -1, sListener);
dialog=builder.create();
dialog.setTitle("请设置壁纸显示方式");
//创建按键监听器
DialogInterface.OnClickListener listener=new DialogInterface.OnClickListener()
public void onClick(DialogInterface dialog, int which)
if(which==DialogInterface.BUTTON_POSITIVE)
//按下确定
dialog.dismiss();
if (frequencyString.endsWith("秒"))
frequencyString=frequencyString.replace("秒", "");
//将String转换成int
int frequency=Integer.parseInt(frequencyString)*1000;
alterConfig(Const.SETING_FREQUENCY,frequency);
else if (frequencyString.endsWith("分钟"))
frequencyString=frequencyString.replace("分钟", "");
//将String转换成int
int frequency=Integer.parseInt(frequencyString)*1000*60;
alterConfig(Const.SETING_FREQUENCY,frequency);
else if(which==DialogInterface.BUTTON_NEGATIVE)//按下取消
dialog.dismiss();
;
dialog.setButton(DialogInterface.BUTTON_POSITIVE, "确定",listener);
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消",listener);
dialog.show();
//关于
protected void about()
// TODO Auto-generated method stub
LayoutInflater inflater=LayoutInflater.from(this);
LinearLayout layout=(LinearLayout) inflater.inflate(R.layout.about, null);
AlertDialog dialog=new AlertDialog.Builder(SettingActivity.this).create();
dialog.setTitle("关于");
dialog.setIcon(R.drawable.smile);
dialog.setView(layout);
dialog.show();
//设置显示频率
protected void setFrequency()
// TODO Auto-generated method stub
final String item[]=new String[]"3秒","5秒","10秒","20秒","30秒","1分钟","5分钟","10分钟";
DialogInterface.OnClickListener sListener=new DialogInterface.OnClickListener()
public void onClick(DialogInterface dialog, int which)
frequencyString=item[which];
;
builder=new AlertDialog.Builder(this);
builder.setSingleChoiceItems(item, -1, sListener);
dialog=builder.create();
dialog.setTitle("请设置壁纸切换的频率");
//创建按键监听器
DialogInterface.OnClickListener listener=new DialogInterface.OnClickListener()
public void onClick(DialogInterface dialog, int which)
if(which==DialogInterface.BUTTON_POSITIVE)
//按下确定
dialog.dismiss();
if (frequencyString.endsWith("秒"))
frequencyString=frequencyString.replace("秒", "");
//将String转换成int
int frequency=Integer.parseInt(frequencyString)*1000;
alterConfig(Const.SETING_FREQUENCY,frequency);
else if (frequencyString.endsWith("分钟"))
frequencyString=frequencyString.replace("分钟", "");
//将String转换成int
int frequency=Integer.parseInt(frequencyString)*1000*60;
alterConfig(Const.SETING_FREQUENCY,frequency);
else if(which==DialogInterface.BUTTON_NEGATIVE)//按下取消
dialog.dismiss();
;
dialog.setButton(DialogInterface.BUTTON_POSITIVE, "确定",listener);
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消",listener);
dialog.show();
//修改配置文件
protected void alterConfig(int flag, int frequency)
// TODO Auto-generated method stub
SharedPreferences preferences=getSharedPreferences("config", MODE_PRIVATE);
//获取SharedPreferences对应的Editor
Editor editor=preferences.edit();
switch (flag)
case Const.SETING_FREQUENCY:
editor.putInt(Const.SETING_FREQUENCY_Str, frequency);
break;
default:
break;
editor.commit();
@Override
public boolean onTouchEvent(MotionEvent event)
// TODO Auto-generated method stub
//将触碰事件交给GestureDetector处理
return detector.onTouchEvent(event);
@Override
public boolean onDown(MotionEvent e)
// TODO Auto-generated method stub
return false;
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY)
// TODO Auto-generated method stub
//如果向左滑动距离大于50mm
if (e2.getX()-e1.getX()>50)
Intent intent=getIntent();
setResult(Activity.RESULT_OK, intent);
this.finish();
overridePendingTransition(R.anim.left_in, R.anim.right_out);
return false;
@Override
public void onLongPress(MotionEvent e)
// TODO Auto-generated method stub
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY)
// TODO Auto-generated method stub
return false;
@Override
public void onShowPress(MotionEvent e)
// TODO Auto-generated method stub
@Override
public boolean onSingleTapUp(MotionEvent e)
// TODO Auto-generated method stub
return false;
工具类:
CopyFolder.java(复制assets中的文件到SD卡的指定位置)
package com.jph.util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
/**
* Describe:</br>
* </br>从assets项目目录中复制文件及目录
* </br>本类启用了一个新线程用于处理复制文件的耗时任务
* </br>当所有的复制完成或复制文件出错时通知UI线程
* </br>@author JPH
* </br>Date:2014.07.30
* */
public class CopyFolder extends Thread
//定义两个常量用于表示复制文件成功的标识
public final static int COPY_FALSE=0x123,COPY_SUCCESS=0x456;
String newPath,oldPath;
Context context;
public CopyFolder()
// TODO Auto-generated constructor stub
/**
* 从assets目录中复制整个文件夹内容
* @param context Context 使用CopyFiles类的Activity
* @param oldPath String 原文件路径 如:img
* @param newPath String 复制后路径 如:xx:/bb/cc
*/
public CopyFolder(Context context,String oldPath,String newPath)
this.context=context;
this.oldPath=oldPath;
this.newPath=newPath;
@Override
public void run()
// TODO Auto-generated method stub
copyFilesFassets(context,oldPath,newPath);
SharedPreferences prference=context.getSharedPreferences("config",
Context.MODE_PRIVATE);
Editor editor=prference.edit();
editor.putBoolean("isFirstUse", false);//写入使用标识
editor.commit();//最后不要忘记将存入的数据进行提交
// MainActivity.handler.sendEmptyMessage(COPY_SUCCESS);
/**
* 从assets目录中复制整个文件夹内容
* @param context Context 使用CopyFiles类的Activity
* @param oldPath String 原文件路径 如:/aa
* @param newPath String 复制后路径 如:xx:/bb/cc
*/
public void copyFilesFassets(Context context,String oldPath,String newPath)
try
String fileNames[] = context.getAssets().list(oldPath);//获取assets目录下的所有文件及目录名
if (fileNames.length > 0) //如果是目录
File file = new File(newPath);
file.mkdirs();//如果文件夹不存在,则递归
for (String fileName : fileNames)
copyFilesFassets(context,oldPath + "/" + fileName,newPath+"/"+fileName);
else //如果是文件
InputStream is = context.getAssets().open(oldPath);
FileOutputStream fos = new FileOutputStream(new File(newPath));
byte[] buffer = new byte[1024];
int byteCount=0;
while((byteCount=is.read(buffer))!=-1) //循环从输入流读取 buffer字节
fos.write(buffer, 0, byteCount);//将读取的输入流写入到输出流
fos.flush();//刷新缓冲区
is.close();
fos.close();
catch (Exception e)
// TODO Auto-generated catch block
e.printStackTrace();
//如果捕捉到错误则通知UI线程
// MainActivity.handler.sendEmptyMessage(COPY_FALSE);
Const.java(常量类:提供程序中用到的主要常量)
package com.jph.util;
/**
* Describe:</br>
* </br>常量类
* </br>提供程序中用到的主要常量
* </br>@author jph
* </br>Date:2014.08.05
* */
public class Const
//壁纸切换频率标识
public final static int SETING_FREQUENCY=0x0001;
public final static String SETING_FREQUENCY_Str="frequency";
//SettingActivity的请求码
public final static int REQUESTCODE_FOR_SETTING=0x123;
public Const()
// TODO Auto-generated constructor stub
AndroidManifest.xml配置清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jph.changewallpaper"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<!-- 在SD卡中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 向SD卡写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 授予用户修改壁纸的权限 -->
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.jph.changewallpaper.ChangeWallpaper"
android:label="@string/app_name"
android:theme="@style/style_title">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.jph.changewallpaper.SettingActivity"></activity>
<!-- 注册 ChangeService-->
<service android:name="com.jph.changewallpaper.ChangeService"></service>
</application>
</manifest>
以上是关于Android开发之自动更换壁纸的主要内容,如果未能解决你的问题,请参考以下文章
android 获取当前壁纸的Drawable对象或者Bitmap。如何获取这张图片的ID或者名称。
iOS 14 这个奇妙功能,能让你的 iPhone 壁纸自动变换