【Bugly安卓开发干货】Android APP 高速 Pad 化实现

Bugly 技术干货系列内容主要涉及移动开发方向。是由 Bugly 邀请腾讯内部各位技术大咖,经过平常工做经验的总结以及感悟撰写而成,内容均属原创。转载请标明出处。css

怎样能在最快的时间内,实现一个最新版本号 android app 的 pad 化呢?从拿到一个大型手机 app 代码開始开发到第一个其全新 pad 版本号的公布,咱们用了不到3个月时间给出了一份惬意的答案。html

项目背景

採用最新版本号手机 APP(以后称为 MyApp)代码。实现其 Pad 化,为平板和大屏手机用户提供更好的体验。java

为实现 MyApp 的 Pad 化工做。需要咱们首先来了解一下 MyApp 项目经典页面的构成以及 Pad 化后的页面结构的变化。android

1.MyApp 页面经典构成

现在主流手机 APP 主页一般採用标签栏加标签内容方式显示。而经过主页进入的二级页面所有採用全屏方式展现。web

比方手机 QQ,微信,支付宝等等都是採用 Tab 栏方式为主,进入一个详细功能后,全屏打开。咱们项目也是如此。微信

如下看一下 MyApp 项目手机端的页面构成图。markdown

腾讯Bugly
Bugly安卓开发

左側是一个 Tab 栏(区域1)加 Tab Content(区域2)构成的页面。右側是在 TabContent 中点击详细功能后进入的一个功能详情页面(全屏区域3)。
查看代码,发现除 TabContent 区域2,从主页開始到其它全屏显示的页面所有採用 Android Activity 组件实现。经统计得出大概有几百个 Activity。架构

这些 Activity还包括比方Web进程。peak 进程(图片选择查看)等其它非主进程 Activity。app

1.MyApp pad 化的设计图

了解了手机 MyApp 页面构成后,还要来看 Pad 化后 UI 结构的变化,经过对照来探索 Pad 化最佳的实现方案。ide

如下是咱们的 PAD 版本号页面结构图。
这里写图片描写叙述

由于 Pad 平板的空间要远大于手机空间。因此。在主页中 Pad 所展现的内容要比手机不少其它。经过观察设计图发现。整个页面分为了3块区域,与手机端页面的1,2,3区域一一对应。Tab 栏被移到了左側1区,Tab Content 被移到了中间2区。而在2区打开的 Details 页面则要求在3区展现,而再也不是像手机 APP 同样全屏展现。

手机 APP Pad 化道路的探索过程

经过了解 MyApp 项目经典页面构成和 pad 版页面结构的变化,以及高速Pad 化的原则,咱们開始了对手机 APP pad 化实现方案的漫漫探索。


首先想到的是,既然手机APP页面主要是由Activity构成。那么咱们能不能把 Activity 缩小。让多个 Activity 在同一屏幕显示呢。很是快咱们的方案1出来了。

方案1。假设把设计图的整个页面称为主 Activity,主 Activity 全屏显示不变,在主 Activiy 中打开的新 Activity (称为A)缩小显示在设计图3区,咱们就可以实现 Pad 设计的要求。那么咱们详细实现步骤为:
1。A类 Activity 继承 Base Activity
2。改动 Base Activity 的 window 的起始坐标x和宽度 width,让其恰好位于3区。
3,A类 Activity 背景改成透明
4,让在A类 Activity 继续打开的 Activity。反复1,2,3,4步骤。

但是很是快就发现了问题。
1. 在当前 Tab 打开 Activity A,切换 Tab 后 A Activity 仍然显示。
2. 每个 Tab 打开的 Activity,都处于同一个 Activity 栈中,按打开前后顺序加入,点击返回键也是顺序退出的。这样每个 Tab 中打开的Activity 都混在一块儿了,而不是彼此独立。致使 back 键出现故障。

既然直接显示 Actvity 有问题,想一想反正都是显示UI布局,能不能把 A 类 Activity 的根布局拉出来挂载在主 Activity 右側?从而咱们推导出了方案2。

