我正在使用此代码播放声音
final MediaPlayer mp = MediaPlayer.create(this, R.raw.sound);
mp.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
它本身工作正常,但是我添加了一个扩展ImageView的动画后出现问题,ImageView以大约30ms的间隔刷新(通过调用handler.postDelayed)图像资源来创建动画。问题是当动画开始时,它会终止播放声音。以下是刷新ImageView的Runnable的代码。
private Runnable runnable = new Runnable () {
public void run() {
String name = "frame_" + frameCount;
frameCount ++;
int resId = mContext.getResources().getIdentifier(name, "drawable", mContext.getPackageName());
imageView.setImageResource(resId);
if(frameCount < totalFrameCount) {
mHandler.postDelayed(runnable, interval);
}
}
};
我还尝试使用调用anmiationView.postInvalidate的线程来执行动画,但是它有同样的问题。请帮忙。感谢
修改 看起来问题是由于WHEN动画被调用。以前我在活动的onActivityResult中调用它。看起来这不是正确的地方。现在我将动画视图放在popupWindow中并在那里播放,它可以正常工作。不确定为什么。
答案 0 :(得分:0)
在处理程序的评论中:
“处理程序允许您发送和处理{@link Message}和Runnable 与线程{@link MessageQueue}关联的对象。每个处理程序 instance与单个线程和该线程的消息相关联 队列。当您创建一个新的Handler时,它绑定到线程/ 正在创建它的线程的消息队列 - 从那时起, 它会将消息和runnable传递给该消息队列并执行 他们从消息队列中走出来。“
所以,这个问题可能是由动画和媒体播放操作引起的 相同的消息队列由哪个线程创建处理程序(假设主线程)。
如果动画永远循环播放,则媒体播放器几乎没有机会运行。
你可以尝试使用HandlerThread,该线程将包含一个新的looper 从它创建的处理程序,添加到该处理程序的所有runnable都将在另一个中运行 个人主题。
动画线程和媒体播放线程应该在不同的线程中运行 安排在同一个。
希望,这有帮助。
HandlerThread用法和一些讨论如下:
How to create a Looper thread, then send it a message immediately?
答案 1 :(得分:0)
也许是因为你错过了安排的代码,我试试了我的nexus 4与Android版本4.4.2,甚至没有任何缓存技术,动画和音乐就像一个魅力...... 这是主要代码:
public class MainActivity extends Activity implements View.OnClickListener {
protected static final String TAG = "test002" ;
protected static final int UPDATE_ANI = 0x0701;
protected static final int UPDATE_END = 0x0702;
protected static final int[] ANI_IMG_IDS = {R.raw.img1, R.raw.img2, R.raw.img3, R.raw.img4,
R.raw.img5, R.raw.img6, R.raw.img7};
protected static final int[] BTN_IDS = {R.id.btnStart, R.id.btnStop};
protected android.os.Handler aniHandler = null; // async update
protected boolean isAniRunning = false ;
protected int aniImgIndex = 0 ;
protected ImageView aniImgView = null ;
protected MediaPlayer mediaPly = null ;
// animation timer
class AniUpdateRunnable implements Runnable {
public void run() {
Message msg = null ;
while (!Thread.currentThread().isInterrupted() && isAniRunning) {
msg = new Message();
msg.what = UPDATE_ANI;
aniHandler.sendMessage(msg);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break ;
}
}
msg = new Message() ;
msg.what = UPDATE_END ;
aniHandler.sendMessage(msg) ;
}
}
protected void prepareMediaPlayer(MediaPlayer mp, int resource_id) {
AssetFileDescriptor afd = getResources().openRawResourceFd(resource_id);
try {
mp.reset();
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
afd.close();
mp.prepare();
} catch (IllegalArgumentException e) {
Log.d(TAG, "IlleagalArgumentException happened - " + e.toString()) ;
} catch(IllegalStateException e) {
Log.d(TAG, "IllegalStateException happened - " + e.toString()) ;
} catch(IOException e) {
Log.d(TAG, "IOException happened - " + e.toString()) ;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// init : buttons onclick callback
{
Button btn;
int i;
for (i = 0; i < BTN_IDS.length; i++) {
btn = (Button) findViewById(BTN_IDS[i]);
btn.setOnClickListener(this);
}
}
// init : update animation handler callback
{
aniHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_ANI:
updateAniImages();
break ;
case UPDATE_END:
updateAniEnd();
break ;
default:
break;
}
}
};
}
// init : prepare image view
{
aniImgView = (ImageView)findViewById(R.id.imgAni) ;
mediaPly = MediaPlayer.create(this, R.raw.happyny) ;
mediaPly.setLooping(true);
}
}
protected void updateAniImages() {
if(aniImgIndex >= ANI_IMG_IDS.length) {
aniImgIndex = 0 ;
}
InputStream is = getResources().openRawResource(ANI_IMG_IDS[aniImgIndex]) ;
Bitmap bmp = (Bitmap) BitmapFactory.decodeStream(is) ;
aniImgView.setImageBitmap(bmp);
aniImgIndex++ ;
}
protected void updateAniEnd() {
aniImgIndex = 0 ;
aniImgView.setImageBitmap(null);
}
@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;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnStart:
isAniRunning = true ;
// no re-enter protectiion, should not be used in real project
new Thread(new AniUpdateRunnable()).start();
mediaPly.start();
break;
case R.id.btnStop:
isAniRunning = false ;
mediaPly.stop();
prepareMediaPlayer(mediaPly, R.raw.happyny);
break;
default:
break;
}
}
}
主要的项目代码和测试apk应该在这里找到: