安卓Presentation

前言

隨著時代的發(fā)展挑胸,單在一塊屏幕上操作應(yīng)用已遠(yuǎn)遠(yuǎn)不能滿足與日俱增的用戶需求宰闰,安卓系統(tǒng)多屏互動也隨即誕生移袍。起初提到多屏幕的交互,開發(fā)者們更多的是想到使用RTP實現(xiàn)的視頻流傳輸螟左,然而傳輸視頻流存在著性能損耗路狮,視頻壓縮蔚约,刷新幀率等多方面的問題苹祟,讓不少想嘗試多屏互動開發(fā)的開發(fā)者望而卻步树枫。其實實現(xiàn)多屏互動也不止是只有視頻流傳輸一條路,今天就讓我們來實現(xiàn)一個使用安卓系統(tǒng)組件Presentation實現(xiàn)的多屏互動應(yīng)用奔誓。

Presentation

A presentation is a special kind of dialog whose purpose is to 
                  present content on a secondary display.  
                                                          ----------Google

從本質(zhì)上來說Presentation只是一個特殊的Dialog而已厨喂,常規(guī)的Dialog是show在了操作屏上,而Presentation是show在了指定的操作屏上派阱,這個指定屏可以是系統(tǒng)的第二塊甚至是第三塊屏幕贫母,同時也可以是主應(yīng)用操作屏盒刚。如果Presentation顯示到了主應(yīng)用屏上伪冰,顯示效果與常規(guī)Dialog無異。
根據(jù)不同的顯示需求,Presentation有兩種顯示方式吓懈,一種是隨應(yīng)用Activity顯示隱藏同步的輔助屏顯示耻警,另一種是常駐輔助屏的保持顯示模式甸怕。如果需要使用常駐顯示模式梢杭,那么Presentation的顯示需要放到Service中武契。

雙屏開發(fā)準(zhǔn)備

常規(guī)的開發(fā)設(shè)備是不俱備輔助屏幕的,開發(fā)調(diào)試雙屏顯示届垫,我們可以借助開發(fā)者模式中的模擬輔助屏幕功能装处。進(jìn)入手機(jī)---設(shè)置---開發(fā)者模式---模擬輔助顯示設(shè)備---選擇一款需要調(diào)試分辨率的屏幕浸船。


模擬輔助屏幕.png

這里需要注意一件事情判族,開發(fā)設(shè)備的系統(tǒng)版本要保證在安卓4.2以上,因為Presentation支持的版本是minSdkVersion >= 17槽惫。開啟輔助顯示設(shè)備的時候默認(rèn)是采用透屏模式界斜,即輔助屏顯示主屏的投影合冀,當(dāng)對輔助屏有定制開發(fā)需求顯示指定界面的時候君躺,就需要用到Presentation了棕叫。


輔助屏.png

雙屏異顯實例

創(chuàng)建輔助屏幕Presentation

輔助屏中有地圖與搜索兩個頁面俺泣,并可以自由的在兩個頁面間進(jìn)行切換。Presentation構(gòu)造函數(shù)中的Context參數(shù)可以是Activity横漏,也可以是ApplicationContext或者是Service缎浇,但如果是ApplicationContext或是Service類型的Context打掘,Presentation的Type類型必須為SYSTEM_ALERT尊蚁。

/**
 * @author : YangHaoYi on 2019/1/2.
 *         Email  :  yang.haoyi@qq.com
 *         Description :雙屏異顯輔助屏幕
 *         Change : YangHaoYi on 2019/1/2.
 *         Version : V 1.0
 */
public class SecondScreenPresentation extends Presentation implements MapFrameLayout.MapCallBackListener,
        SearchFrameLayout.SearchCallBack {

    /** TAG **/
    private static final String TAG = "Presentation";
    /** 根布局 **/
    private FrameLayout fmContent;
    /** 地圖頁 **/
    private MapFrameLayout mapFrameLayout;
    /** 搜索頁 **/
    private SearchFrameLayout searchFrameLayout;

    /** Context 可以為Activity Application Service **/
    public SecondScreenPresentation(Context outerContext, Display display) {
        super(outerContext, display);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.presentation_search);
        init();
    }

    private void init(){
        initView();
        initEvent();
    }
    // ··· 省略頁面初始化與頁面事件代碼
}

