动画效果之360桌面清除动画(一)

方法一:

思路:为了模仿替换效果,首先个图片设置一张背景颜色,然后再分别准备三张纯色的红,黄,绿图片.当可用内存的比例小于等于50%的时候,显示绿色图片背景;当可用内存比例在50%到75%之间的时候,显示黄色图片背景;当可用内存比例大于75%显示红色背景图片.这种方法是通过画布Canvas的clipRect()加上Handler+Message机制实现的.

在这个程序中不经意间发现了内存泄露的问题,问题原因是多线程的问题.下面会阐述.

首先看正确 的代码

public class MainActivity extends Activity {
	private ImageView img;
	private Bitmap bmp_full;
	private Bitmap bmp_mid;
	private Bitmap bmp_min;
	private int num = 1;
	private boolean isFinished = true;
	private static final int START = 1;
	private Handler handler = new Handler() {
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case START:
				int number = (Integer) msg.obj;
				if (number <= 50) {
					img.setImageBitmap(getBitmap(bmp_min, number));
				} else if (number > 50 && number <= 75) {
					img.setImageBitmap(getBitmap(bmp_mid, number));
				} else if (number > 75 && number <= 100) {
					img.setImageBitmap(getBitmap(bmp_full, number));
				}
				isFinished = true;
				break;
			}
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		setContentView(R.layout.activity_main);
		img = (ImageView) findViewById(R.id.img);
		bmp_full = BitmapFactory.decodeResource(getResources(),
				R.drawable.taskmanager_circle_full);
		bmp_mid = BitmapFactory.decodeResource(getResources(),
				R.drawable.taskmanager_circle_mid);
		bmp_min = BitmapFactory.decodeResource(getResources(),
				R.drawable.taskmanager_circle_min);

		System.out.println("run");
		new Anima().start();
		super.onCreate(savedInstanceState);
	}

	class Anima extends Thread {

		@Override
		public void run() {
			while (num <= 100) {
				System.out.println("run isFinished=" + isFinished);
				if (isFinished) {
					isFinished = false;
					System.out.println("num = " + num);
					Message msg = new Message();
					msg.what = START;
					msg.obj = num;
					num++;
					handler.sendMessage(msg);
					
				}
			}
		}

	}

	private Bitmap getBitmap(Bitmap bit, int percent) {
		Bitmap bitmap = Bitmap.createBitmap(bit.getWidth(), bit.getHeight(),
				Config.ARGB_8888);
		Paint paint = new Paint();
		paint.setAntiAlias(true);
		Canvas canvas = new Canvas(bitmap);
		canvas.drawARGB(0, 0, 0, 0);
		canvas.rotate(-180, bit.getWidth() / 2, bit.getHeight() / 2);
		canvas.clipRect(0, 0, bit.getWidth(), bit.getHeight() * percent / 100);
		canvas.drawBitmap(bit, 0, 0, paint);
		
		return bitmap;
	}
}


问题现象:如果子线程要写成如下,则会发生背景图片在替换的过程中,会在某个不确定的比例值上停止

class Anima extends Thread {

		@Override
		public void run() {
			while (num <= 100) {
				System.out.println("run isFinished=" + isFinished);
				if (isFinished) {
				         Message msg = new Message();
					msg.what = START;
					msg.obj = num;
					num++;
					handler.sendMessage(msg);
					isFinished = false;
				}
			}
		}

	}


 由于是通过布尔值isFinished来判断每次发出的消息是已经更新完毕了.如果把isFinished = false写在最后,就会出现内存的泄露,造成开启的子线程不停的执行,不可控.

原因:当消息发出去后,CPU的执行权被UI线程抢占,handleMessage()捕获到消息后,进行一系列的更新,并将布尔值isFinished置为true,表示更新完毕,可以发下一个消息了.

在UI线程将isFinished置为true后,子线程抢占了CPU的执行权,这时候,接着上面的执行isFinished=false;这时候问题就产生了.

解决办法:将子线程中的isFinished的布尔值的改变在判断后就立即改变就可以避免

 ===================================================================

方法二,自定义一个view对象,然后重写其onDraw()方法,然后每次重写onDraw()的时候调用invalidate()即可.

但是这个demo存在两个问题.1,每次都重写,效率有点低.2,动画的效果是从右到左,使用canvas.rotate()方法显示的效果还是达不到要求.如果有哪位有比较好的方法,请留言

下面贴出自定义View代码:

public class MyView extends View {
	private float current;
	private float expire;
	private float temp;
	private boolean isFinished = true;
	
	
	private Handler handler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			invalidate();
			isFinished = true;
		};
	};
	private Timer timer;
	private TimerTask task;
	public MyView(Context context,float current,float expire) {
		super(context);
		this.expire = expire;
		this.current = current;
		temp = current;
	}
	public MyView(Context context) {
		super(context);
	}
	
	public MyView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public MyView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		Paint paint = new Paint();
		paint.setAntiAlias(true);
		if(temp > 0 && temp <=50){
			paint.setColor(Color.GREEN);
		}else if(temp > 50 && temp <=75){
			paint.setColor(Color.YELLOW);
		}else if(temp > 75 && temp <=100){
			paint.setColor(Color.RED);
		}
		canvas.drawColor(Color.BLACK);
		canvas.drawRect(0, 0, temp, expire, paint);
		new Anima().start();
		super.onDraw(canvas);
	}
	
	private void getAnima(){
		timer = new Timer();
		task = new TimerTask() {
			@Override
			public void run() {
				while(true){
					if(isFinished){
						System.out.println("temp = "+temp);
						isFinished = false;
						temp--;
						if(temp < 0){
							if(timer != null){
								timer.cancel();
								timer = null;
							}
							if(task != null){
								task.cancel();
								task = null;
							}
							return;
						}
						Message msg = new Message();
						msg.obj = temp;
						
						handler.sendMessage(msg);
					}
				}
			}
		};
	}
	private class Anima extends Thread{
		@Override
		public void run() {
			while(true){
				if(isFinished){
					System.out.println("temp = "+temp);
					isFinished = false;
					temp--;
					if(temp < 0){
						return;
					}
					Message msg = new Message();
					msg.obj = temp;
					
					handler.sendMessage(msg);
				}
			}
		}
	}
	
	public float getCurrent() {
		return current;
	}
	public void setCurrent(float current) {
		this.current = current;
	}
	public float getExpire() {
		return expire;
	}
	public void setExpire(float expire) {
		this.expire = expire;
	}
	public float getTemp() {
		return temp;
	}
	public void setTemp(float temp) {
		this.temp = temp;
	}
	

}


 

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值