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 --><serviceandroid: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選擇路徑
功能:很簡單只有一個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;//路徑列表@Overridepublic 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);}@Overridepublic 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() { @Overridepublic 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() {@Overridepublic 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{@Overridepublic 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;//背景圖片@Overridepublic Engine onCreateEngine() {return new DiceEngine();}@Overridepublic 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);}@Overridepublic void onVisibilityChanged(boolean visible) {// TODO Auto-generated method stubsuper.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;}elsereturn 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的同學交流共同進步!
源碼下載地址:點擊打開鏈接
總結
以上是生活随笔為你收集整理的android动态壁纸--美女报时的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 现在Php、Java、Python横行霸
- 下一篇: CANoe:第5个仿真工程:仿真+测试