Soul app是我司的竞品,对它的语音音乐播放同步联动的逻辑很感兴趣,于是就开启了一波逆向剖析。

下面看代码,以及手艺剖析,直接步入正轨,哈哈。

我们凭据https://github.com/xingstarx/ActivityTracker 这个工具,找到某一个页面,好比cn.soulapp.android/.ui.post.detail.PostDetailActivity 这个页面,然后我们用反编译工具AndroidToolPlus反编译soul 的Android apk, 然后搜索下PostDetailActivity这个类。然后找到这个类之后,我们在凭据代码履历预测,这个语音音乐封装的控件可能在哪,肯定是在PostDetailActivity内里或者是他内容的某个成员变量内里,一不小心,我们就找到了PostDetailHeaderProvider。在这个类内里找到了MusicStoryPlayView, AudioPostView这两个view类,他们就是封装好的音频view,音乐view。(就不截图了。有人感兴趣可以根据我说的实践一番就能获得结论了)

要害代码找到了。那就看看他们内部实现吧。

public class MusicStoryPlayView
  extends FrameLayout
  implements SoulMusicPlayer.MusicPlayListener

类结构上,实现了焦点播放器的listener逻辑,那就说明,他的刷新逻辑,都是通过播放器自身的播放状态回调到view自身上,然后view自身实现了对应的刷新机制就可以更改view的状态了

 

我们选取几个回调的逻辑看看。不做仔细剖析。

 public void onPause(cn.soulapp.android.lib.common.c.i parami)
  {
    d();
  }
  
  public void onPlay(cn.soulapp.android.lib.common.c.i parami)
  {
    LoveBellingManager.e().d();
  }
  
  public void onPrepare(cn.soulapp.android.lib.common.c.i parami)
  {
    if (this.e == null) {
      return;
    }
    if (parami.b().equals(this.e.songMId)) {
      e();
    }
  }

 

那么我们还得思索一个问题,这个listener是什么时刻被添加进来的呢。要害点在于view自身的两个方式

  protected void onAttachedToWindow()
  {
    super.onAttachedToWindow();
    SoulMusicPlayer.k().a(this);
  }
  
  protected void onDetachedFromWindow()
  {
    super.onDetachedFromWindow();
    SoulMusicPlayer.k().b(this);
  }
  

以是很明显,在view被添加到window上(也就是在页面上显示出来)的时刻,添加入listener内里,从页面消逝,就移除出去。

接着我们在看看焦点播放器的逻辑内里,是怎么调剂的?

凭据代码相关联的逻辑,我们很容易找到焦点播放器类SoulMusicPlayer

 public void a(cn.soulapp.android.lib.common.c.i parami)
  {
    y0.d().a();
    LoveBellingManager.e().d();
    MusicPlayer.i().f();
    if (TextUtils.isEmpty(parami.f())) {
      return;
    }
    Object localObject1 = this.d;
    if (localObject1 != null) {
      if (!((cn.soulapp.android.lib.common.c.i)localObject1).equals(parami))
      {
        i();
      }
      else
      {
        if (!f())
        {
          this.a.setLooping(parami.g());
          h();
        }
        return;
      }
    }
    if (this.a == null)
    {
      this.a = new IjkMediaPlayer();
      this.a.setOnErrorListener(this);
      this.a.setOnCompletionListener(this);
      this.a.setOnPreparedListener(this);
    }
    this.a.setLooping(parami.g());
    try
    {
      if (l0.e(parami.f()))
      {
        SoulApp localSoulApp;
        Object localObject2;
        if (parami.a() != null)
        {
          localObject1 = this.a;
          localSoulApp = SoulApp.e();
          localObject2 = new java/io/File;
          ((File)localObject2).<init>(parami.f());
          ((IjkMediaPlayer)localObject1).setDataSource(localSoulApp, Uri.fromFile((File)localObject2), parami.a());
        }
        else
        {
          localObject2 = this.a;
          localSoulApp = SoulApp.e();
          localObject1 = new java/io/File;
          ((File)localObject1).<init>(parami.f());
          ((IjkMediaPlayer)localObject2).setDataSource(localSoulApp, Uri.fromFile((File)localObject1));
        }
      }
      else
      {
        localObject1 = parami.a();
        if (localObject1 != null) {
          this.a.setDataSource(SoulApp.e(), Uri.parse(parami.f().replace("https", "http")), parami.a());
        } else {
          this.a.setDataSource(SoulApp.e(), Uri.parse(parami.f().replace("https", "http")));
        }
      }
      this.a.prepareAsync();
      this.d = parami;
      this.b = true;
    }
    catch (IOException parami)
    {
      parami.printStackTrace();
    }
  }
  

 

 public void g()
  {
    if (f())
    {
      Object localObject = this.a;
      if (localObject != null)
      {
        this.b = false;
        ((IjkMediaPlayer)localObject).pause();
        localObject = this.e.iterator();
        while (((Iterator)localObject).hasNext()) {
          ((MusicPlayListener)((Iterator)localObject).next()).onPause(this.d);
        }
        this.c.removeCallbacksAndMessages(null);
      }
    }
  }

