DreamService是android已经出了很久的的特性,在设备闲置、充电或锁屏时,可以显示特定的内容。但是网上的资源不多,我自己开发了一个,希望对大家有些帮助。
实现起来很简单,首先注册
<service android:name=".DayDreamService"
android:exported="true"
android:icon="@drawable/ic_launcher"
android:label="ScreenSaver"
android:permission="android.permission.BIND_DREAM_SERVICE"
>
<intent-filter>
<action android:name="android.service.dreams.DreamService"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
一开始我使用的是ViewPager+Fragment的方式来实现,因为之前有过这样的开发,所以很容易就将思路向这里走了,但是后来经过实践发现DreamService里是实现不了Fragment的,至少我没办法实现
如果有能够通过ViewPager+Fragment的方式实现的大神希望能留言学习下。
所以我就只好通过ViewPager来实现了。
public class DayDreamService extends DreamService {
private final static String TAG = "DayDreamService";
private ViewPager viewPager;
private List<ImageView> imageViews;
private int currentItem = 0;
private MyAdapter pageAdapter;
boolean nowAction = false;// 当前用户正在滑动视图
String[] fileName = new String[0];
AssetManager manager;
private String[] imageUrls=null;
private ScheduledExecutorService scheduledExecutorService;
ImageLoader imageLoader;
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
setInteractive(false);
setFullscreen(true);
setContentView(R.layout.mydream);
configImageLoader();
init();
}
//退出的时候干掉自己哈哈哈哈
@Override
public void onDetachedFromWindow(){
super.onDetachedFromWindow();
viewPager = null;
manager = null;
imageLoader = null;
imageViews = null;
scheduledExecutorService=null;
imageUrls=null;
fileName=null;
pageAdapter=null;
System.exit(0);
android.os.Process.killProcess(android.os.Process.myPid());
Log.d(TAG, "onDetachedFromWindow");
}
@SuppressLint("HandlerLeak")
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
viewPager.setCurrentItem(currentItem);
};
};
//获取目录下的图片的绝对路径
@SuppressWarnings("finally")
public String[] getImageName(Context context, String loc) {
String prefix = "";
try {
if (loc.equalsIgnoreCase("screen")) {
manager = context.getAssets();
fileName = manager.list(loc);
prefix = "assets://screen/";
} else {
File f = new File(loc);
fileName = f.list();
prefix = "file:///data/local/tmp/image/";
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fileName!=null){
for (int i = 0; i < fileName.length; i++) {
fileName[i] = prefix + fileName[i];
}
}
return fileName;
}
}
@Override
public void onDreamingStarted() {
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
//20秒换一图
scheduledExecutorService.scheduleAtFixedRate(new ScrollTask(), 20, 20, TimeUnit.SECONDS);
super.onDreamingStarted();
}
private class ScrollTask implements Runnable {
public void run() {
synchronized (viewPager) {
if (!nowAction) {
System.out.println("currentItem: " + currentItem);
currentItem = currentItem + 1;
handler.obtainMessage().sendToTarget();
}
}
}
}
private class MyPageChangeListener implements OnPageChangeListener {
public void onPageSelected(int position) {
currentItem = position;
}
public void onPageScrollStateChanged(int arg0) {
if (arg0 == 0) {
nowAction = false;
}
if (arg0 == 1) {
nowAction = true;
}
if (arg0 == 2) {
}
}
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
}
public void init() {
//首先获取/data/local/tmp/image/目录下的图片,如果没有就获取screen里的默认图片
imageUrls = getImageName(this, "/data/local/tmp/image/");
if (imageUrls==null||imageUrls.length==0) {
imageUrls = getImageName(this, "screen");
}
imageViews = new ArrayList<ImageView>();
for (int i = 0; i < imageUrls.length; i++) {
// ImageView imageView = new ImageView(this);
ImageView imageView = (ImageView) LayoutInflater.from(this).inflate(R.layout.view_banner, null);
ImageLoader.getInstance().displayImage(imageUrls[i], imageView);
// imageView.setImageResource(imageResId[i]);
imageView.setScaleType(ScaleType.CENTER_CROP);
imageViews.add(imageView);
}
viewPager = (ViewPager) findViewById(R.id.vp);
pageAdapter = new MyAdapter();
viewPager.setCurrentItem(Integer.MAX_VALUE / 4);
viewPager.setAdapter(pageAdapter);
// 切换动画实现淡入淡出效果
viewPager.setPageTransformer(true, new DepthPageTransformer());
// 设置滑动切换时间
try {
Field mScroller = null;
mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
FixedSpeedScroller scroller = new FixedSpeedScroller(viewPager.getContext());
scroller.setScrollDuration(1500);
mScroller.set(viewPager, scroller);
} catch (NoSuchFieldException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
viewPager.setOnPageChangeListener(new MyPageChangeListener());
}
//ViewPager的Adapter
private class MyAdapter extends PagerAdapter {
@Override
public int getCount() {
//定义一个极大的数,实现伪无线循环
return Integer.MAX_VALUE / 2;
}
@Override
public Object instantiateItem(View arg0, int position) {
View view = null;
if (position % imageViews.size() < 0) {
view = imageViews.get(imageViews.size() + position);
} else {
view = imageViews.get(position % imageViews.size());
}
ViewParent vp = view.getParent();
if (vp != null) {
ViewGroup parent = (ViewGroup) vp;
parent.removeView(view);
}
((ViewPager) arg0).addView(view);
return view;
}
@Override
public void destroyItem(View arg0, int arg1, Object arg2) {
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
}
//configImageLoader框架,用来管理和处理图片
private void configImageLoader() {
// 初始化ImageLoader
@SuppressWarnings("deprecation")
DisplayImageOptions options = new DisplayImageOptions.Builder().showStubImage(R.drawable.ic_launcher) // 设置图片下载期间显示的图片
// .showImageForEmptyUri(R.drawable.ic_launcher) //
// 设置图片Uri为空或是错误的时候显示的图片
.showImageOnFail(R.drawable.icon) // 设置图片加载或解码过程中发生错误显示的图片
.bitmapConfig(Bitmap.Config.RGB_565) // 图片太多的时候设置 ,避免内存溢出和解码失败
//.cacheInMemory(true) // 设置下载的图片是否缓存在内存中
//.cacheOnDisc(true) // 设置下载的图片是否缓存在SD卡中
// .displayer(new RoundedBitmapDisplayer(20)) // 设置成圆角图片
.build(); // 创建配置过得DisplayImageOption对象
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.defaultDisplayImageOptions(options).threadPriority(Thread.NORM_PRIORITY - 2)
.denyCacheImageMultipleSizesInMemory().discCacheFileNameGenerator(new Md5FileNameGenerator())
.tasksProcessingOrder(QueueProcessingType.LIFO).build();
ImageLoader.getInstance().init(config);
}
}
其中有几个工具类
/**
* 自定义高度的viewpapger
*/
public class BaseViewPager extends ViewPager {
private boolean scrollable = true;
public BaseViewPager(Context context) {
super(context);
}
public BaseViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* 设置viewpager是否可以滚动
*
* @param enable
*/
public void setScrollable(boolean enable) {
scrollable = enable;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (scrollable) {
return super.onInterceptTouchEvent(event);
} else {
return false;
}
}
}
/**
* 自定义的淡入淡出效果
*/
public class DepthPageTransformer implements BaseViewPager.PageTransformer {
private static final float MIN_ALPHA = 0.0f; //最小透明度
@SuppressLint("NewApi")
public void transformPage(View view, float position) {
int pageWidth = view.getWidth(); //得到view宽
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left. 出了左边屏幕
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
if (position < 0) {
//消失的页面
view.setTranslationX(-pageWidth * position); //阻止消失页面的滑动
} else {
//出现的页面
view.setTranslationX(pageWidth); //直接设置出现的页面到底
view.setTranslationX(-pageWidth * position); //阻止出现页面的滑动
}
// Fade the page relative to its size.
float alphaFactor = Math.max(MIN_ALPHA, 1 - Math.abs(position));
//透明度改变Log
view.setAlpha(alphaFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right. 出了右边屏幕
view.setAlpha(0);
}
}
}
/**
* 自定义的Scroller
*/
public class FixedSpeedScroller extends Scroller {
private int mDuration = 1000;
public void setScrollDuration(int duration){
this.mDuration = duration;
}
public FixedSpeedScroller(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public FixedSpeedScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}
public void setmDuration(int time) {
mDuration = time;
}
public int getmDuration() {
return mDuration;
}
}
xml ..
最后向assets里面建立个screen文件夹,里面放上几张图就ok了 大功告成。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#00FFFFFF"
android:orientation="vertical" >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</LinearLayout>
最后向assets里面建立个screen文件夹,里面放上几张图就ok了 大功告成。
但是一运行发现应用的内存占用太大了
,就循环播几张图片而已,居然要整整50+m的内存,真是醉了,估摸着是android-support-v4.jar 和 universal-image-loader-1.9.2-SNAPSHOT-with-sources.jar 两个的问题,干脆就不用ViewPager和configImageLoader了,自己思考了一下需求,只是个图片的轮播罢了,直接就是一个ImageView,然后一个Handler不断的替换图片就ok了,由于DreamService只要一操作,就回退出屏保状态,所以就无所谓按键控制了。没必要搞那么多幺蛾子不是吗
。
public class DayDreamService extends DreamService {
private final static String TAG = "DayDreamService";
private int currentItem = 0;
String[] fileName = new String[0];
AssetManager manager;
private String[] imageUrls = null;
AssetManager assetManager = null;
ImageView imageView = null;
Bitmap oldbmp = null;
int time = 20 * 1000;// 切图时间
Boolean flag = false;// 是否加载的是默认图片
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
setInteractive(false);
setFullscreen(true);
setContentView(R.layout.mydream);
Log.d(TAG, "qidong");
init();
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
manager = null;
imageUrls = null;
fileName = null;
System.exit(0);
android.os.Process.killProcess(android.os.Process.myPid());
}
@SuppressWarnings("finally")
public String[] getImageName(Context context, String loc) {
String prefix = "";
try {
if (loc.equalsIgnoreCase("screen")) {
manager = context.getAssets();
fileName = manager.list(loc);
// prefix = "assets://screen/";
prefix = "screen/";
} else {
File f = new File(loc);
fileName = f.list();
prefix = "/data/local/tmp/image/";
f = null;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileName != null) {
for (int i = 0; i < fileName.length; i++) {
fileName[i] = prefix + fileName[i];
}
}
return fileName;
}
}
@Override
public void onDreamingStarted() {
super.onDreamingStarted();
}
public void init() {
imageUrls = getImageName(this, "/data/local/tmp/image/");
if (imageUrls == null || imageUrls.length == 0) {
flag = true;
imageUrls = getImageName(this, "screen");
}
fileName = null;
imageView = (ImageView) findViewById(R.id.iv_pb);
assetManager = this.getAssets();
setimage();
handler.postDelayed(task, time);
}
public void setimage() {
// 把历史的ImageView 图片对象(imageView)释放
BitmapDrawable bitmapDrawable = (BitmapDrawable) imageView.getBackground();
if (bitmapDrawable != null) {
Bitmap hisBitmap = bitmapDrawable.getBitmap();
if (hisBitmap.isRecycled() == false) {
hisBitmap.recycle();
}
}
// 设置自动清理的参数使得Bitmap占用的内存不再是1280*720*4而是1280*720*2 一下子就减了一半
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
// 切换图片
try {
Bitmap bmp = null;
if (flag) {
InputStream in = assetManager.open(imageUrls[currentItem % imageUrls.length]);
bmp = BitmapFactory.decodeStream(in, null, options);
//要是内存还是占用太大就就直接自己改分辨率吧,会降低清晰度,但是大大减小内存
// bmp=decodeSampledBitmapFromResource(in, 768,432);
} else {
Log.d(TAG, "uri:" + imageUrls[currentItem % imageUrls.length]);
InputStream in = new FileInputStream(imageUrls[currentItem % imageUrls.length]);
bmp = BitmapFactory.decodeStream(in,null,options);
// bmp=decodeSampledBitmapFromResource(in, 960,540);
}
if (oldbmp == null) {
oldbmp = bmp;
}
Drawable[] layers = new Drawable[2];
layers[0] = new BitmapDrawable(oldbmp);
layers[1] = new BitmapDrawable(bmp);
oldbmp = bmp;
if (currentItem == 0) {
imageView.setImageBitmap(bmp);
} else {
TransitionDrawable transitionDrawable = new TransitionDrawable(layers);
imageView.setImageDrawable(transitionDrawable);
transitionDrawable.startTransition(400);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private Handler handler = new Handler();
private Runnable task = new Runnable() {
public void run() {
// TODOAuto-generated method stub
handler.postDelayed(this, time);// 设置延迟时间
// 需要执行的代码
currentItem++;
setimage();
}
};
/*public static Bitmap decodeSampledBitmapFromResource(InputStream is, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(is, null, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
Log.d(TAG, "height:" + height + " width" + width);
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
Log.d(TAG, "height inSampleSize:" + inSampleSize);
return inSampleSize;
}*/
}
他的xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#00FFFFFF"
android:orientation="vertical" >
<!--
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
-->
<ImageView
android:id="@+id/iv_pb"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
再将原来1920p的图片换成1280p的之后,内存终于降到了10M,这下终于是彻底完成了 。