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
  1. clone telegram
git clone git@github.com:DrKLO/Telegram.git
clone主仓库的内容之后,要获取子仓库的内容
git submodule init
git submodule update
  1. 安装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
  1. 修改Module级别下面的build.gradle
signingConfigs内的内容全部注释掉,这一步是了直接使用android studio 提供的签名,而不必麻烦得使用自己的签名
buildTypes中和signingConfigs相关的内容注释掉,特别的在buildTypes.debug中的applicationIdSuffix ".beta"也要注释掉
  1. 在telegram的网站https://my.telegram.org/注册并申请appid.把获得的id填入BuildVars.java的APP_IDAPP_HASH内,HOCKEY_APP_HASHHOCKEY_APP_HASH_DEBUG就随便填写一个32位的数字就行
  2. 申请firebase的google-service.json,保存到Module级别的目录下面


  3. 现在点一下这个神奇的按钮 Telegram阅读心得---页面结构(1)
    文章图片
    UTOOLS1554777325864.png 就可以跑起来啦
  4. 如果你遇到编译安装后启动失败的问题,请关闭telegram的instant run,
阅读源码一定要有目的性 带着你的问题去看源码,要不然就会陷入,代码的海洋中找不到方向.
我第一次看源码从哪里入手呢,我选择了页面的架构,先从整体上看看这个app都是有哪些组成的.
查看Androidmianfest 这里可以看到LaunchActivity就是主入口的activity
翻遍在Androidmianfest中注册的activity可以发现,activity的数量很少,
org.telegram.ui.LaunchActivityorg.telegram.ui.ShareActivityorg.telegram.ui.ExternalActionActivityorg.telegram.ui.IntroActivityorg.telegram.messenger.OpenChatReceiverorg.telegram.ui.PopupNotificationActivityorg.telegram.ui.VoIPActivityorg.telegram.ui.VoIPGroupActivityorg.telegram.ui.VoIPPermissionActivityorg.telegram.ui.VoIPFeedbackActivity

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

那么我们就从这里入手.
记得,一定要带着问题去看
问题一. telegram有这么多的页面,为什么activity的数量那么少呢? 首先猜测是不是由一个activity+多个fragement实现的呢?
这里将telegram调到主页面,可以使用adb命令来看一下
dumpsys activity org.telegram.messengerok
结果如下
TASK org.telegram.messengerok id=10679 userId=0ACTIVITY org.telegram.messengerok/org.telegram.ui.LaunchActivity 3ceac50 pid=10773Local Activity b23cd31 State:mResumed=true mStopped=false mFinished=falsemChangingConfigurations=falsemCurrentConfig={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=trueFragmentManager misc state:mHost=android.app.Activity$HostCallbacks@f1b2ff6mContainer=android.app.Activity$HostCallbacks@f1b2ff6mCurState=5 mStateSaved=false mDestroyed=falseViewRoot:mAdded=true mRemoved=falsemConsumeBatchedInputScheduled=truemConsumeBatchedInputImmediatelyScheduled=falsemPendingInputEventCount=0mProcessInputEventsScheduled=falsemTraversalScheduled=truemIsAmbientMode=false (barrier=16046)android.view.ViewRootImpl$NativePreImeInputStage: mQueueLength=0android.view.ViewRootImpl$ImeInputStage: mQueueLength=0android.view.ViewRootImpl$NativePostImeInputStage: mQueueLength=0Choreographer:mFrameScheduled=truemLastFrameTime=108084593 (12 ms ago).......下面还有一些无关的

这里只给出一部分的输出内容,可以看到,并不是fragment实现的,其实,如果细心一点,在一开始就会发现LaunchActivity extends Activity
LaunchActivity直接继承的是activity,自然不会有fragment来实现了
那么是用什么来实现的呢
接着往下看
查看LaunchActivity的布局文件 布局文件可能会带来一些新的思路
这一个activity足足有3395行,刚开始看到时候可能会有点头大
Telegram阅读心得---页面结构(1)
文章图片
UTOOLS1554793816963.png 不要慌,我们先从简单的看起,没错!就是布局文件.
然后我吭哧吭哧去看哪里setContenview(),然后我就看到了这样的
setContentView(drawerLayoutContainer, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

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


Telegram阅读心得---页面结构(1)
文章图片
UTOOLS1554794135657.png
telegram为什么要这么做呢,真相只有一个
Telegram阅读心得---页面结构(1)
文章图片
UTOOLS1554794263778.png 我们知道我们通过xml布局文件是通过LayoutInflater来解析生成View的,解析的过程会花掉一部分的时间, 如果是自己通过代码来构建布局,则省去了这个步骤,那么界面的显示就会更加流畅啦.
有点跑题,现在拉回来
找到了LaunchActivity的根布局drawerLayoutContainer,看一下它里面都加了什么view,可以看到有sideMenu,actionBarLayout.
sideMenu可以看到,它是一个侧边栏
Telegram阅读心得---页面结构(1)
文章图片
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来管理多个页面的.
那么这篇就讲到这里啦.
【Telegram阅读心得---页面结构(1)】晚安

    推荐阅读