关于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 关键代码

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏码匠的流水账

聊聊spring cloud gateway的SetStatusGatewayFilter

本文主要研究下spring cloud gateway的SetStatusGatewayFilter

1251
来自专栏Android知识点总结

O3-开源框架使用之Butterknife 8.8.1及源码浅析

cast()方法是Clazz的一个公共方法:由下可见它反会一个由传入值强转成的T类型对象

1293
来自专栏Android群英传

不需要再手写 onSaveInstanceState 了,因为你的时间非常值钱

891
来自专栏everhad

ViewPager无限滑动

前言 View轮播效果在app中很常见,一想到左右滑动的效果就很容易想到使用ViewPager来实现。对于像我们常说的banner这样的效果,具备无限滑动的功能...

3407
来自专栏androidBlog

Android 自定义 MarqueeView 实现跑马灯 —— 原理篇

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details/...

1491
来自专栏蜉蝣禅修之道

android之listview使用方法(一)

1412
来自专栏Android先生

Android 使用代码实现一个选词(拖拽)填空题

在上一篇文章《Android 使用代码实现一个填空题》中,我们学习了如何实现一个填空题,今天继续接着上一篇文章的节奏,学习一下如何实现一个选词填空题,由于本文中...

1022
来自专栏Android开发指南

2.抽取代码(BaseActivity)

3578
来自专栏Android中高级开发

Android开发之漫漫长途 XV——RecyclerView

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索...

1612
来自专栏Android常用基础

简单好用的RecyclerView适配器

给大家推荐个好用RecyclerView适配器,也就是在百篮应用里用到的适配器。为了大家学习方便,这里简单的写下如何使用这个适配器,不做代码具体的分析,有兴趣的...

1133

扫码关注云+社区

领取腾讯云代金券