VLC for Androidのメイン画面の解析


はじめに

VLC for Androidのメイン画面を解析する。ゴールはメイン画面で登場するクラスの洗い出しと関連性のざっくりとした把握。

各種リンク

アプリ
GitHub
公式サイト

MainActivityのスクリーンショット

メイン画面の表現するクラス

  • MainActivity:アクティビィティ
  • Navigator:下のタブの処理部分
  • AudioBrowserFragment:音楽関係のブラウズ画面
  • MainBrowserFragment:ファイルベースのブラウズ画面
  • PlaylistFragment:プレイリストのブラウズ画面
  • MoreFragment:その他のブラウズ画面
  • VideoGridFragment:ビデオ関係のブラウズ画面

MainActivityのレイアウト構成

<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/coordinator"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

  // 上のツールバー
    <include
            layout="@layout/toolbar"
            ...
            android:nextFocusForward="@+id/ml_menu_search" />

    // フラグメントを入れる所(ビデオ、プレイリスト、アルバム、ブラウズ)
    <androidx.fragment.app.FragmentContainerView
            ...
            tools:targetApi="o" />

  // 進捗バー?
    <androidx.appcompat.widget.ViewStubCompat
            ...
            android:layout="@layout/scan_progress" />

    <include layout="@layout/audioplayercontainer" />

  // シャッフルボタン
    <com.google.android.material.floatingactionbutton.FloatingActionButton
            ...
            app:rippleColor="@color/orange50" />

    // 下タブ
    <com.google.android.material.bottomnavigation.BottomNavigationView
            ...
            app:menu="@menu/bottom_navigation" />


    <androidx.appcompat.widget.ViewStubCompat
            ...
            android:layout_width="match_parent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

MainActivityの解説

継承周り

↓。タブバー関係の処理はNavigatorクラスに委譲している。そのおかげでクラスの行数は170ステップぐらいに収まっている模様。

class MainActivity : ContentActivity(),
        ExtensionManagerService.ExtensionManagerActivity,
        INavigator by Navigator()
{

ContentActivity周りが気になるので調べてみると以下の継承構造になっている模様。

なんでこんな階層になっているかは気になるが今回は割愛。AudioPlayerContainerActivityは再生周りの何かを共通化しているように見えるが。

 インスタンス変数

下の3つだけ。ライブラリ更新関係の制御を行っている模様。

   var refreshing: Boolean = false
        set(value) {
            field = value
        }
    private lateinit var mediaLibrary: Medialibrary
    private var scanNeeded = false

Navigatorについて

継承関係とインスタンス変数は↓。フラグメントまわりは色々ごちゃごちゃやっているが詳細は割愛。設計的にMainActivityと循環参照しているのが気になるが。

class Navigator : BottomNavigationView.OnNavigationItemSelectedListener, LifecycleObserver, INavigator {

    private val defaultFragmentId= R.id.nav_video
    override var currentFragmentId : Int = 0
    private var currentFragment: Fragment? = null
        private set
    private lateinit var activity: MainActivity
    private lateinit var settings: SharedPreferences
    private var extensionsService: ExtensionManagerService? = null
    override lateinit var navigationView: BottomNavigationView
    override lateinit var appbarLayout: AppBarLayout

    override lateinit var extensionsManager: ExtensionsManager
    override var extensionServiceConnection: ServiceConnection? = null
    override var extensionManagerService: ExtensionManagerService? = null
    private val isExtensionServiceBinded: Boolean
        get() = extensionServiceConnection != null

 まとめ

  • Navigatorクラスにうまく委譲することよって、MainActivityの肥大化を避けている?
  • とは言ってもNavigatorとMainActivityは循環依存しているけど。