自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

模仿Android微信小程序,實(shí)現(xiàn)小程序獨(dú)立任務(wù)視圖的效果

移動(dòng)開發(fā) Android
小程序相信現(xiàn)在所有人都使用過的對(duì)吧,很多人甚至天天都在使用。小程序特別的方便,無(wú)需下載,無(wú)需安裝,在微信當(dāng)中打開就能立刻使用。隨取隨用,隨用隨走,也不占用任何手機(jī)的存儲(chǔ)空間。

?今天跟大家分享一個(gè)非常有趣的技術(shù),如何在我們的App中實(shí)現(xiàn)類似于微信小程序的功能。

哈哈開個(gè)玩笑,如果我能徒手實(shí)現(xiàn)一套微信小程序系統(tǒng)的話,早就被騰訊挖過去當(dāng)架構(gòu)師了。

小程序相信現(xiàn)在所有人都使用過的對(duì)吧,很多人甚至天天都在使用。小程序特別的方便,無(wú)需下載,無(wú)需安裝,在微信當(dāng)中打開就能立刻使用。隨取隨用,隨用隨走,也不占用任何手機(jī)的存儲(chǔ)空間。

而Android上的微信小程序做得格外的像一個(gè)真正的應(yīng)用程序。為什么這么說呢?因?yàn)锳ndroid上的每個(gè)微信小程序甚至還能擁有自己的任務(wù)視圖,就像是一個(gè)真正的獨(dú)立應(yīng)用程序一樣。點(diǎn)擊手機(jī)任務(wù)欄鍵可以看到如下界面:

圖片

上圖中美團(tuán)外賣、微博熱搜、星巴克都是小程序。

擁有獨(dú)立的任務(wù)視圖的話,就可以更加方便地在多個(gè)小程序或微信本體之間進(jìn)行快速切換,在這點(diǎn)上Android的體驗(yàn)要比iOS更好。

那么問題來(lái)了,這種依附于其他程序的小程序是如何做到擁有一個(gè)獨(dú)立的任務(wù)視圖的呢?

本篇文章我們就來(lái)一探究竟。

事實(shí)上,這是一個(gè)很基礎(chǔ)的功能。有多基礎(chǔ)呢?任何一位Android開發(fā)者在入門時(shí)都一定學(xué)過這個(gè)知識(shí):Launch Mode。

因此,我就不在這里對(duì)Launch Mode進(jìn)行展開講解了。如果你真的從來(lái)沒有聽說過Launch Mode,建議參考《第一行代碼 第3版》第3章的內(nèi)容。

我們都知道,Android中Activity的啟動(dòng)模式一共有4種:standdard、singleTop、singleTask和singleInstance。

從字面意思上來(lái)看,singleTask表示的就是要啟用一個(gè)單獨(dú)的任務(wù)來(lái)存放當(dāng)前Activity。但假如你把一個(gè)Activity聲明成了singleTask,你會(huì)發(fā)現(xiàn)并不能得到我們想要的效果,所有的Activity仍然是放在同一個(gè)任務(wù)當(dāng)中的。

這是因?yàn)椋瑂ingleTask還會(huì)關(guān)聯(lián)一個(gè)叫taskAffinity的屬性,只有被聲明成singleTask的Activity,且它的taskAffinity值也是獨(dú)立的,那么這個(gè)Activity才會(huì)被放在一個(gè)單獨(dú)的任務(wù)當(dāng)中。

而默認(rèn)情況下,每個(gè)Activity的taskAffinity屬性值都是當(dāng)前應(yīng)用程序的包名,也就是說它們的值都是相同的,所以才不能得到我們想要的效果。

那么解決方法也很簡(jiǎn)單,給每一個(gè)要啟用獨(dú)立任務(wù)視圖的Activity都賦值一個(gè)不同的taskAffinity值即可。

接下來(lái)我們就開始動(dòng)手實(shí)踐一下吧。

首先創(chuàng)建一個(gè)叫MiniProgramTest的項(xiàng)目。

接下來(lái)創(chuàng)建3個(gè)空的Activity,分別給它們起名為FirstActivity、SecondActivity和ThirdActivity。

然后編輯項(xiàng)目的activity_main.xml布局文件,在里面加入3個(gè)按鈕,分別用于啟動(dòng)FirstActivity、SecondActivity和ThirdActivity:

<androidx.constraintlayout.widget.ConstraintLayout 
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<Button
android:id="@+id/first_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="啟動(dòng)第一行代碼"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintBottom_toTopOf="@+id/second_btn"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<Button
android:id="@+id/second_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="啟動(dòng)第二行代碼"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintBottom_toTopOf="@+id/third_btn"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/first_btn" />

