Android creates its own personalized application (4): moji-> Custom extension ZIP format skin

Source: Internet
Author: User
Tags deflater format definition

Here I will talk about the skin replacement method of moji weather, but first I declare that I just used reverse compilation and some other online materials to deduce the skin replacement principle. Here I will only give a reference. if you have a better way, please contact us.

The downloaded skin of moji weather is a zip compressed package. During the application, the skin resources are released to the directory of the moji weather application, when skin is changed, the new skin resources will replace the old skin resources. Each time the resources are loaded, the pictures are read from the hard drive of the mobile phone. The names of these image resources are consistent with those in the program, once these resources cannot be found, you can find them in the default system. This implementation directly reads external resource files and replaces the background resources on the Interface displayed by the code when the program is running. The advantage of this method is that the format definition of skin resources can be ZIP or custom at will, as long as the resources can be parsed in the program, the disadvantage is efficiency.

Here, we need to note that we can decompress the compressed package and use the third-party tool ant. jar to decompress and compress the file. I will introduce how to use the ant tool in a later article.

Main technical points:

How to read resources in a zip file and store skin files

Implementation solution: if the software reads the skin files on the SD card every time it starts, the speed will be slow. It is better to provide a skin setting interface, which skin does the user choose, decompress the skin file to the "/data/[package name]/skin" path (fast and secure reading), so that it does not need to be read across memory, and the speed is fast, it does not need to be read from the zip package every time and does not depend on the files in the SD card. Even if the files in the skin package are deleted, it does not matter.

Implementation Method:

1. You are prompted to copy the skin file to the path specified by the SD card with the help of the software or help from the official website.
2. Provide the skin setting interface in the software. It can be in the menu or in the settings. You can refer to moji, sogou input method, QQ, and other software that supports skin replacement.
3. load the skin file in the specified path, read the thumbnail, and display it on the skin settings page, decompress the selected skin file to the "/data/[package name]/skin" path.
4. The software preferentially reads Resources in the "/data/[package name]/skin/" path. If not, use the resources in the APK.

:

Code:

1. androidmanifest. xml:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.tony.skin" android:versionCode="1" android:versionName="1.0"><uses-sdk android:minSdkVersion="7" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    <application android:icon="@drawable/icon" android:label="@string/app_name">        <activity android:name=".Re_Skin2Activity"                  android:label="@string/app_name">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>

2. layout file main. xml

<? 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: Background = "# d2d2d2" Android: id = "@ + ID/layout"> <button Android: text = "Import skin" Android: Id = "@ + ID/button2" Android: layout_width = "wrap_content" Android: layout_height = "wrap_content"> </button> <button Android: text = "skin change" Android: Id = "@ + ID/button1" Android: layout_width = "wrap_content" Android: layout_height = "wrap_content"> </button> <textview Android: Id = "@ + ID/textview1" Android: layout_width = "wrap_content" Android: layout_height = "wrap_content" Android: TEXT = "click" Import skin "to import/sdcard/skin.zip to the/sdcard/skin_kris directory, then, click "skin" to use the material in the sdcard as the skin. "Android: textcolor =" #000 "> </textview> </linearlayout>

3. re_skin2activity:

Package COM. tony. skin; import android. app. activity; import android. graphics. bitmap; import android. graphics. bitmapfactory; import android. graphics. drawable. bitmapdrawable; import android. OS. bundle; import android. view. view; import android. view. view. onclicklistener; import android. widget. button; import android. widget. linearlayout; import android. widget. toast; import COM. tony. skin. utils. ziputil;/***** @ author Tony **/public class re_skin2activity extends activity implements onclicklistener {private buttonbtnset; private buttonbtnimport; private linearlayout layout; /** called when the activity is first created. * // @ override public void oncreate (bundle savedinstancestate) {super. oncreate (savedinstancestate); setcontentview (R. layout. main); btnset = (button) findviewbyid (R. id. button1); btnset. setonclicklistener (this); btnimport = (button) findviewbyid (R. id. button2); btnimport. setonclicklistener (this); layout = (linearlayout) findviewbyid (R. id. layout) ;}@ overridepublic void onclick (view v) {Switch (v. GETID () {case R. id. button1: Bitmap bitmap = bitmapfactory. decodefile ("/sdcard/skin_kris/skin/google.png"); bitmapdrawable BD = new bitmapdrawable (Bitmap); btnset. setbackgrounddrawable (BD); layout. setbackgrounddrawable (New bitmapdrawable (bitmapfactory. decodefile ("/sdcard/skin_kris/skin/BG/bg.png"); break; case R. id. button2: ziputil zipp = new ziputil (2049); system. out. println ("begin do zip"); zipp. unzip ("/sdcard/skin.zip", "/sdcard/skin_kris"); toast. maketext (this, "imported successfully", toast. length_short ). show (); break; default: break ;}}}

4. Tool class for ziputil decompression and processing zip packages

Package COM. tony. skin. utils; import Java. io. bufferedoutputstream; import Java. io. file; import Java. io. fileinputstream; import Java. io. fileoutputstream; import Java. io. ioexception; import Java. io. inputstream; import Java. util. enumeration; import java.util.zip. deflater; import org.apache.tools.zip. zipentry; import org.apache.tools.zip. zipfile; import org.apache.tools.zip. zipoutputstream;/*** zip package compression, decompress the processing tool class *@ Author A **/public class ziputil {private zipfile; private zipoutputstream zipout; // zip private int bufsize; // size of bytes private byte [] Buf; private int readedbytes; public ziputil () {This (512);} public ziputil (INT bufsize) {This. bufsize = bufsize; this. buf = new byte [this. bufsize];}/***** @ Param srcfile directory or file to be compressed * @ Param destfile path of the compressed file */Public void dozip (string srcfile, String destfile) {// zipdirectorypath: name of the folder to be compressed: file zipdir; string dirname; zipdir = new file (srcfile); dirname = zipdir. getname (); try again this.zip out = new zipoutputstream (New bufferedoutputstream (New fileoutputstream (destfile); // set the compressed annotation zipout. setcomment ("comment"); // sets the compression encoding. If the path to be compressed contains Chinese characters, use the following encoding zipout. setencoding ("GBK"); // enable zipout compression. setmethod (zipoutputstream. deflated); // The compression level is the strongest, but it takes a little more time to zipout. Setlevel (Deflater. best_compression); handledir (zipdir, this.zipout,dirname?#this.zip out. close ();} catch (ioexception IOE) {IOE. printstacktrace () ;}}/*** called by dozip, recursively read the directory file * @ Param dir * @ Param zipout * @ Param dirname this is mainly used to record a directory hierarchy of the compressed file * @ throws ioexception */private void handledir (file Dir, zipoutputstream zipout, string dirname) throws ioexception {system. out. println ("traversal Directory:" + dir. getname ()); Fileinputstream filein; file [] files; Files = dir. listfiles (); If (files. length = 0) {// If the directory is empty, it is created separately. // In the isdirectory () method of zipentry, the directory ends. system. out. println ("Compressed Name:" nvidirname={this.zip out. putnextentry (New zipentry(dirname={this.zip out. closeentry ();} else {// If the directory is not empty, process the directories and files respectively. for (File filename: Files) {// system. out. println (filename); If (filename. isdirectory () {handledir (filename, this. zi Pout, dirname + file. separator + filename. getname () + file. separator);} else {system. out. println ("Compressed Name:" + dirname + file. separator + filename. getname (); filein = new fileinputstream(filename={this.zip out. putnextentry (New zipentry (dirname + file. separator + filename. getname (); While (this. readedbytes = filein. read (this. buf)> 0) Export this.zip out. write (this. buf, 0, this.readedbytes?##this.zip out. closeentry (); }}}/*** Decompress the specified ZIP file * @ Param unzipfile: Path of the compressed file * @ Param destfile to the decompressed directory */Public void unzip (string unzipfile, string destfile) {// unzipfilename the ZIP file name fileoutputstream fileout to be decompressed; file; inputstream; try restarting this.zip file = new zipfile (unzipfile); For (enumeration entries = this.zip file. getentries (); entries. hasmoreelements ();) {zipentry entry = (zipentry) entries. nextelement (); file = ne W file (destfile + file. separator + entry. getname (); If (entry. isdirectory () {file. mkdirs ();} else {// created if the directory of the specified file does not exist. file parent = file. getparentfile (); If (! Parent. exists () {parent. mkdirs ();} inputstream = zipfile. getinputstream (entry); fileout = new fileoutputstream (File); While (this. readedbytes = inputstream. read (this. buf)> 0) {fileout. write (this. buf, 0, this.readedbytes000000000000fileout.close(~~inputstream.close(~~~~this.zip file. close ();} catch (ioexception IOE) {IOE. printstacktrace () ;}/// set the buffer size public void setbufsize (INT bufsize) {This. bufsize = bufsize ;}}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.