方案2:在主 Activity 启动 A 类 Activity 时,获取 A 的根布局。加入到主 Activity 在右側3区预留的一个空布局中。

详细实现步骤为:
1,重写主 Activity 的 startActivity 方法。
2。使用 LocalActivityManager 启动 A 类 Aactivity 返回 window 对象。
3,经过 Window 对象 window.getDecorView()返回打开 Activity 的布局并 Add 到主 Actvity 上。


4,重写主 Activity 的 Back 逻辑,在点击返回键时 remove 掉挂载的 decorView。

但是在 Demo 上一測试,就发现了很是多问题。
1. 用 mat 查看到 A 类 Activity 是怎么也释放不掉的,由于 LocalActivityManager 已经抓住了 A 类 Activity 的 parent。


2. 直接拿出 A 类 Activity 的 decorView,已经让A类 Activity 丧失了 Activity 的一切特性,包括生命周期,返回逻辑,ActivityResult,以及启动其它 Activity 等功能。

会致使以前正常执行的A类 Activity 出现大量问题。

既然直接拿到根视图没实用。那该怎么作才好呢?怎么作才干使 A 类 Activity 的页面挂载在主 Activity 右側。又能保证 A 的生命周期和 Activity 行为呢?通过你们一番思考讨论后。能不能利用插件的思想,把 A 类 Activity 中的生命周期方法以及继承自 Activity 类的方法都拿出来了,在适当时候本身调用呢?这样就保证了原来 A 中的代码不会出现故障,不需要改动 A 中的不论什么代码。但是用什么作容器(代理)比較好了?以后咱们想到了用 Fragment,。由于 Fragment 可以做为所属 Activity 的一个块存在于不论什么位置,而且 Fragment 有本身的生命周期,并受所属 Activity 的生命周期影响。它就像一个子 Activity 同样。简直是绝佳容器。而且 Fragment 比較轻量。自己由 Activity 来管理(而不像 Activity 由 Android 系统服务管理),在不一样的布局结构中重用 Fragment 可以优化屏幕空间和用户体验。


注意。如下所说的把 Activity 转换为 Fragment 并不是直接把 Activity 变为 Fragment,这会付出巨大代价。而是以一个空的 Fragment 为容器来承载 Activity。

最终方案3顺利出炉。

方案3,把 Activity 转换为 Fragment。使用 Fragment 模拟 Activity 的方法。

而后把 Fragment 直接加入到主 Activity 的右側布局中。

实现的详细步骤为:
1,新增 BasePadActivity,让所有 Activity 继承 BasePadActivity,重写 StartActivity 方法。在该方法中手动 New 出A类 Activity,并把主 Activity 的上下文对象 Context 传递给它。


2,建立 MyFragment,持有A类 Activity 实例引用,在 MyFragment 生命周期中直接调用A类 Activity 生命周期方法,并把A类 Activity 的视图传递给 Fragment 使用。


3,A类 Activity 中继承自 Activity 的方法所有重写,详细实现由步骤1中的获得的主 Activity 上下文 context 处理。这样A类 Activity 已经成为一个普通实例化对象,再也不由 Android 系统管理。

该方案有较多长处,由于继承 base。不只能迅速将大量 Activity 快换为 Fragment。而且转换后,使原来A类 Activity 的功能逻辑维持正常。

而且由于A类 Activity 的上下文事实上使用了主 Activity 的上下文对象,需要在A类 Activity 获取 Resouce。Window,Asset 对象等都能经过主 Activity 的 context 进行获取。


该方案实现后,最初測试好像一切正常,但是不就后也发现了若干问题:
1. 原 Activity 本身定义 TitleBar 出现故障。
2. 每个 Tab 标签中打开的 Fragment,由于都属于一个主 Activity,致使它们仅仅有一个 Fragment 栈,Back 返回时会出现与方案1类似的问题。