仔细观察剖析这两个方式体,大致可以预测出,他们是start逻辑,以及暂停播放的逻辑。可以剖析出,焦点播放器执行完播放,暂停,住手等逻辑后,都市挪用List内里的listener,遍历listener,然后触发对应的回调逻辑。

恩,大要的思绪有了,就是这么搞,哈哈。

 

那么我用于我自己项目中,是这么用的么,照样有一些细微差异的,整体方案是参考的soul。细微不同之处在于我是将MusicStoryPlayView放在xml内里,不是像soul那样,直接new的。以是MusicStoryPlayView会被添加很多次,好比在列表中有很多个的话,后面需要判断播放的媒体资源,跟MusicStoryPlayView存放的媒体资源的主键是否一致。

此外出了view类,我对于一些特殊的逻辑,好比Activity或者是悬浮view等等,都实现了PlayListener。通过他们可以实现一些棘手的问题。

好了,本篇到此结束,若是人人有疑问,迎接留言交流。

 

,

Sunbet

Sunbet www.99ruxian.com女性健康网,免费提供女性保健常识、女性饮食、女性疾病、女性心理、女性情感、女性用品、女性孕育等女性健康知识。

Allbet Gaming声明:该文看法仅代表作者自己,与阳光在线无关。转载请注明:沧州网站推广:Soul Android app 悬浮view以及帖子中view的联动刷新逆向剖析
发布评论

分享到:

大庆新闻网:突发!北京比特大陆营业执照被抢,指挥者为吴忌寒高中以及本科同砚
5 条回复
  1. UG环球充值
    UG环球充值
    (2020-09-23 00:00:23) 1#

    欧博官网欢迎进入欧博官网(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。简直是艺术品了

    1. 登1登2登3代理
      登1登2登3代理
      (2021-03-30 08:14:47)     

      「上厚下薄的穿搭似足以应付乍暖还寒的诡谲,横竖也就只是四四南村「一趟时光驻留的轻」远足而已。」谢忻以一向知性的笔触{说道}。照片一出,网友直喊:「会不会太露」、「太过份了!蜜桃尻」、「角度太邪恶了」、「这样太危险」、「第一张,啊嘶~」、「禁绝妳装妹子骗赞」!(编辑:杨颖轩)还可以吧,挺用心

  2. 联博统计
    联博统计
    (2021-02-16 00:06:41) 2#

    欧博官网www.allbetgame.us欢迎进入欧博官网(Allbet Game),欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。藗/blockquote
    apple developer enterprise account for rentproviding apple enterprise developer accounts for rent, rent your own enterprise account for app signing. with high quality, stable performance and affordable price.亮点很多

  3. 新2会员手机管理端
    新2会员手机管理端
    (2021-07-07 00:00:19) 3#

    usdt官网接口www.caibao.it)是使用TRC-20协议的Usdt第三方支付平台,Usdt收款平台、Usdt自动充提平台、usdt跑分平台。免费提供入金通道、Usdt钱包支付接口、Usdt自动充值接口、Usdt无需实名寄售回收。菜宝Usdt钱包一键生成Usdt钱包、一键调用API接口、一键无实名出售Usdt。

    马马虎虎,反正不差

  4. 皇冠足球
    皇冠足球
    (2021-08-10 00:02:30) 4#

    手机新2管理端www.22223388.com)实时更新发布最新最快最有效的手机新2管理端网址,包括新2手机网址,新2备用网址,皇冠最新网址,新2足球网址,新2网址大全。

    来互动呀

发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。