搭建Presentation顯示環(huán)境

因為我們所要實現(xiàn)的功能是在應(yīng)用退居后臺也能夠在輔助屏進(jìn)行顯示横朋,所以采用Service進(jìn)行Presentation的顯示,前文提到過Presentation與Dialog的區(qū)別在于衙传,Presentation可以自行選擇顯示的屏幕蓖捶,那么他是怎么控制顯示在指定屏幕上的呢扁远?這里我們需要用到安卓系統(tǒng)的DisplayManager畅买,通過他的getDisplays方法我們可以獲取到當(dāng)前系統(tǒng)所掛載的所有屏幕谷羞,然后對指定的屏幕進(jìn)行Presentation顯示操作。以一塊主屏和一塊輔屏為例犀填,在獲取到displays數(shù)組后宏浩,displays[0]即為我們系統(tǒng)的主屏幕靠瞎,displays[1]即為系統(tǒng)的輔助屏幕乏盐。因為設(shè)置了顯示類型為SYSTEM_ALERT父能,所以這里需要給我們的應(yīng)用添加相應(yīng)的權(quán)限何吝,6.0以上系統(tǒng)記得申請動態(tài)權(quán)限鹃唯。

     /**  彈窗權(quán)限 **/
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    /**  屏幕管理器 **/
    private DisplayManager mDisplayManager;
    /**  屏幕數(shù)組 **/
    private Display[] displays;
    /** 初始化第二塊屏幕 **/
    private void initPresentation(){
        if(null==presentation){
            mDisplayManager = (DisplayManager) this.getSystemService(Context.DISPLAY_SERVICE);
            displays = mDisplayManager.getDisplays();
            if(displays.length > 1){
                // displays[1]是副屏
                presentation = new SecondScreenPresentation(this, displays[1]);
                presentation.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

            }
        }
    }

綁定Presentation服務(wù)

主屏通過綁定服務(wù)開啟Presentation的顯示黔酥,在服務(wù)的onServiceConnected方法中進(jìn)行Presentation的show操作。

/**
 * @author : YangHaoYi on  2019/4/30.
 * Email  :  yang.haoyi@qq.com
 * Description :離屏邏輯控制中心
 * Change : YangHaoYi on  2019/4/30.
 * Version : V 1.0
 */
public class PresentationPresenter {

    private MultiScreenService multiScreenService;
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            multiScreenService = ((MultiScreenService.MultiScreenBinder) service).getService();
            //顯示第二塊屏幕
            multiScreenService.showSearchPresentation();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            //恢復(fù)置空
            multiScreenService = null;
        }
    };

    public void openSearchPresentation(Activity activity){
        Intent intent = new Intent(activity,MultiScreenService.class);
        activity.bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);

    }
}

業(yè)務(wù)邏輯

為了方便對雙屏異現(xiàn)實現(xiàn)功能的理解,這里通過一個簡單業(yè)務(wù)邏輯的示例來展示跪者。主屏幕上顯示地圖應(yīng)用棵帽,地圖具有放大、縮小與跳轉(zhuǎn)搜索頁面的功能渣玲,搜索頁具有搜索與返回地圖頁的功能逗概。輔助屏Presentation上具有和主屏應(yīng)用相同的兩個頁面地圖與搜索頁,同時具有相同的功能事件忘衍。


業(yè)務(wù)邏輯.png

主屏與輔助屏是完全相同的兩個頁面逾苫,筆者做示例Demo采用的是MVP的模式淑履,即View層保證主屏與輔助屏是兩個相同對象隶垮,頁面封裝在MapFrameLayout與SearchFrameLayout中。

    /** 初始化頁面 **/
    private void initPage(){
        mapFrameLayout = new MapFrameLayout(getContext());
        mapFrameLayout.setMapCallBackListener(this);
        fmContent.addView(mapFrameLayout);
        searchFrameLayout = new SearchFrameLayout(getContext());
    }
    
    /** 地圖回調(diào) **/
    @Override
    public void mapCallBackContent(MapFrameLayout.MapEvent event, Object data) {
        switch (event){
            case Search:
                if(null == searchFrameLayout){
                    searchFrameLayout = new SearchFrameLayout(getContext());
                    searchFrameLayout.setSearchBackListener(this);
                    fmContent.addView(searchFrameLayout);
                }else {
                    fmContent.addView(searchFrameLayout);
                }
                break;
            default:
                break;
        }
    }