3. 虽然 Activity 转换为 Fragment 后,大部分行为都进行了模拟,但是另外一些重要行为没有作处理,比方说 Activity 的启动模式。Back 键,onActivityResult 等等,这些还要进行无缺。
4. 对于声明为多进程的 Activity。转换为 Fragment 后失去了多进程的特性。由于这些 Fragment 属于主 Activity,主 Activity 是属于手Q进程的。

该方案虽然也有诸多问题,但是通过调研和測试,发现基本都是能解决的。出于该方案的长处,以及对其出现的问题的解决难易评估,最终决定在该方案基础上进行优化和无缺。那么对上述出现的若干问题该怎样解决呢?

问题1。Activity 替换成 Fragment 以后。怎样实现本身定义 TitleBar?

设置本身定义 TitleBar,是 Activity 所提供的接口,查看手机APP代码,大部分 Activity 都继承了 TitleBarActivity。经过

getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
            R.layout.custom_commen_title);

来定义 TitleBar 的样式。因此改成 Fragment 以后致使大量 Activity titlebar 显示不出。甚至 crash。

那么能不能实现一个本身定义的 window 对象继承 android.view.Window,经过 getWindow()获得的是咱们本身定义的 Window 对象,它可以处理本身定义 Titlebar 的使用。

问题2。怎样确保每个标签页中 Fragment 的操做互不干扰?

Pad 版本号主页也是分为多个 Tab 标签栏的,每个标签栏中对 Fragment 的操做应该是相互独立的。

Android中Fragment都是由 FragmentManager 来管理的。

Fragment 的加入,替换,移除等操做都是由 FragmentManager 中对象 FragmentTransaction 来记录和执行。每个 Activity 中仅仅有一个 FragmentManager 实例。经过代码
Activity.java

final FragmentManagerImpl mFragments = new FragmentManagerImpl();
public FragmentManager getFragmentManager() {
    return mFragments;
}

获取。假设把设计图中的整个页面称为主 Activity,用主 Activity 中一个 FragmentManager 来管理所有标签栏的 Fragment 显然会引发混乱,那么可否实现每个标签页中都有一个 FragmentManager 的实例来管理当前标签中所有 Activity 转换的 Fragment?

问题3:Activity 替换成 Fragment 以后,无缺 Fragment 模拟 Activity 的行为。

无缺 Fragment 的 Activity 行为。比方还需要模拟 Activity 的启动模式、Activity result、startActivity、finish、onBackPressed 等等。

问题4。怎样处理多进程 Activity 的显示?

在回答这个问题以前。要先问一个问题,为何不都转换为 Fragment 呢?
以前研究手机 APP 项目代码发现,不少Activity都是设计成属于其它进程,比方 Web 进程。这样设计的缘由:

其一是这类 Activity 功能都是属于同一模块。出现 crash 也不会让整个QQ崩溃。
另一个重要缘由是,Android 平台对每个进程都有内存限制。使用多进程就可以使APP所使用的内存加大几倍。其它进程可以分担主进程的内存压力。大大减小内存溢出致使的 crash。

因此不能轻易把这些 Activity 转换为 Fragment。由于转换为 Fragment,就失去了 Activity 多进程的特性,违背了以前设计初衷,大大添加了APP的内存压力。

那么这种状况下可否让多个 Activity 在同一屏幕显示,能不能让从主 Activity 打开的新 Activity 变为透明,而且让其大小和位置恰好覆盖设计图的区域3。同一时候让属于主 Activity 的区域1,和区域2接收事件。这样既让 Acitvity 拥有多进程的特性,又让他们看起来就像是在同一个 Activity 中操做。咦,这不是咱们的方案1吗? 对的,由于以上种种缘由,对于多进程的 Activity,咱们仍是要依照方案1来处理。

那么怎样解决解决方式1中的问题。

问题5。多进程的 Activity 在切换标签后怎样处理?Back 键怎样处理?

在每个标签页打开的多进程 Activity,应该仅仅与本标签页有关联,在切换到其它标签后。这些 Activity 应该隐藏起来,又一次再切换 Tab 回到该标签时,以前在该标签打开的这些 Activity 应该又一次显示。

