目标:在操作栏中显示连接图标。 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);
}
}
}
}
答案 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;
}