<Button
android:id="@+id/third_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="啟動(dòng)第三行代碼"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/second_btn" />

</androidx.constraintlayout.widget.ConstraintLayout>

布局文件定義好了之后,接下來(lái)修改MainActivity的代碼,加入啟動(dòng)邏輯:

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

val firstBtn = findViewById<Button>(R.id.first_btn)
val secondBtn = findViewById<Button>(R.id.second_btn)
val thirdBtn = findViewById<Button>(R.id.third_btn)

firstBtn.setOnClickListener {
val intent = Intent(this, FirstActivity::class.java)
startActivity(intent)
}
secondBtn.setOnClickListener {
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)
}
thirdBtn.setOnClickListener {
val intent = Intent(this, ThirdActivity::class.java)
startActivity(intent)
}
}
}

代碼非常簡(jiǎn)單,點(diǎn)擊哪個(gè)按鈕就去啟動(dòng)相應(yīng)的Activity就可以了。

但如果僅僅是這樣,F(xiàn)irstActivity、SecondActivity和ThirdActivity一定與MainActivity是存放在同一個(gè)任務(wù)當(dāng)中的。

因此下面我們就要去編寫最核心的代碼了,修改AndroidManifest.xml文件,如下所示:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.miniprogramtest">

<application
...>

<activity
android:name=".FirstActivity"
android:exported="false"
android:label="第一行代碼"
android:launchMode="singleTask"
android:taskAffinity="com.example.miniprogramtest.first"
/>

<activity
android:name=".SecondActivity"
android:exported="false"
android:label="第二行代碼"
android:launchMode="singleTask"
android:taskAffinity="com.example.miniprogramtest.second" />

<activity
android:name=".ThirdActivity"
android:exported="false"
android:label="第三行代碼"
android:launchMode="singleTask"
android:taskAffinity="com.example.miniprogramtest.third"
/>
...
</application>

</manifest>

可以看到,這里我們將FirstActivity、SecondActivity和ThirdActivity的launchMode都設(shè)置成了singleTask,并且給它們都指定了一個(gè)不同的taskAffinity。

現(xiàn)在運(yùn)行一下程序,并分別點(diǎn)擊界面上的3個(gè)按鈕,然后按下手機(jī)任務(wù)欄鍵,我們就能看到如下效果了:

圖片

有沒有覺得很神奇?明明都是同一個(gè)App中的3個(gè)Activity,現(xiàn)在我們竟然可以讓它們?cè)?個(gè)獨(dú)立的任務(wù)視圖中顯示,是不是感覺就好像是微信小程序一樣?

不過,雖然FirstActivity、SecondActivity和ThirdActivity都擁有獨(dú)立的任務(wù)視圖了,它們和微信小程序還有一個(gè)非常明顯的差距。

因?yàn)槊總€(gè)程序都有自己專屬的應(yīng)用Logo,小程序也不例外。就像我們?cè)谧铋_始的圖片中看到的一樣,美團(tuán)小程序有美團(tuán)的Logo,微博小程序有微博的Logo,星巴克小程序有星巴克的Logo。

而目前,F(xiàn)irstActivity、SecondActivity和ThirdActivity顯示的都是MiniProgramTest這個(gè)項(xiàng)目的Logo,這使得它們看上去仍然不像是一個(gè)獨(dú)立的應(yīng)用程序。

下面我們就開始著手優(yōu)化這部分問題。

首先,這里我準(zhǔn)備了3張圖片first_line.png、second_line.png、third_line.png,分別用于作為FirstActivity、SecondActivity和ThirdActivity的Logo:

圖片

接下來(lái),編輯FirstActivity、SecondActivity和ThirdActivity的代碼,在里面加入如下邏輯:

class FirstActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_first)
setCustomTaskDescription()
}

private fun setCustomTaskDescription() {
val taskDescription = ActivityManager.TaskDescription(
"FirstActivity",
BitmapFactory.decodeResource(resources, R.drawable.first_line)
)
setTaskDescription(taskDescription)
}
}

class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
setCustomTaskDescription()
}

private fun setCustomTaskDescription() {
val taskDescription = ActivityManager.TaskDescription(
"SecondActivity",
BitmapFactory.decodeResource(resources, R.drawable.second_line)
)
setTaskDescription(taskDescription)
}
}

class ThirdActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_third)
setCustomTaskDescription()
}

private fun setCustomTaskDescription() {
val taskDescription = ActivityManager.TaskDescription(
"ThirdActivity",
BitmapFactory.decodeResource(resources, R.drawable.third_line)
)
setTaskDescription(taskDescription)
}
}

