Android Handler.postDelayed中断声音播放

时间:2013-12-30 03:20:24

标签: android audio android-animation android-mediaplayer

我正在使用此代码播放声音

     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中并在那里播放,它可以正常工作。不确定为什么。

2 个答案:

答案 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应该在这里找到:

apk installer

source code