基于DreamService的屏保

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  ..
<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,这下终于是彻底完成了 大笑


评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值