這3段代碼的邏輯基本都是相同的。

核心部分就是調(diào)用了setCustomTaskDescription()方法來(lái)給當(dāng)前Activity設(shè)置一個(gè)自定義的TaskDescription。

所謂TaskDescription就是給當(dāng)前的任務(wù)設(shè)置一個(gè)描述,描述中可以包含任務(wù)的名稱和圖標(biāo)。

那么這里我們給FirstActivity、SecondActivity和ThirdActivity分別設(shè)置了不同的TaskDescription,這樣在任務(wù)視圖當(dāng)中,就可以看到各不相同的應(yīng)用Logo了,如下圖所示:

圖片

其實(shí)到這里為止,我們就把微信小程序的外殼搭建得差不多了。剩下的部分,當(dāng)然也是最難的部分,就是在這個(gè)殼子里面添加小程序的內(nèi)容了。這部分的技術(shù)以前端為主,并不是我擅長(zhǎng)的領(lǐng)域,我也講不了,因此就不再繼續(xù)向下延伸了。

不過或許還有些朋友會(huì)存在這樣的疑惑:目前我們的技術(shù)實(shí)現(xiàn)方案是給每個(gè)小程序定義一個(gè)單獨(dú)的Activity(FirstActivity、SecondActivity和ThirdActivity),而微信小程序卻可以有無(wú)限多個(gè),我們顯然不可能在AndroidManifest.xml文件中注冊(cè)無(wú)限個(gè)Activity,那么微信又是如何實(shí)現(xiàn)的呢?

其實(shí)這只是一個(gè)美麗的誤會(huì),因?yàn)槲⑿判〕绦虿⒉皇强梢杂袩o(wú)限多個(gè),只是你平時(shí)沒有注意這個(gè)小細(xì)節(jié)而已。

我們通過做個(gè)實(shí)驗(yàn)來(lái)驗(yàn)證一下吧,觀察下圖中的效果:

圖片

可以看到,這里我事先依次按照順序打開了嗶哩嗶哩、QQ音樂、微博熱搜、京東購(gòu)物、星巴克,這5個(gè)小程序。

這個(gè)時(shí)候回到微信當(dāng)中,再打開一個(gè)順豐速運(yùn)小程序。

再次回到任務(wù)視圖列表界面,你會(huì)發(fā)現(xiàn)現(xiàn)在多了一個(gè)順豐速運(yùn)的小程序,而最早打開的嗶哩嗶哩小程序卻從任務(wù)視圖列表中消失不見了。

由此可以看出,微信其實(shí)在AndroidManifest.xml文件中也只是放置了5個(gè)占位的Activity。當(dāng)你嘗試打開第6個(gè)小程序時(shí),最先打開的那個(gè)小程序就會(huì)被回收,將它的容器提供給第6個(gè)小程序使用。

好了,本篇文章到這里就結(jié)束了。內(nèi)容其實(shí)非常的簡(jiǎn)單,但是已經(jīng)把在Android上如何實(shí)現(xiàn)小程序外層的架子講明白了。至于如何實(shí)現(xiàn)小程序最核心的內(nèi)容部分,那就要看各位架構(gòu)師的水準(zhǔn)了。?

責(zé)任編輯:武曉燕 來(lái)源: 郭霖
相關(guān)推薦

2017-05-08 15:03:07

微信小程序開發(fā)實(shí)戰(zhàn)

2016-11-04 10:48:37

信小程序

2017-02-06 13:32:12

微信小程序思想

2016-11-22 11:23:52

微信小程序騰訊微信

2016-09-27 16:38:24

JavaScript微信Web

2016-09-27 15:40:58

微信程序前端

2016-11-04 10:49:48

微信小程序

2021-06-10 10:51:27

程序基礎(chǔ)架構(gòu)

2016-10-20 21:02:12

微信小程序javascript

2017-01-09 10:01:49

微信小程序

2017-06-09 10:06:54

微信小程序架構(gòu)分析

2017-06-09 12:58:20

微信小程序架構(gòu)分析

2017-06-09 10:40:00

微信小程序架構(gòu)分析

2016-11-04 10:31:49

微信程序指南

2016-09-28 18:10:59

微信程序MINA

2021-10-28 19:32:16

微信原理程序

2016-11-04 10:30:17

微信小程序

2018-07-26 15:16:50

小程序iPhone X甜酸

2021-03-03 14:23:06

微信小程序互聯(lián)網(wǎng)

2018-08-03 11:10:30

前端小程序vue.js
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)