Model層與Presenter層完全復(fù)用秘噪。

/**
 * @author : YangHaoYi on  2019/4/3017:23.
 * Email  :  yang.haoyi@qq.com
 * Description :搜索數(shù)據(jù)中心
 * Change : YangHaoYi on  2019/4/3017:23.
 * Version : V 1.0
 */
public class SearchModel {

    /**
     *  轉(zhuǎn)換搜索數(shù)據(jù)
     * @return 搜索結(jié)果
     * **/
    public SearchResultData doNearbySearch(){
        SearchResultData resultData = new SearchResultData();
        resultData.setCode(0);
        resultData.setDescription("請求成功");
        SearchResultData.PayloadData payloadData = new SearchResultData.PayloadData();
        payloadData.setTitle("市圖書館");
        payloadData.setAddress("遼寧省沈陽市沈河區(qū)青年大街205號");
        payloadData.setNotice("市圖書館");
        payloadData.setLat("41.765923");
        payloadData.setLng("123.442674");
        return resultData;
    }
}


/**
 * @author : YangHaoYi on  2019/4/3010:54.
 * Email  :  yang.haoyi@qq.com
 * Description :搜索邏輯控制中心
 * Change : YangHaoYi on  2019/4/3010:54.
 * Version : V 1.0
 */
public class SearchPresenter {

    /** 搜索數(shù)據(jù)Model **/
    private SearchModel searchModel;
    /** 搜索View接口 **/
    private ISearchView searchView;

    public SearchPresenter(ISearchView searchView) {
        this.searchView = searchView;
        searchModel = new SearchModel();
    }

    /** 執(zhí)行搜索 **/
    public void nearbySearch(){
        searchView.showSearchResult(searchModel.doNearbySearch());
    }

}

主屏與輔助屏事件支持同屏同顯與同屏異顯兩種模式狸吞,同屏同顯即主屏操作事件的時候同步給輔助屏,可以通過事件總線EventBus或者RxBus實現(xiàn)指煎。頁面數(shù)據(jù)的刷新與變更可以使用總線機(jī)制實現(xiàn)蹋偏,也可以使用 Jetpack的LiveData實現(xiàn),基于谷歌 Jetpack的LiveData實現(xiàn)可以參考筆者關(guān)于LiveData的文章《基于DataBinding與LiveData的MVVM實踐(Kotlin)》至壤。

同屏同顯.png
同屏異顯.png

多屏顯示性能分析

CPU占用

我們知道威始,在一個典型的顯示系統(tǒng)中,一般包括CPU像街、GPU黎棠、Display三個部分。CPU 計算屏幕數(shù)據(jù)镰绎、GPU 進(jìn)一步處理和緩存脓斩、最后 Display 再將緩存中(buffer)的屏幕數(shù)據(jù)顯示出來。而CPU計算屏幕數(shù)據(jù)指的就是View樹的繪制過程畴栖,也就是窗體對應(yīng)的視圖樹從根布局 DecorView 開始層層遍歷每個 View随静,分別執(zhí)行測量、布局吗讶、繪制三個操作的過程燎猛,對于多屏顯示來說,因為新增了一個輔助屏幕的頁面展示照皆,勢必會增加CPU的占用重绷。
讓我們通過Android Studio的Android Profiler來實際看一下CPU的使用情況:


輔助屏_顯示設(shè)置頁_CPU.png
序號 時間節(jié)點 CPU峰值 CPU均值
1 輔助屏設(shè)置頁顯示之前 11.9% 9.7%
2 輔助屏開始顯示設(shè)置頁10s取樣 28.5% 26.3%
3 輔助屏顯示設(shè)置頁后 21.2% 16.1%
輔助屏_顯示地圖頁_CPU.png
序號 時間節(jié)點 CPU峰值 CPU均值
1 輔助屏地圖頁顯示之前 13.3% 12.5%
2 輔助屏開始顯示地圖頁10s取樣 60.5% 43.2%
3 輔助屏顯示地圖頁后 41.9% 37%