而且每个 Tab 的 Activitys 都应该有一个 Activity 栈来管理。
这该怎样实现呢?经过阅读http://developer.android.com/guide/components/tasks-and-back-stack.html了解到
一个 app 中一般包括若干个 Activitys,咱们可以把这些 Activity 分为若干类。让每一类都属于同一个 Task,以多任务的方式把这些 Activity 分为若干组。

比方把在 Tab1栏内打开的多进程 Activity 放入一个Task中。把Tab2中打开的多进程 Activity 放入另一个 Task 中。切换 tab 时,仅仅需要让两个 task 交替移到前台显示或后台隐藏就能够,而且每个Task中都维护着一个 Activity 栈。该想法彷佛能解决问题。

那么看到这里你们又会有另一个疑问了?既然能解决方式1中的问题,为何不直接所有使用方案1呢?还要把Activity转为Fragment干吗?
1。实现的问题,使用多Task的实现方式,在Android中需要声明Activity的TaskAffinity,而 TaskAffinity 不能在代码中动态声明。而仅仅能写在配置文件里,致使不一样Tab打开的同一个Activity可能需要在配置文件里声明两次,由于它们的 TaskAffinity 要不同,而同一个Activity是不能声明两次的。因此仅仅有写一个空的 Activity 继承它。致使大量空Activity产生,而且在代码中启动 Activity 前还要重定向到继承的Activity。比較麻烦。多进程 Activity 毕竟仍是少数,因此可以这么作。

但所有这样实现明显不太可取。

2。体验的问题,当切换 Tab,把 Task 移入前台,会有一个延时。而且这个延时并不肯定,致使切回 tab,会先显示底部的页面,而后 task 中Activity 才覆盖上来。

3。机型的问题,极少数机型多是由于厂家定制的缘由,在多个 Activity 显示在同一屏幕时会有一个问题,在接收左側主 Activity 的事件时,A类 Activity 会消失。通过缘由查找,发现A类 Activity 的 task 本身主动回到了后台。应该是系统源代码被改动了。这种话基本无法用了。

通过你们若干分析讨论,咱们基本理清楚了方案3所遇到问题的大体解决版本号,通过均衡考虑,使用如下解决方式是眼下 Pad 化最好的解决方式。

APP 高速 Pad 化实现架构方案

对 MyApp pad 化的整个流程以及会遇到的问题理清楚以后。通过思考和你们的讨论肯定了咱们手机端 APP Pad 化的架构方案:

1,转换 APP 主进程的 Activity 为 Fragment,转换过程尽可能不改动原来 Activity 的不论什么代码。
2,让转换后的 Fragment 模拟 Activity 的行为。保持 Fragment 和原来 Activity 的行为一致。


3,使用 LocalActivityManager 实现每个 Tab 标签 Fragments 操做的独立性。
4,多进程 Activity(包括插件 Activity)不转换为 Fragment,实现多任务分屏显示。

1,巧妙转化 Activity 为 Fragment

实现 BasePadActivity 为所有 Activity 基类,对 Activity 转换为 Fragment 的操做在 BasePadActivity 中实现,利用类似插件的想法。以Fragment为壳,把真正详细的实现从 Activity 中搬入 Fragment,而不需要改动原 Activity 的不论什么代码。经过重写 StartActivity 方法。让原来去 startActivity 的动做变为加入一个新的 Fragment 动做,并调用 addToBackStatck()方法加入到 Fragment 栈中。


如下给出部分伪代码的实现 。注意如下代码都是伪代码,很是多仅仅有方法而无实现, 这里主要是讲思路

BasePadActivity.java  

