Telegram阅读心得---页面架构(1)

Telegram阅读心得---页面架构(1)

获得telegram的源码

  1. 开发环境
    Android Studio 3.3 Canary 3
    Build #AI-181.5281.24.33.4884283, built on July 11, 2018
    JRE: 1.8.0_152-release-1136-b04 amd64
    JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
    Windows 10 10.0
    ndk版本ndk 16b

  2. clone telegram
    git clone  git@github.com:DrKLO/Telegram.git
    clone主仓库的内容之后,要获取子仓库的内容
    git submodule init
    git submodule update

  3. 安装ndk
    我使用的是ndk16b,如果你自带的ndk版本不适合,请切换到ndk16b试一试.
    jni目录下面的Android.mk中,LOCAL_MODULE:=avutil下面添加一句LOCAL_SHORT_COMMANDS:=true,再将'-DVERSION="1.3.1"'修改为-DVERSION="1.3.1"
    Application.mk下面添加APP_SHORT_COMMANDS:=true

  4. 修改Module级别下面的build.gradle
    signingConfigs内的内容全部注释掉,这一步是了直接使用android studio 提供的签名,而不必麻烦得使用自己的签名
    buildTypes中和signingConfigs相关的内容注释掉,特别的在buildTypes.debug中的applicationIdSuffix ".beta"也要注释掉

  5. 在telegram的网站https://my.telegram.org/注册并申请appid.把获得的id填入BuildVars.java的APP_IDAPP_HASH内,HOCKEY_APP_HASHHOCKEY_APP_HASH_DEBUG就随便填写一个32位的数字就行

  6. 申请firebase的google-service.json,保存到Module级别的目录下面

  7. 现在点一下这个神奇的按钮UTOOLS1554777325864.png就可以跑起来啦

  8. 如果你遇到编译安装后启动失败的问题,请关闭telegram的instant run,

阅读源码一定要有目的性

带着你的问题去看源码,要不然就会陷入,代码的海洋中找不到方向.
我第一次看源码从哪里入手呢,我选择了页面的架构,先从整体上看看这个app都是有哪些组成的.

查看Androidmianfest

这里可以看到LaunchActivity就是主入口的activity
翻遍在Androidmianfest中注册的activity可以发现,activity的数量很少,

org.telegram.ui.LaunchActivity
org.telegram.ui.ShareActivity
org.telegram.ui.ExternalActionActivity
org.telegram.ui.IntroActivity
org.telegram.messenger.OpenChatReceiver
org.telegram.ui.PopupNotificationActivity
org.telegram.ui.VoIPActivity
org.telegram.ui.VoIPGroupActivity
org.telegram.ui.VoIPPermissionActivity
org.telegram.ui.VoIPFeedbackActivity

可以看到拥有下面这个属性的org.telegram.ui.LaunchActivity就是主activity

<intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
                <category android:name="android.intent.category.MULTIWINDOW_LAUNCHER" />
            </intent-filter>

那么我们就从这里入手.
记得,一定要带着问题去看

问题一. telegram有这么多的页面,为什么activity的数量那么少呢?

首先猜测是不是由一个activity+多个fragement实现的呢?
这里将telegram调到主页面,可以使用adb命令来看一下
dumpsys activity org.telegram.messengerok
结果如下


TASK org.telegram.messengerok id=10679 userId=0
  ACTIVITY org.telegram.messengerok/org.telegram.ui.LaunchActivity 3ceac50 pid=10773
    Local Activity b23cd31 State:
      mResumed=true mStopped=false mFinished=false
      mChangingConfigurations=false
      mCurrentConfig={1.0 460mcc11mnc [zh_CN] ldltr sw500dp w500dp h953dp 345dpi nrml long hdr port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2057) mAppBounds=Rect(0, 89 - 1080, 2146) mWindowingMode=fullscreen mActivityType=standard} s.31 themeChanged=0 themeChangedFlags=0}
      mLoadersStarted=true
      FragmentManager misc state:
        mHost=android.app.Activity$HostCallbacks@f1b2ff6
        mContainer=android.app.Activity$HostCallbacks@f1b2ff6
        mCurState=5 mStateSaved=false mDestroyed=false
    ViewRoot:
      mAdded=true mRemoved=false
      mConsumeBatchedInputScheduled=true
      mConsumeBatchedInputImmediatelyScheduled=false
      mPendingInputEventCount=0
      mProcessInputEventsScheduled=false
      mTraversalScheduled=true      mIsAmbientMode=false (barrier=16046)
      android.view.ViewRootImpl$NativePreImeInputStage: mQueueLength=0
      android.view.ViewRootImpl$ImeInputStage: mQueueLength=0
      android.view.ViewRootImpl$NativePostImeInputStage: mQueueLength=0
    Choreographer:
      mFrameScheduled=true
      mLastFrameTime=108084593 (12 ms ago)
.......
下面还有一些无关的

这里只给出一部分的输出内容,可以看到,并不是fragment实现的,其实,如果细心一点,在一开始就会发现LaunchActivity extends Activity
LaunchActivity直接继承的是activity,自然不会有fragment来实现了
那么是用什么来实现的呢
接着往下看

查看LaunchActivity的布局文件

布局文件可能会带来一些新的思路
这一个activity足足有3395行,刚开始看到时候可能会有点头大

UTOOLS1554793816963.png

不要慌,我们先从简单的看起,没错!就是布局文件.
然后我吭哧吭哧去看哪里setContenview(),然后我就看到了这样的

setContentView(drawerLayoutContainer, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

居然是由代码生成的.
去看一下res/layout的资源文件,xml的布局文件居然只有4个

![UTOOLS1554794135657.png](https://i.loli.net/2019/04/09/5cac469841495.png)
telegram为什么要这么做呢,真相只有一个
UTOOLS1554794263778.png

我们知道我们通过xml布局文件是通过LayoutInflater来解析生成View的,解析的过程会花掉一部分的时间, 如果是自己通过代码来构建布局,则省去了这个步骤,那么界面的显示就会更加流畅啦.

有点跑题,现在拉回来

找到了LaunchActivity的根布局drawerLayoutContainer,看一下它里面都加了什么view,可以看到有sideMenu,actionBarLayout.

sideMenu可以看到,它是一个侧边栏
UTOOLS1554797727141.png
sideMenu.setOnItemClickListener(),我看到这里是实现了很多的点击事件,发现了presentFragment(new GroupCreateActivity(args));
跟进这个函数,发现跟到了actionBarLayout.presentFragment()中,
可以看到这里会把"fragment"加入containerViewBack中(containerViewBack是一个linearLayout),并且在actionBarLayout中维护了一个返回栈fragmentsStack

....
//
containerViewBack.addView(fragmentView);
....
fragmentsStack.add(fragment);
....

再看一下这个所谓的"fragment" 到底是什么

    protected View fragmentView;
    protected ActionBarLayout parentLayout;
    protected ActionBar actionBar;

在基类BaseFragment中,可以看到它内部有一个fragmentView,也就是被添加到containerViewBack的那个view.
actionBarLayoutBaseFragment中都提供了相应的入栈presentFragment()和出栈removeFragmentFromStack()的方法.
那么到这里我的疑惑就解开了,telegram自己实现了一个类似于官方的fragment的自己的一个fragemnt,从来实现一个activity来管理多个页面的.
那么这篇就讲到这里啦.
晚安