可以看到CPU的占用情況與輔助屏頁的繪制相關(guān),普通頁面CPU占用約提升0.7纵寝,顯示雙屏UI后CPU占用均值16.1%论寨⌒橇ⅲ基于SurfaceView的地圖頁面CPU占用提升1.5,顯示雙屏UI后CPU占用均值37%葬凳。

內(nèi)存占用

多屏顯示增加CPU占用的同時也將引發(fā)更多的內(nèi)存分配绰垂,內(nèi)存的占用與頁面的復(fù)雜度息息相關(guān),頁面使用的對象越豐富火焰,特效越復(fù)雜劲装,帶來的內(nèi)存消耗也就越多,通常來說有些功能本身就會很耗內(nèi)存昌简,例如視頻直播占业,音樂播放,地圖顯示等纯赎。
同樣的谦疾,讓我們繼續(xù)通過Android Studio的Android Profiler分析一下多屏顯示的內(nèi)存占用情況:


輔助屏_設(shè)置頁_內(nèi)存.png
序號 時間節(jié)點 內(nèi)存占用峰值 內(nèi)存占用均值
1 輔助屏設(shè)置頁顯示之前 82.5MB 82.1MB
2 輔助屏開始顯示設(shè)置頁10s取樣 85.4MB 85MB
3 輔助屏顯示設(shè)置頁后 86.1MB 86MB
輔助屏_地圖_內(nèi)存.png
序號 時間節(jié)點 內(nèi)存占用峰值 內(nèi)存占用均值
1 輔助屏地圖頁顯示之前 86MB 85.4MB
2 輔助屏開始顯示地圖頁10s取樣 100.6MB 60MB
3 輔助屏顯示地圖頁后 73MB 60MB

可以看到內(nèi)存占用情況與頁面負(fù)責(zé)度相關(guān),當(dāng)輔助屏為普通頁面的情況下犬金,內(nèi)存占用只增加了4MB左右念恍,內(nèi)存平穩(wěn)。當(dāng)輔助屏為基于SurfaceView的地圖頁面的情況下晚顷,內(nèi)存拉升20MB左右峰伙。

示例源碼

文章對Presentation功能展示的Demo已上傳GitHub,感興趣的朋友可以clone下來共同探討一下该默。
GitHub源碼鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瞳氓,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子栓袖,更是在濱河造成了極大的恐慌匣摘,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件裹刮,死亡現(xiàn)場離奇詭異恋沃,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)必指,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來恕洲,“玉大人塔橡,你說我怎么就攤上這事∷冢” “怎么了葛家?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長泌类。 經(jīng)常有香客問我癞谒,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任弹砚,我火速辦了婚禮双仍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘桌吃。我一直安慰自己朱沃,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布茅诱。 她就那樣靜靜地躺著逗物,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瑟俭。 梳的紋絲不亂的頭發(fā)上翎卓,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機(jī)與錄音摆寄,去河邊找鬼失暴。 笑死,一個胖子當(dāng)著我的面吹牛椭迎,可吹牛的內(nèi)容都是我干的锐帜。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼畜号,長吁一口氣:“原來是場噩夢啊……” “哼缴阎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起简软,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤蛮拔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后痹升,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體建炫,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年疼蛾,在試婚紗的時候發(fā)現(xiàn)自己被綠了肛跌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡察郁,死狀恐怖衍慎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情皮钠,我是刑警寧澤稳捆,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站麦轰,受9級特大地震影響乔夯,放射性物質(zhì)發(fā)生泄漏砖织。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一末荐、第九天 我趴在偏房一處隱蔽的房頂上張望侧纯。 院中可真熱鬧,春花似錦鞠评、人聲如沸茂蚓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽聋涨。三九已至,卻和暖如春负乡,著一層夾襖步出監(jiān)牢的瞬間牍白,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工抖棘, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留茂腥,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓切省,卻偏偏與公主長得像最岗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子朝捆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353