public class BasePadActivity extends Activity{
    /**
     * 经过重写startActivityForResult来将Fragment转换为Activity
     */
    @Override
    public void startActivityForResult(Intent intent) {
        if (isfragment && !isNewProcessActivty()){ //多进程Activity不转换为Fragment
                //初始化activity,注意该Activity是咱们本身实例化出来的
                BasePadActivity activity =(BasePadActivity)newInstance(intent);
                activity.attachBaseContext(getBaseContext()) 
                activity.onCreate(intent.getExtras());  //模拟Activity的onCreate
                activity.addMyFragment();
            }
        }
    }

    public class MyFragment extends Fragment {
        @Override
        public View onCreateView() {
            View contentView = getWindow().getDecorView();   //Fragment的View为Activity的decorView
            return contentView;
        }

        @Override
        public void onResume() {
            super.onResume();
            BasePadActivity.this.onResume();  //模拟Activity 
        }

        @Override
        public void onPause() {
            super.onPause();
            BasePadActivity.this.onPause(); //模拟Activity onPause
        }
        ........
        ........
    }
}

代码巧妙实现了所有继承 BasePadActivity 的 Activity 转换为Fragment 的过程,固然这里仅仅展现了转换一小部分。其它细节问题并无在代码中列出来。当打开 Activity 的过程转换为打开 Fragment 的过程后。咱们需要让 Fragment 模拟 Activity 的行为。

2,Fragment 模拟 Activity 的行为

模拟 Activity 的 finish 方法

BasePadActivity.java    

 public void finish() {  
    if (bActivityToFragment) {
        removeTopFragment(); //移除Fragment栈中最顶层Fragment
    } 
}

模拟 Activity 的 onActivityResult,在当前 Fragment 被 finish 去触发

