zoukankan      html  css  js  c++  java
  • 关于Activity销毁,而绘制UI的子线程未销毁出现的问题

    项目总结

    ---------------------------------------------------------------------------------------------------------

    有一个功能模块,需要播放音频,画一个简单的界面

    一个例子:

    我们都知道播放音频要用到MediaPlayer类,我这里,不需要开启Service,就在本Activity播放音频,当Activity销毁的时候,音频便结束

    但是有一个重点,需要即时的变化当前播放的时间

    我的思路是,开启一个线程,计算当前音频的剩余播放时间,如果>0 则用Handler循环发送一个消息来更改时间UI

    Thread tPlay ;
    tPlay = new Thread(new Runnable() {
                @Override
                public void run() {
                    int time = (mPlay.getDuration()-mPlay.getCurrentPosition())/1000;  // 获得当前的音频的剩余时间,总时长-当前播放时长
                    while(time>0&&mPlay!=null) {                                       // 如果剩余时间>0 并且MediaPlayer对象存在,就需要没0.2秒更新一下时间UI
                        try {
                            Thread.sleep(200);
                            time = (mPlay.getDuration()-mPlay.getCurrentPosition())/1000; //获得当前时间
                            final int finalTime = time;
                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    topic_play_time.setText(finalTime /60+"'"+ finalTime %60); //更改UI
                                }
                            });
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });

    然后有线程对象了,什么时候start呢,必然是在第一次播放音频的时候,而且只能start一次。

    那么问题来了。当我播放音频的时候,或者暂停已经播放一段的音频的时候,用户可能会退出Activity ,

    而Activity销毁了,但是这个Activity开启的计算时间更改UI的子线程还存在,它还需要循环计算剩余时间,但是MediaPlayer对象没了,就报错了。

    所以,解决方法只能是销毁Activity之前结束这个Activity开启的子线程。

    试过几种方法,最后选定了一个最简单,最易理解的方法:

    1、设置一个全局标记变量boolean flag = true;

    2、线程中while 循环判断 flag 是否为true,是则执行内部代码,否则不执行,结束循环了,即线程也随之结束了

    tPlay = new Thread(new Runnable() {
                @Override
                public void run() {
                    int time = (mPlay.getDuration()-mPlay.getCurrentPosition())/1000;
                    while(time>0&&mPlay!=null&&flag) {
                    }
                }
            });

    3、在Activity销毁的

    @Override
    protected void onDestroy() {
        super.onDestroy();
        isflag=false;
    }

    方法中更改flag,那么线程中while条件则不成立,线程就结束了,也不会再报错了。

    贴一下关键代码:

      1 public class TopicDetailActivity extends Activity implements View.OnClickListener {
      2 
      3     private ImageButton topic_play_music;
      4 
      5     private Attention entity;
      6 
      7     private boolean isflag= true;
      8     private MediaPlayer mPlay;
      9     private Thread tPlay;
     10     private Handler handler = new Handler(){
     11         @Override
     12         public void handleMessage(Message msg) {
     13             super.handleMessage(msg);
     14 
     15         }
     16     };
     17     @Override
     18     protected void onCreate(Bundle savedInstanceState) {
     19         super.onCreate(savedInstanceState);
     20         setContentView(R.layout.activity_topic_detail);
     21 
     22         Intent intent = getIntent();
     23         Serializable attention = intent.getSerializableExtra("attention");
     24         tPlay = new Thread(new Runnable() {
     25             @Override
     26             public void run() {
     27                 int time = (mPlay.getDuration()-mPlay.getCurrentPosition())/1000;
     28                 while(time>0&&mPlay!=null&&isflag) {
     29                     try {
     30                         Thread.sleep(200);
     31                         time = (mPlay.getDuration()-mPlay.getCurrentPosition())/1000;
     32                         final int finalTime = time;
     33                         handler.post(new Runnable() {
     34                             @Override
     35                             public void run() {
     36                                 topic_play_time.setText(finalTime /60+"'"+ finalTime %60);
     37                             }
     38                         });
     39                     } catch (InterruptedException e) {
     40                         e.printStackTrace();
     41                     }
     42                 }
     43             }
     44         });
     45         initView();
     46         initData(attention);
     47     }
     48 
     49     /**
     50      * 数据展示
     51      * @param attention
     52      */
     53     private void initData(Serializable attention) {
     54         entity = (Attention) attention;
     55        
     56         int nowTime = Integer.parseInt(entity.getAudiolength());
     57         topic_play_time.setText(nowTime/60 + "'" + nowTime%60);
     58         
     59 
     60 
     61 
     62     }
     63 
     64 
     65     /**
     66      * 初始化控件
     67      */
     68     private void initView() {
     69         topic_play_music = (ImageButton) findViewById(R.id.topic_play_music);
     70 
     71         topic_play_music.setOnClickListener(this);
     72     }
     73 
     74     @Override
     75     public void onClick(View v) {
     76         switch (v.getId()){
     77             
     78             case R.id.topic_play_music:
     79                 if(mPlay==null){
     80                     mPlay = new MediaPlayer();
     81                     mPlay.reset();
     82                     try {
     83                         mPlay.setDataSource("http://imagecdn.xunjimap.com/image/" + entity.getAudiourl());
     84                         mPlay.prepare();
     85                         topic_play_music.setImageResource(R.mipmap.ui_detail_pause);
     86                         mPlay.start();
     87                         tPlay.start();
     88                     } catch (IOException e) {
     89                         e.printStackTrace();
     90                     }
     91                 }else{
     92                     if (mPlay.isPlaying()){
     93                         mPlay.pause();
     94                         topic_play_music.setImageResource(R.mipmap.ui_detail_play);
     95                     }else{
     96                         mPlay.start();
     97                         topic_play_music.setImageResource(R.mipmap.ui_detail_pause);
     98                     }
     99                 }
    100                 break;
    101         }
    102     }
    103 
    104     @Override
    105     protected void onDestroy() {
    106         super.onDestroy();
    107         isflag=false;
    108         try {
    109             tPlay.sleep(500);
    110         } catch (InterruptedException e) {
    111             e.printStackTrace();
    112         }
    113         if (mPlay!=null){
    114             mPlay.stop();
    115 
    116             mPlay.release();
    117         }
    118     }
    119 
    120 
    121 }
    122 
    123 关键代码
    关键代码
  • 相关阅读:
    [Kotlin] Open Classes and Inheritance
    [Kotlin] Class
    [Kotlin] Reverse a List with downTo
    [Kotlin] Named loop
    [Kotlin] for loop
    [Kotlin] Array List ArrayList
    深度解读 java 线程池设计思想及源码实现
    源码实战 | 从线程池理论聊聊为什么要看源码
    自己实现一个简单的线程池
    死磕 java线程系列之自己动手写一个线程池(续)
  • 原文地址:https://www.cnblogs.com/xqxacm/p/4960240.html
Copyright © 2011-2022 走看看