今天在做开发的时候发现一个奇怪的问题,我使用Timer和Handler配合更新UI界面,Timer每隔一段时间执行一次,发送一次消息,然后Handler接受后更新UI,并在这里使用了动画效果。代码如下:
package com.example.handlerdemo;import java.util.Timer;import java.util.TimerTask;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.app.Activity;import android.view.Menu;import android.view.View;import android.view.animation.AccelerateInterpolator;import android.view.animation.TranslateAnimation;import android.widget.ImageView;import android.widget.TextView;public class MainActivity extends Activity { private int animCount = -1; Timer timer = new Timer(true); Message message; TextView tv_1, tv_2, tv_3, tv_4, tv_5; private static Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv_1 = (TextView) this.findViewById(R.id.tv_1); tv_2 = (TextView) this.findViewById(R.id.tv_2); tv_3 = (TextView) this.findViewById(R.id.tv_3); tv_4 = (TextView) this.findViewById(R.id.tv_4); tv_5 = (TextView) this.findViewById(R.id.tv_5); animPost(); } private void animPost() { // new Thread() { // public void run() { // // // while (animCount < 5) { // // try { // // Message message = handler.obtainMessage(); // // message.arg1 = animCount; // // handler.sendMessage(message); // // animCount++; // // Thread.sleep(2000); // // // // } catch (InterruptedException e) { // // e.printStackTrace(); // // } // // // } // }.start(); handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 0: if (animCount == 0) { startAnimation(tv_1); } else if (animCount == 1) { startAnimation(tv_2); } else if (animCount == 2) { startAnimation(tv_3); } else if (animCount == 3) { startAnimation(tv_4); } else if (animCount == 4) { startAnimation(tv_5); } break; } super.handleMessage(msg); } }; TimerTask task = new TimerTask() { @Override public void run() { // TODO Auto-generated method stub if (message == null) { message = new Message(); } else { message = Message.obtain(); } message.what = 0; handler.sendMessage(message); animCount = animCount + 1; System.out.print(animCount); } }; timer.schedule(task, 0, 3000); } // 左右摆动 private void startAnimation(View paramView) { TranslateAnimation localTranslateAnimation = new TranslateAnimation(2, 0.0F, 2, -0.05F, 1, 0.0F, 1, 0.0F); localTranslateAnimation.setDuration(1000); localTranslateAnimation.setInterpolator(new AccelerateInterpolator()); localTranslateAnimation.setRepeatCount(1); // paramView.setAnimation(localTranslateAnimation); // localTranslateAnimation.start(); paramView.startAnimation(localTranslateAnimation);//这个方式没有问题 } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; }}结果动画只是执行了一遍,开始我以为是使用Timer以及Handler逻辑的问题,换了几个方案都不行。最后无奈,试着从动画入手,改一下动画的启动方式。开始用的是
paramView.setAnimation(localTranslateAnimation);localTranslateAnimation.start();这个方法,这是组件设置动画效果,然后动画开始启动。当然还有组件启动动画的方式,我就试着换这种,发现问题解决了。那到底是什么原因导致的呢?搜了一下,网上没有这方面的资料。那只能去看api了。
从图可知,startAnimmation是立即执行的。也就是说,我们调用了这个方法,动画马上就会执行。而setAnimmation的执行是需要两个先决条件的:
1、动画要设置一个开始时间
2、执行动画的组件的父视图在动画启动之前需要刷新界面。
而我们就是因为没有满足这两个条件,所以出现了问题。
- 1楼zx1989989113小时前
- 您好,我刚才结合源代码发现有两点疑问想请教下:n1.你说的setAnimmation的执行是需要两个先决条件的的第二条貌似翻译有点问题吧,我的翻译是“组件在打算开始动画之前其父组件需要被刷新”n2.你之前说的那种所谓错误的动画启动方式应该是不满足第二个条件,你看源码就发现其实是满足第一个条件的。如果按照setAnimation()设置动画,其实去看startAnimation()原理发现下面这种方式也是正确的:nparamView.setAnimation(localTranslateAnimation);nlocalTranslateAnimation.start();nparamView.invalidate();nparamView.requestLayout();nn仅供参考,如有错误或者不对的可以多多交流哈。。。
- Re: wangjinyu5013小时前
- 回复zx19899891n嗯,你说得对,昨天invalidate这个单词翻译错了,把我自己也弄迷糊了。看你一说恍然大悟,谢谢你的提醒,多多交流。