private void removeTopFragment() { if(popBackStackImmediate()){ //成功把顶层Fragment,从Fragment栈中移出。

handleSetResult(requestCode,false); } } private void handleSetResult(int requestCode){ //触发上层Fragment的onActivityResult topFragment.onActivityResult(requestCode, resultCode, data); }

模拟 Activity 的返回事件,当把 Activity 转换为 Fragment 时。其返回事件已经由该 Fragment 所属的 Activity 接收。所以需要处理其所属真正 Activity 的返回事件。经过 FragmentManager 可以管理该 Activity 中所有 Fragment。

BasePadActivity.java     

public void onBackPressed() {
    if(isActivityForFragment()){  //,为Fragment所属Activity
        if(!handleFragmentBackEvent()){  //先处理Fragment自己的返回事件。比方想先关闭当前Fragment菜单。
            finishTopFragment();  //最后finish该Fragment
        }
    }
}

模拟 Activity 的启动方式,经过获取 intent.getFlags()值。来推断 Activity 的启动模式,经过

public boolean hasFlagClearTop(int flags){
     return  (flags & Intent.FLAG_ACTIVITY_CLEAR_TOP )!=0  ;
}

public boolean hasFlagNewTask(int flags){
    return  (flags & Intent.FLAG_ACTIVITY_NEW_TASK )!=0  ;
}

来推断 Flag 中是否包括对应启动方式值。来对 Fragment 的打开作对应处理。这里会略微麻烦一点。故不做代码说明了。

3。Fragment 实现本身定义的 TitleBar

在不改变原来 Activity 代码的状况下。经过改变 Window 对象,本身实现对 Fragment 布局的控制。实现本身定义 Titlebar。
BasePadActivity.java

public Window getWindow() {
    if(customWindow==null){   //本身定义的window,主要为了解决很是多Activity继承IphoneTitleBar的问题
            customWindow = new Window4FragmentTitle(mContext); 
        }
        return customWindow;
}  

Window4FragmentTitle.java    

public class Window4FragmentTitle extends Window{
    @Override
    public void setContentView(View view, LayoutParams params) {
        if (mContentParent == null) {
            installDecor();
        } 
        mContentParent.addView(view, params);
    }

    @Override
    public void setFeatureInt(int featureId, int value) {
         if(featureId != FEATURE_CUSTOM_TITLE){
             return;
         }
         FrameLayout titleContainer = (FrameLayout) findViewById(android.R.id.title);
         if (titleContainer != null) {
             mLayoutInflater.inflate(value, titleContainer);
         }
    }
}

经过 Window4FragmentTitle 调用 setFeatureInt(int)方法,会把本身定义的 Title 布局嵌入到咱们建立的布局 mDecor 中,而后把 mDecor 放入 Fragment,实现本身定义 Titlebar 在 Fragment 中的显示。

4。使用 LocalActivityManager,实现对每个 Tab 中 Fragments 的独立管理。

使用 LocalActivityManager 实现标签布局,使每个 Tab 中都有一个 Acitvity 对象。而每个 Activity 中都会有一个 FragmentManager 对该 Tab 的 Frament 栈进行管理。这样每个 Tab 的 Fragments 相互独立,互不影响。
主Activity

addFrame(Tab1Content.class, mTabs[1]);   //Tab1
    addFrame(Tab2Content.class, mTabs[2]);    //Tab2
    .....
    public void addFrame(){
        mTabHost.setup(getLocalActivityManager());
        TabSpec tabSpec = mTabHost.newTabSpec("").setIndicator(tab).setContent(new Intent(this, clz));
        mTabHost.addTab(tabSpec);

    }

经过 setContent(new Intent(this, clz) ,把每个标签栏内容以子 Activity 的方式加入进来。

5,多任务分屏显示。

前面说过。对于多进程的 Activity。为了保持其模块化以及分担主进程内存压力的特色,通过你们讨论,不把他们转换为 Fragment,那么就需要解决多个 Activity 一块儿展现的问题。通过研究,得出的有效实现方式是:让在每个标签栏内打开的 Activity 透明化,而且让其大小和位置恰好居于设计图3区,同一时候能让处于该 Activity 下方的左側区域的主Activity 接收点击事件

1,Activity 透明化实现,在配置文件里声明 Activity 的 theme 为透明
2,定义 Activity 的大小和位置。


在 Activity 的 onCreate 方法中实现

WindowManager.LayoutParams layoutParams = window.getAttributes();
layoutParams.gravity = Gravity.RIGHT | Gravity.TOP;  //位置居于右側
layoutParams.width =  mActivity.getRightPanelWidth(); //宽度为右側区域宽度

* 3,让左側主 Activity 接收事件*
经过设置 window 的 WindowManager.LayoutParams 的 flag 为 FLAG_NOT_TOUCH_MODAL 可以让显示在透明 Activity 左側下方的主 Activity 接收事件。
新打开的 Activity 位于右区,左区为主 Activity 显示区域。左区和右区能同一时候接收用户点击事件,看起来就好像同一个 Activity 同样。

但是由于在当前 Tab 打开的位于右区的 Activity,是尾随当前Tab的,在切换 Tab 后,应该消失。比方 Tab1中打开的 Actvity。切换到Tab2时应该隐藏掉。又一次再切换回 Tab1时让其又一次显示。保留现场。该功能要怎样实现呢?通过对 Android 特性的理解以及思考。发现可以是用多任务分屏显示方式实现不一样 Tab 多进程 Activitys 的显示和隐藏。让不一样Tab打开的 Activitys 分属于不一样 Task,每个 task 拥有一个 Activity 栈来管理当中 Activity,切换 tab 要作的就是不一样 Task 的切换。

这样逻辑很是清楚,也符合高速 Pad 化的原则。那么详细该怎么实现呢?
为每个 Tab 打开的第一个 Activity 提供一个不一样的 TaskAffinity
首先咱们来了解。什么是 TaskAffinity
在某些状况下。Android 需要知道一个 Activity 属于哪一个 Task,这是经过任务共用性(TaskAffinity)完毕的。TaskAffinity 为执行一个或多个Activity 的 task 提供一个独特的名称,当使用 Intent.FLAG_ACTIVITY_NEW_TASK 标志的 Activity,并为该 Activity 声明一个独特的 TaskAffinity 时,该 Activity 再也不执行在启动它的 Task 里。而是会又一次启动一个新的 Task,新的 task 管理一个新的 Activity 栈。而打开的这个 Activity 则位于栈底。
了解了 TaskAffinity,咱们在配置文件里为打开的多进程 Activity 设置相关 tab 的 TaskAffinity 值
如下展现对 web 进程 Activity 的处理

<activity
  android:name=" BrowserActivity1"
  android:process=":web"
  android:taskAffinity="com.tab1. BrowserActivity1" 
  android:theme="@style/Default.Transparent" />

<activity
  android:name=" BrowserActivity2"
  android:process=":web"
  android:taskAffinity="com.tab2.BrowserActivity2" 
  android:theme="@style/Default.Transparent"/>

........

在不一样 Tab 打开的 BrowserActivity,都为它们设置了不一样的 TaskAffinity,在代码中当发现打开的页面是 Web 页面时,则在哪一个Tab打开。页面重定向到设置了对应 TaskAffinity 的 Activity上。

public void startActivityForResult(Intent intent) {
  if(isBrowserActivity(intent)){   //纯打开QQBrowserActivity
    int curTab = getTabIndex();  //获取当前Tab索引
    Class<?> c = getBrowserMap().get(curTab);  //取出对应打开的Activity
    redirectAndOpenInNewTask()    //重定向    
  }
  ......
  ......
}

这样就为在不一样 Tab 打开的 Activity 建立了不一样的 Task。而后在切换Tab时经过发送广播动态的显示和隐藏 Task。

public void onTabSelected(int curTabIndex) {
    Intent i = new Intent("action");
    i.putExtra("cur_Tab_Id",curTabIndex);    //切换到当前Tab的索引
    sendBroadcast(i);
}

在 Task 的根 Activity 中接收广播,处理 Task 显示和隐藏逻辑

public void onReceive(Context context, Intent intent) {
        int tab = intent.getIntExtra(CUR_TAB_ID,-1);
            if(tabIndex>=0 && tabIndex == tab){
                 moveTaskToFront(mActivity.getTaskId());   //移动当前Task移入后台
            }else{
                 moveTaskToBack();  //把该Activity所属Task移动到前台

            }
    }

到这里基本上攻克了多进程 Activity 与主 Activity 同屏显示所带来的问题。

总结

经过上述方案。以及一些问题的巧妙解决。最终实现了 MyApp Pad 化的高速开发,而且 MyApp for Pad 第一个版本号的公布上线。到现在6到7个版本号的迭代,一直都是稳定执行的。该方案的长处是,仅仅要维护好架构,其它开发人员在对单个页面改造时。不需要管它是真正 Activity 仍是 Fragment,仅仅要知道这些页面表现的都是 Activity 的行为,就和在手机 APP 上开发是同样的。

扩展

经过 MyApp Pad 化开发方案的实现,咱们想咱们这个方法可否够写成一个通用的手机 App Pad 化组件。为公司的其它Android产品Pad化提供技术支持。就算你的 APP 布局并不是 Tab 方式,咱们开放出一个 Base Activity。其它 App 的 Activity 经过继承 Base,就能本身主动转换为Fragment,而且能为多进程 Activity 提供处理方案。

但这确定需要考虑不少其它的状况。和解决不少其它问题。路漫漫其修远兮。吾将上下而求索。

期待无缺的 Android App PAD 组件能与你们见面。

假设你认为内容意犹未尽。假设你想了解不少其它相关信息。请扫描如下二维码。关注咱们的微信公众帐号,可以获取不少其它技术类干货,还有精彩活动与你分享~
这里写图片描写叙述

腾讯 Bugly是一款专为移动开发人员打造的质量监控工具。帮助开发人员高速,便捷的定位线上应用崩溃的状况以及解决方式。智能合并功能帮助开发同窗把天天上报的数千条 Crash 依据根因合并分类。每日日报会列出影响用户数最多的崩溃,精准定位功能帮助开发同窗定位到出问题的代码行,实时上报可以在公布后高速的了解应用的质量状况,适配最新的 iOS, Android 官方操做系统。鹅厂的project师都在使用,快来加入咱们吧。

相关文章
相关标签/搜索