方法一:
思路:为了模仿替换效果,首先个图片设置一张背景颜色,然后再分别准备三张纯色的红,黄,绿图片.当可用内存的比例小于等于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;
}
}