很有用的一篇文章,对于android新手,Log的分析之二

 http://www.eoeandroid.com/thread-55761-1-1.html

 

 

三,如何通过Handler或者多线程来解决某操作执行时间过程的问题(update on Jan.19)

结合上面的分析,我们知道问题似乎是线程队列中某个操作presentRegionMedia(view,(RegionMediaModel) model, dataChanged);执行时间太长所导致的界面无响应因此比较典型的做法当然是控制线程队列
在这里我们不得不提一下Handler  .

HandlerAndroid中是什么样的作用和地位呢?

1,线程之间消息传递通过sendMessage方法我们通常用来后台子线程向主线程传递消息,主线程接到通知之后做更新界面等操作

2,通过管理消息队列(MessageQueue)来安排计划任务这个常常会被人忽略,很多书上也没有提到这个作用

Handler这个单词中文意思是管理者,处理者的意思通过这个意思顾名思义,我们知道这个对象就是个操作对象。那么要操作谁呢

当然是消息队列(MessageQueueAndroid消息队列类似于Win32队列设计都是采用线性结构,先进先出其实在智能手机平台很久以前就用这种消息结构了比如Palm只不过Palm是整个进程共享一个消息队列,而Android是线程为单位的队列罢了


那么是否每个线程或者子线程都有消息队列呢

很遗憾,不是的,也没有必要Android中,只有使用了Looper的线程才有消息队列当然如果你要简单建立一个有消息队列的线程也很方便,直接使用HandlerThread即可,这个类继承于Thread。怎么用我就不多说了吧。你懂的

Handler有两种方式来操作消息队列

一种是通过sendMessage(Message)方法,发送消息体

另一种是通过post(Runnable)方法发送Runnable对象


注意:这点请注意,虽然发送方法含参不同但他们使用的是同一个消息队列
我记得Mars的视频教程上说有两个队列,一个是消息队列,一个是线程队列
这种说法是错误的。事实上只有一个消息队列,没有所谓的线程队列当然了post(Runnable)也没有启动新的线程,仍然是在当前线程


注意:还有一种说法
,说Handler对象在主线程,这种说法也是错误的准确的说是在产生他的线程中虽然常常我们是在主线程产生他的

那么我们要在Android建立多线程程序该如何做呢?很简单,就是Java的多线程方式。要么实现Runnable接口,要么继承Thread

关于线程同步,线程锁定,线程异步,线程池这些概念也是一样的我就不累述了。


 

好了,经过一点儿简单的介绍,我们有了一些Handler的基础,现在开始回到我们的问题开始来分析

mHandler.post(new Runnable() {
                   public void run() {
                       try {
                          presentRegionMedia(view, (RegionMediaModel) model, dataChanged);
                       } catch(OMADRMException e) {
                          Log.e(TAG, e.getMessage(), e);
                          Toast.makeText(mContext,
                                 mContext.getString(R.string.insufficient_drm_rights),
                                  Toast.LENGTH_SHORT).show();
                       } catch (IOExceptione){
                          Log.e(TAG, e.getMessage(), e);
                          Toast.makeText(mContext,
                                 mContext.getString(R.string.insufficient_drm_rights),
                                  Toast.LENGTH_SHORT).show();



                       }
                   }

从上面这段代码中,我们可以看出,在做播放器控制按钮(比如播放,暂停,停止)等操作的时候是通过Handler.post(Runnable)来放到消息队列中排序来处理那么之所以这里出现了无响应,很有可能是因为某一项控制操作太耗时或者耗资源这时候又接收到新的要处理的消息,就会处理不过来了
因此我试图让队列中同时只有一个控制播放器按钮的任务在
我对代码做了如下改动:

Runnabler = new Runnable(){
                   public void run() {
                       try {
                          presentRegionMedia(view, (RegionMediaModel) model, dataChanged);
                       } catch(OMADRMException e) {
                          Log.e(TAG, e.getMessage(), e);
                          Toast.makeText(mContext,
                                 mContext.getString(R.string.insufficient_drm_rights),
                                  Toast.LENGTH_SHORT).show();
                       } catch (IOExceptione){
                          Log.e(TAG, e.getMessage(), e);
                          Toast.makeText(mContext,
                                 mContext.getString(R.string.insufficient_drm_rights),
                                  Toast.LENGTH_SHORT).show();



                       }
                   }

mHandler.removeCallbacks(r);

mHandler.postr ;


代码慢慢看,思路很简单:其实就是在post Runnable之前先清除队列中已存的相同Runnable实例
这样可以保证同时队列中只有一个操作在处理

很遗憾,不生效:(,改动之后,问题依然存在,欲哭无泪



 

再来,我将整个模式改为message再试试,核心代码如下


if(mHandler.hasMessages(MEDIA_PLAY_WHAT_MESSAGEFLAG))


{


return;


}


Message msg= mHandler.obtainMessage();


msg.what =this.MEDIA_PLAY_WHAT_MESSAGEFLAG;


msg.obj =mMeidaPlayMessageObj;


mHandler.sendMessageDelayed(msg, 1000);


 

代码慢慢看,思路也很简单,通过发消息的方式,先检测如果有相关消息队列,就直接跳出函数,不做任何处理,否则延迟一秒后再向队列发送一条消息为何我用了1秒这个这么长的时间呢,因为这么长时间如果都处理不了,那就不是压力测试的问题了,而是方法本身的问题了,这也是通过排除法来试图排除是因为点击屏幕过快产生的问题

编译,再试很不辛,又不生效,不幸被我猜中了仰望苍天


现在问题很明显了:不是压力测试时候点击过快导致的ANR,而是某些方法本身有问题。

通过之前我们的日志

-----pid 2922 at 2011-01-13 13:51:07 -----
Cmd line: com.android.mms

DALVIK THREADS:
"main" prio=5 tid=1 NATIVE
  | group="main" sCount=1dsCount=0 s=N obj=0x4001d8d0 self=0xccc8
  | sysTid=2922 nice=0 sched=0/0cgrp=default handle=-1345017808
  | schedstat=( 3497492306 1531289792310358 )
  at android.media.MediaPlayer._release(NativeMethod)
  atandroid.media.MediaPlayer.release(MediaPlayer.java:1206)
  atandroid.widget.VideoView.stopPlayback(VideoView.java:196)
  atcom.android.mms.ui.SlideView.stopVideo(SlideView.java:640)

很容易就知道了问题出在每次执行完了MediaPlayer.stop()方法调用之后会调用release()来释放播放器资源而这个方法中又死在了_release()方法上这是一个Native方法因此,真相大白,问题是在Framework层的MediaPlayer调用的Native方法_release()


(打的手酸了,休息一下,大家对下面的内容还感兴趣么?)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值