题记
闲来无事,折腾下AS,突然就想到我一个承诺且未完成的任务:把AS新建的模板Activity整理一遍,顺便熟悉下Kotlin和JetPack。想到有些的小伙伴已经被我忽悠到是用Kotlin了,心中窃喜,一鼓作气的继续走在前面吧。
简单且实用,有趣且规整,是我对这个几个模板类的总结。
我也不知道正文该起什么标题的标题
1.新建与使用
AS左上角File→New→Act→可以点开Gallery看看具体外观。
2.工程结构
点击Next,系统会自动生成需要的一切。这里主要分为俩部分,分别是java目录下和res目录下的文件。
2.1 java文件夹
我是新建了一个nav包,所以生成的相关的文件都在nav下。分为ui文件夹和NavActivity主题。工程结构如下图所示。
2.1.1 ui文件夹
里面分别有3个小文件夹,对应三个不同界面的Fragment和ViewModel。Fragment对应的UI展示,ViewModel负责数据,熟悉Jetpack的小伙伴一定不会对ViewModel感到陌生,因为数据的改变刷新的观察者基本上就全靠它了。这里不多赘述,因为。。。emmm。。。其实我的JetPack学的也半斤八两,可能后续会写一篇文章整理下作为一个小白的学习过程,但那当然是以后啦,哈哈。
随便捞一个文件夹讲吧,就Home界面吧。
HomeFragment
直接看代码的3处标注
class HomeFragment : Fragment() {
@1
private lateinit var homeViewModel: HomeViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
@2
homeViewModel =
ViewModelProvider(this).get(HomeViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_home, container, false)
val textView: TextView = root.findViewById(R.id.text_home)
@3
homeViewModel.text.observe(viewLifecycleOwner, Observer {
textView.text = it
})
return root
}
}
- @1处Kotlin的
lateinit
需要注意下,这个是Kotlin特有的语法,证明这个变量初始化由玩家自己把控,所以就特别容易忽视,一定要记住自己初始化。毕竟为了应付Kotlin的?!
,大家也是煞费苦心,但是这玩意真的慎用啊老哥们,放荡不羁爱自由是要付出代价的。 - @2处的ViewModel初始化了一个ViewModel
- @3处的添加了一个数据监听跟页面绑定,一旦model的text改变就会通知到观察者,textview就可以刷新了。有趣的是,Observer同时绑定了Lifecycle,可以让观察者跟View层的生命周期一致,这样就避免了手写的Observer防泄露代码。(想想当年写MVP架构时候,真的是为了RXJava的Observer和架构的Presenter层的解绑,煞费苦心啊!!!)
HomeViewModel
class HomeViewModel : ViewModel() {
@1
private val _text = MutableLiveData<String>().apply {
@3
value = "This is home Fragment"
}
@2
val text: LiveData<String> = _text
}
同样是简简单单,新建了Home界面的HomeViewModel
继承ViewModel
。
- @2处的LiveData就是一个数据实体类(androidx.lifecycle-livedata),可以暂存数据。重要的是他可以关键生命周期并且是一个观察者,所以他可以用于V层和数据的单向一对多通知,并且与生命周期绑定。简单说就是一个观察者模式数据实体类,以前一个数据改变了,以前你需要通过广播,EventBus等方式把改变发出去,页面接收改变的数据并刷新,现在只需要一个
LiveData
就可以搞定了。同时与生命周期的绑定,可以天然的避免了很多内存泄漏和空指针。 - @1处的
MutableLiveData
继承LiveData
,但是他必须实体类或者数据类型变化后才通知.不会细节到某个字段。LiveData则是某个字段更新就通知。 - @3处才是精髓!!! 不要被kotlin的语法迷惑了,这个
value
其实是setValue()=XX
。当玩家通过setValue方法更新数据,LiveData会通知所有的observer数据更新了。 - 再给大家说个Kotlin语法一个大家默契的操作,一般不想对外呈现的变量除了用
private
处理,还会在前面加一个下划线。(不要问我为啥知道,你去用用data class就知道其中的苦了)
NavActivity.java
class NavActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_nav)
val navView: BottomNavigationView = findViewById(R.id.nav_view)
@1
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
@2
val appBarConfiguration = AppBarConfiguration(setOf(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications))
@3
setupActionBarWithNavController(navController, appBarConfiguration)
@4
navView.setupWithNavController(navController)
}
}
- @1处
findNavController
是为了连接你们你Act布局里面的fragment容器,id就是你布局里面的<fragment>
的id。 - @2处主要是为了配置
Toolbar, CollapsingToolbarLayout,ActionBar
详细解释参照Android开发者注意这个id,分别对应顶部title和底部botom的,俩者的ID要保持一致,否则就会出现一些惊喜。(我已经试过我下图红圈里面的俩个ID改为不同的名字,发现不是顶部title就是底部view显示的文字不对,大家尽管尝试) - @3处的
setupActionBarWithNavController
就是把已经配置好的appbar和navcontroll链接到ActionBar。 - @4处是NavView链接navcontroll并且使能。
ADD:我这里应该是最新版的AS生成的代码,老版本的我记得会有Listener中swich
控制三个监听,大家有兴趣可以回头看看。
2.2 res文件夹
这里要看仔细了,不仅生成了一个menu文件夹,还有一个navigation文件夹。
2.2.1 bottom_nav_menu.xml
这里不贴代码了,直接看图吧。主要作用就是主页底部的三个item的资源文件的引用。标准的menu中的item。
- icon属性的图片我们是可以替换的。但是一定要换成透明背景的图片,因为Navigation底部item的选择会直接控制图标背景色的改变,直接改变选中图标背景色的方法略墨迹我就不提了。当然这里也有简单办法,你可以自己新建一个drawble.xml,选中状态的图标颜色跟大小你想怎么更改就怎么更改。
- title:没什么说的,其中引用的文字就是item对应的文字。
2.2.1 mobile_navigation.xml
哈这个就有意思了。大家打开View或者design面变可以看到有趣的画面
这里分别有三个<fragment>
标签通过layout属性链接3个fragment。
注意app:startDestinatinotallow="@+id/navigation_home"
这句代码,它是代表本次加载N个Fragment的其实页面。
你认为这玩意就这个?错了,用处还有很多,放到下一篇,这里就是简单介绍。这里基本介绍就完了,我会在整理下一遍,记录一下Navgation好用的地方跟一些骚操作。
我爱骚操作,我是骚操作小能手,啊哈~。