自从Android 2.1中加入了动态壁纸,一下子牛叉了很多啊,漂亮的壁纸层出不穷,看上去老土的Android手机总算也是可以炫一下了。
动态壁纸基础
制作方法,网上太多了,虽然基本都是抄的,其实都是从sample上发展出来的,我也把要点记一下,每次写新的都要把老的工程打开看,啥记性……
- res/xml中指定动态壁纸的xml文件:
<?xml version="1.0" encoding="utf-8"?> <wallpaper xmlns:android="http://schemas.android.com/apk/res/android" android:settingsActivity="xxx.yyy.LiveWallpaperSettings" android:thumbnail="@drawable/icon" />
这里是说明自己图标和设定Activity。
- 还有一个设定Activity的xml文件,就是普通的PreferenceScreen,省略。
- 创建WallpaperService的子类,需要再onCreateEngine方法中返回一个Engine,Engine中画画儿,就像用SurfaceView一样。
public class LiveWallpaper extends WallpaperService { public static final String SHARED_PREFS_NAME = "setting_file_name"; @Override public void onCreate() { super.onCreate(); } @Override public void onDestroy() { super.onDestroy(); } @Override public Engine onCreateEngine() { return new TestPatternEngine(); } class TestPatternEngine extends Engine implements SharedPreferences.OnSharedPreferenceChangeListener { private final Handler mHandler = new Handler(); private final Runnable mDrawPattern = new Runnable() { public void run() { drawFrame(); } }; private boolean mVisible; private SharedPreferences mPreferences; TestPatternEngine() { mPreferences = LiveWallpaper.this.getSharedPreferences( SHARED_PREFS_NAME, 0); mPreferences.registerOnSharedPreferenceChangeListener(this); onSharedPreferenceChanged(mPreferences, null); } public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { } @Override public void onCreate(SurfaceHolder surfaceHolder) { super.onCreate(surfaceHolder); } @Override public void onDestroy() { super.onDestroy(); mHandler.removeCallbacks(mDrawPattern); } @Override public void onVisibilityChanged(boolean visible) { mVisible = visible; if (visible) { drawFrame(); } else { mHandler.removeCallbacks(mDrawPattern); } } @Override public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { super.onSurfaceChanged(holder, format, width, height); drawFrame(); } @Override public void onSurfaceCreated(SurfaceHolder holder) { super.onSurfaceCreated(holder); } @Override public void onSurfaceDestroyed(SurfaceHolder holder) { super.onSurfaceDestroyed(holder); mVisible = false; mHandler.removeCallbacks(mDrawPattern); } @Override public void onOffsetsChanged(float xOffset, float yOffset, float xStep, float yStep, int xPixels, int yPixels) { drawFrame(); } void drawFrame() { final SurfaceHolder holder = getSurfaceHolder(); Canvas c = null; try { c = holder.lockCanvas(); if (c != null) { // draw something } } finally { if (c != null) holder.unlockCanvasAndPost(c); } mHandler.removeCallbacks(mDrawPattern); if (mVisible) { mHandler.postDelayed(mDrawPattern, 1000 / 25); } } } }
- 还有设定Activity的实现:
public class LiveWallpaperSettings extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener { @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); getPreferenceManager().setSharedPreferencesName(LiveWallpaper.SHARED_PREFS_NAME); addPreferencesFromResource(R.xml.livewallpaper_settings); getPreferenceManager().getSharedPreferences() .registerOnSharedPreferenceChangeListener(this); } @Override protected void onResume() { super.onResume(); } @Override protected void onDestroy() { getPreferenceManager().getSharedPreferences() .unregisterOnSharedPreferenceChangeListener(this); super.onDestroy(); } public void onSharedPreferenceChanged( SharedPreferences sharedPreferences, String key) { } }
- androidmanifest.xml中一定要加入的:
<service android:name=".LiveWallpaper" android:label="@string/app_name" android:icon="@drawable/icon"> <intent-filter> <action android:name="android.service.wallpaper.WallpaperService" /> </intent-filter> <meta-data android:name="android.service.wallpaper" android:resource="@xml/livewallpaper" /> </service> <activity android:label="@string/livewallpaper_settings" android:name=".LiveWallpaperSettings" android:theme="@android:style/Theme.Light.WallpaperSettings" android:exported="true" android:icon="@drawable/icon"> </activity> <uses-sdk android:minSdkVersion="7" /> <uses-feature android:name="android.software.live_wallpaper" />
“uses-feature android:name=”android.software.live_wallpaper””这句话要慎用啊!Google的电子市场会认这句话,然后把有些可以用的机器过滤掉,比如俺的破机器,本来是不支持的,升级到2.1按说是可以用的。我看了市场上很多有名的动态壁纸,就没有加这句话~~
另外,如果想在动态壁纸中使用OpenGL ES,请参考这篇文章:Android中使用OpenGL ES的一二事。
加入AdMob广告
上面都是废话,我这次想说的主题是如何在壁纸设定界面里加入AdMob广告,好不容易做好的东西,总是要意思意思是吧,加个广告是没法的事情了。
不同于一般的Activity,直接加入AdMob是不行的,连个Layout都没有,而且直接加到壁纸上则非常糟糕,谁也不希望好好的背景上塞一个广告。所以一般动态壁纸的广告都加在设置界面里,这样还真有些不容易。
一般有两种方法,把Admob的adView当做一个Preference,直接加入xml就好。
public class AdmobPreference extends Preference { public AdmobPreference(Context context) { super(context, null); } public AdmobPreference(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected View onCreateView(ViewGroup parent) { //override here to return the admob ad instead of a regular preference display LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); return inflater.inflate(R.layout.admob_preference, null); } }
相对的admob_preference的配置:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/ad_layout" android:layout_width="fill_parent" android:layout_height="fill_parent"> <com.google.ads.AdView xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads" android:id="@+id/ad" android:layout_width="fill_parent" android:layout_height="wrap_content" ads.adSize="BANNER" ads:adUnitId="a14e51ca560d266" ads:loadAdOnCreate="true" /> </LinearLayout>
这里还是有些学问的,网上查一下会有无数的“AdView missing required XML attribute ‘adSize’”的问题,据说是4.1.0之后带来的问题,一定要这么写(将”http://schemas.android.com/apk/lib/com.google.ads”当做一个命名空间,而不是加入自己的程序中)才能不出错,至少大家是如此说的,可惜我不行,怎么写都有这个错,耗费了两个小时尝试了各种写法,还是不行啊!!最后还是写在代码里了:(
不过光这么写貌似还是不行,AdView周围还有留白,貌似是PreferenceActivity里的padding,去不掉,最后还是使用了Tab的方式:
public class SettingsTabActivity extends TabActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.table_layout); TabHost tabHost = getTabHost(); // The activity TabHost TabHost.TabSpec spec; // Resusable TabSpec for each tab Intent intent; // Reusable Intent for each tab // Create an Intent for the regular live wallpaper preferences activity intent = new Intent().setClass(this, LivePaperSettings.class); // Initialize a TabSpec and set the intent spec = tabHost.newTabSpec("TabTitle").setContent(intent); spec.setIndicator("TabTitle"); tabHost.addTab(spec); tabHost.setCurrentTab(0); }
对应的layout:
<?xml version="1.0" encoding="utf-8"?> <TabHost xmlns:android="http://schemas.android.com/apk/res/android" xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads" android:id="@android:id/tabhost" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:orientation="vertical" android:id="@+id/main_layout" android:layout_width="fill_parent" android:layout_height="fill_parent"> <com.google.ads.AdView android:id="@+id/ad" android:layout_width="fill_parent" android:layout_height="wrap_content" ads:backgroundColor="#000000" ads:primaryTextColor="#FFFFFF" ads:secondaryTextColor="#CCCCCC" ads.adSize="BANNER" ads:adUnitId="a14e51ca560d266" ads:loadAdOnCreate="true" /> <TabWidget android:id="@android:id/tabs" android:layout_width="fill_parent" android:layout_height="1dp" android:visibility="invisible" /> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="1dp" /> </LinearLayout> </TabHost>
大概就是如此了。
对了还有一个浪费了我两个多小时的问题,对于已经按照的live wallpaper,你修改了setting的Activity,直接覆盖安装是没效果的,点配置还是出现以前的Activity,发现这一点之前,我做了不知几百次修改上传,都快整挂了,Google怎么考虑的?!
出现AdView missing required XML attribute ‘adSize’是因为ads:adSize=”BANNER”打错成ads.adSize=”BANNER” , 但不了解, 已按了方法使用. 但广告都出不来.
@8888: 传上来写错了……这种弱智错误Eclipse会告诉我的。。
能把代码发给我吗?805858226@qq.com
谢谢!
如果博主通过tabactivity间接的启动preferenceActivity,但是在wallperpar中那个设置acitivity只能是一个preference的activity!这个问题怎么解决呢!
有可能在自己的activity中启动WallpaperService吗?
感谢楼主的分享。楼主你不妨尝试下keymob平台。keymob平台支持的开发平台多、丰富多样化的广告形式、还有丰富的广告资源。并且还能顺利通过市场审核,还不用担心被封号。这些都是keymob平台的优势支持。你想了解更多的信息请登入keymob平台官网进行了解。平台地址:www.keymob.com