2014-07-08 66 views
1

目標:在操作欄中有一個連接圖標。 OnClick,它應該嘗試在後臺連接。在嘗試連接時,應該播放連接動畫。然後它應該切換回「not_connected」或「connected」drawable,取決於成功或失敗。Android:動作欄中的動畫不支持異步任務

問題:如果我調用自定義操作提供程序的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); 
      } 
     } 
    } 
} 

回答

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; 
} 
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; 
    } 
}