Android:操作栏中的动画不适用于异步任务

时间:2014-07-08 22:16:56

标签: android android-asynctask android-animation

目标:在操作栏中显示连接图标。 OnClick,它应该尝试在后台连接。在尝试连接时,应该播放连接动画。然后它应该切换回“not_connected”或“connected”drawable,具体取决于成功或失败。

问题:如果我在自定义操作提供程序的onClick方法中调用代码,它可以正常工作(请参阅注释掉它的注释掉部分)。当相同的确切代码在AsyncTask的onPreExecute中时,它将不会播放(它停留在第一帧),即使我传递了对ImageView的引用。

我的设置:要在操作栏中执行框架动画,您必须使用自定义操作提供程序(请参阅animationDrawable is not playing in Actionbar?)。所以,我有一个自定义布局,一个自定义操作提供程序,它会使它膨胀并设置点击方法。我的连接功能在AsyncTask中,因此它将异步连接。

有什么想法吗?

menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/connect"
        android:showAsAction="always"
        android:title="@string/btn_connect"
        android:actionProviderClass="com.****.ConnectIconActionProvider"
        />
</menu>

布局/ connecting_animation.xml

<?xml version="1.0" encoding="utf-8"?>
 <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ivConnecting"
    style="@android:style/Widget.ActionButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_not_connected" />

动画/ connectinganimation.xml

<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
    <item android:drawable="@drawable/ic_connecting1" android:duration="300" />
    <item android:drawable="@drawable/ic_connecting2" android:duration="300" />
    <item android:drawable="@drawable/ic_connecting3" android:duration="300" />
</animation-list>

ConnectIconActionProvider.java

public class ConnectIconActionProvider extends ActionProvider {

    private Context context;
    private ImageView button; 
//  boolean toggle = false;
    private AnimationDrawable animationDrawable;

    public ConnectIconActionProvider(Context context) {
        super(context);
        this.context = context;
    }

    @Override
    public View onCreateActionView(MenuItem forItem) {

        // Inflate the action view to be shown on the action bar.
        LayoutInflater layoutInflater = LayoutInflater.from(context);
        View view = layoutInflater.inflate(R.layout.connecting_animation, null);
        button = (ImageView) view.findViewById(R.id.ivConnecting);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MyClass.toggleConnectionToDevice(button);

//              if (toggle) {
//                  button.setImageResource(R.anim.connectinganimation);
//                  animationDrawable = (AnimationDrawable) button.getDrawable();
//                  animationDrawable.start();
//              } else {
//                  button.setImageResource(R.drawable.ic_not_connected);
//                  if (animationDrawable != null) {
//                      animationDrawable.stop();
//                  }
//              }
//              toggle ^= true;
            }
        });
        return view;
    }

MyClass.toggleConnectionToDevice

public void toggleConnectionToDevice(ImageView iv) {
    if (deviceConnected) {
        (new DisconnectProgressBar(this, iv)).execute();
    } else {
        (new ConnectProgressBar(this, iv)).execute();
    }
}

ConnectProgressBar.java

public class ConnectProgressBar extends AsyncTask<Void, Void, Void> {

    private final MainActivity activity;
    private AnimationDrawable animationDrawable;
    private ImageView iv;
    private Handler handler = new Handler(Looper.getMainLooper());

    public ConnectProgressBar(final MainActivity activity, final ImageView iv) {
        this.activity = activity;
        this.iv = iv;
    }

    @Override
    protected void onPreExecute() {
        if (iv != null) {
            iv.setImageResource(R.anim.connectinganimation);
            animationDrawable = (AnimationDrawable) iv.getDrawable();
            animationDrawable.start();
        }
    }

    @Override
    protected Void doInBackground(final Void... params) {
        // Connect to Car
        handler.post(new Runnable() {
            public void run() {
                activity.isCurrentlyConnecting = true;
                activity.connect(); 
            }
        });
        return null;
    }

    @Override
    protected void onPostExecute(final Void result) {
        if (activity.deviceConnected) {         
            // Show Connected Icon
            if (animationDrawable != null) {
                animationDrawable.stop();
            }
            if (iv != null) {
                iv.setImageResource(R.drawable.ic_connected);
            }

        } else {
            Toast.makeText(activity, "Connect failed!", Toast.LENGTH_LONG).show();

            // Show Disconnected Icon
            if (animationDrawable != null) {
                animationDrawable.stop();
            }
            if (iv != null) {
                iv.setImageResource(R.drawable.ic_not_connected);
            }
        }
    }
}

2 个答案:

答案 0 :(得分:1)

我最终废弃了自定义动作提供程序和动画xml。我只是手动使用AsyncTask中的计时器。它可能不是“正确”,但它肯定更简单。

public class ConnectProgressBar extends AsyncTask<Void, Void, Void> {

    private final MainActivity activity;
    private MenuItem item;
    private Timer timer;

    public ConnectProgressBar(final MainActivity activity) {
        this.activity = activity;
    }

    @Override
    protected void onPreExecute() {
        startAnimation();
    }

    @Override
    protected Void doInBackground(final Void... params) {
        // Connect to Car
        activity.connectHardware();
        return null;
    }

    @Override
    protected void onPostExecute(final Void result) {
        stopAnimation();

        if (myClass.deviceConnected) {
            // Show Connected Icon
            if (item != null) {
                setIcon(R.drawable.ic_connected);
                setTitle(R.string.btn_disconnect);
            }

        } else {
            Toast.makeText(activity, "Connect failed!", Toast.LENGTH_LONG).show();
            // Show Disconnected Icon
            if (item != null) {
                setIcon(R.drawable.ic_not_connected);
                setTitle(R.string.btn_connect);
            }
        }

    }

    private void startAnimation() {
        if (timer == null) {
            timer = new Timer();
        }
        timer.schedule(new AnimateTask(), 0, 300);
    }

    private class AnimateTask extends TimerTask {
        int frame = 0;

        AnimateTask() {
            if (item == null) {
                item = activity.myMenu.findItem(R.id.connect);
            }
            if (item != null) {
                setTitle(R.string.btn_connecting);
            }
        }

        @Override
        public void run() {
            // Animate!
            switch (frame % 3) {
            case 0:
                setIcon(R.drawable.ic_connecting1);
                break;
            case 1:
                setIcon(R.drawable.ic_connecting2);
                break;
            case 2:
                setIcon(R.drawable.ic_connecting3);
                break;
            }
            frame++;
        }
    }

    private void setIcon(final int resId) {
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                item.setIcon(resId);
            }
        });
    }
    private void setTitle(final int resId) {
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                item.setTitle(resId);
            }
        });
    }
    private void stopAnimation() {
        timer.cancel();
        timer = null;
    }
}

答案 1 :(得分:1)

我用初始代码块找出了问题。处理程序在UI线程上运行,因此它阻止UI线程更新。

private Handler handler = new Handler(Looper.getMainLooper());

protected Void doInBackground(final Void... params) {
    handler.post(new Runnable() {
        public void run() {
            activity.isCurrentlyConnecting = true;
            activity.connect(); 
        }
    });
    return null;
}