Android:动作栏中的动画不支持异步任务



目标:在操作栏中有一个连接图标。OnClick,它应该尝试在后台连接。当它尝试连接时,应该播放连接动画。然后,它应该切换回"not_connected"或"connected"可绘制,这取决于成功或失败。

问题:如果我在自定义操作提供程序的onClick方法中调用代码,它可以完美地工作(参见切换它的注释部分)。当相同的代码是AsyncTask的onPreExecute内部,它将不会播放(它停留在第一帧),即使我传递一个引用到ImageView。

我的设置:要在动作栏中做帧动画,你必须使用自定义动作提供程序(参见animationDrawable在动作栏中不播放?)我有一个自定义布局,一个自定义动作提供者它会膨胀并设置on-click方法。我的连接功能在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);
            }
        }
    }
}

我最终放弃了自定义动作提供程序和动画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;
    }
}

我发现了我的初始代码块的问题。处理程序在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;
}

最新更新