文档介绍:http://8.136.122.222/book/primary/kotlin/kotlin-intro.html
文档补充说明:https://blog.csdn.net/qq_42059717/category_12047508.html
一、搭建环境及工具安装
见文档
二、工具界面及项目文件介绍
├── app //工程主模块名称
│ ├── build.gradle //app模块的配置文件(签名信息,依赖包,版本号,包名....)
│ ├── libs //放置第三方依赖的jar包,aar,so文件...
│ ├── proguard-rules.pro //打包的混淆规则配置
│ └── src //源码文件夹
│ ├── main //主工程源码文件夹
│ │ ├── AndroidManifest.xml //清单文件(权限声明,四大组件注册...)
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── firstapp
│ │ │ ├── MainActivity.kt //页面的名称
│ │ │ └── ui
│ │ │ ├── dashboard
│ │ │ │ ├── DashboardFragment.kt
│ │ │ │ └── DashboardViewModel.kt
│ │ │ ├── home
│ │ │ │ ├── HomeFragment.kt
│ │ │ │ └── HomeViewModel.kt
│ │ │ └── notifications
│ │ │ ├── NotificationsFragment.kt
│ │ │ └── NotificationsViewModel.kt
│ │ └── res //res全称resource,下面是各类资源文件
│ │ ├── drawable//矢量图片存放文件夹
│ │ │ ├── ic_dashboard_black_24dp.xml
│ │ │ ├── ic_home_black_24dp.xml
│ │ │ ├── ic_launcher_background.xml
│ │ │ └── ic_notifications_black_24dp.xml
│ │ ├── layout //页面布局文件存放文件夹
│ │ │ ├── activity_main.xml
│ │ │ ├── fragment_dashboard.xml
│ │ │ ├── fragment_home.xml
│ │ │ └── fragment_notifications.xml
│ │ ├── menu //菜单资源文件夹(导航栏,侧边栏)
│ │ │ └── bottom_nav_menu.xml
│ │ ├── mipmap-xhdpi// 常规图片资源文件夹(.png,.jpg)
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── navigation //navigation框架导航框架资源存放文件夹
│ │ │ └── mobile_navigation.xml
│ │ ├── values //颜色、尺寸,字符串,主题
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── themes.xml
│ │ └── values-night// 夜间模式的主题
│ │ └── themes.xml
│ └── test //java 测试
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── firstapp
│ │ └── ExampleUnitTest.kt
│ ├── androidTest //android测试
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── firstapp
│ │ └── ExampleInstrumentedTest.kt
├── build.gradle //整个工程的配置文件(maven仓库,android-gradle-plugin插件...)
├── gradle
│ └── wrapper //这个是gradle文件夹
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties // 虚拟机配置文件
├── gradlew //下面两个是一些打包脚本配置文件(./gradle assembleDebug)
├── gradlew.bat
├── local.properties // 本地配置文件(如读取一些配置常量)
└── settings.gradle // 模块管理配置文件(app,libray,libray2. 如果要参与编译则都需要在这里配置才会生效)
android:只会显示安卓相关的文件
project:显示工程项目开发的所有文件
app:在安卓中叫“模块”文件夹
build.gradle:声明在编译过程中所需的插件、仓库的配置
libs:存放开发过程中会用到的“架包、so文件等等”
src:源码存放目录
build.gradle:声明app编译版本、构建工具的版本、包名、版本号、编译文件所需的依赖
main:主要存放源码的文件夹
res:存放各种资源文件,如:图片资源drawable、布局资源layout、菜单资源menu、导航资源navigation、颜色尺寸主题等资源values
AndroidManifest.xml:清单文件
MainActivity.kt:第一个页面文件,声明权限、声明activity等等
三、开发语言——Kotlin
psvm 或者 main:可以快速打出 main 方法
println():输出
Kotlin 是依赖于Java 虚拟机运行的语言,应用程序能够跨平台运行
(一)基本数据类型
类型后面+
?
代表可以为 null
1、整数类型
包括:Byte、Short、Int、Long、Float、Double
2、字符型
用 Char
声明字符类型,赋值时用 单引号 引起来,只能是单个字符。
3、布尔类型
使用 Boolean
表示布尔类型,它只有两个值 true
和 false
。
注意可空类型 Boolean?
类型会存在装箱操作。
4、字符串型
用 String
类型表示。
字符串是不可变的。
字符串的元素——字符可以使用索引运算符访问: s[i]
。 可以用 for 循环迭代字符串
(1)字符串模板
模板表达式 $
开头,由一个简单的名字构成: $number
;或者 ${}
括起来的任意表达式:${text.length}
(2)字符串的值
\
转义字符
val s = "Hello, world!\n" // \n换行
val s2= "{\"key\":\"value\"}" // \反斜杠对""进行转义,保留字符串格式
字符串使用三个引号 """
分界符括起来,内部没有转义并且可以包含换行以及任何其他字符:
val text = """
for (c in "foo")
print(c)
"""
(二)类型强制转换
(三)数字运算
1、四则运算
整数 / 整数 = 整数
,小数点会被抹掉(可以将结果转浮点数得到正确值)
整数 / 小数 = 小数
2、位运算
左移、右移、与 and、或 or、非 inv、异或 xor
(四)数据容器
1、数组
(1)arrayOf
创建数组
必须指定数组元素,元素类型可以是任意类型
val array: Array<Int> = arrayOf(1, 2, 3)
val array: Array<Any> = arrayOf(1, true, "2", JSONObject()) // 集合中的元素可以是任意类型
(2)arrayOfNulls
创建空数组
创建指定长度的空数组,元素类型必须指定
val arrayOfNulls = arrayOfNulls<String>(5) //创建一个指定大小的、所有元素都为空的数组
(五)Kotlin 方法
1、
2、方法参数
(1)默认参数
(2)具名参数
(3)可变数量的参数:vararg
3、Lambda 表达式
四、Android UI 控件
dp:安卓中的一个度量单位,能根据屏幕的分辨率和密度来自适应
- Android UI
- View 视图
- TextView:文本
- ImageView:图片
- Botton:普通按钮
- MaterialButton:主题按钮
- 1、在 build.gradle.kts 中注入依赖
- 2、在 theme.xml 中 修改 app 的 theme 主题
- Tab:选项卡
- ViewGroup 容器
内部可以承载、放置、添加View视图- LinearLayout 线性布局
横着或竖着按顺序排列
- RelativeLayout 相对布局
起始坐标为屏幕左上角,以同级或上级为参考系定位位置
- FrameLayout 帧布局
像千层饼一样,一层压着一层
- ConstraintLayout约束布局
google于2016年新发布的一种布局方式,它不在android的基础api包里,需要额外引入
- LinearLayout 线性布局
- RecyclerView 高级控件
性能出色、插拔式的架构、使用频率极高- RecyclerView.layoutManager:负责布局
- RecyclerView.adapter:负责适配列表数据(绑定数据)
- RecyclerView.ViewHolder:负责列表子项的复用(处理内容数据)
- View 视图
(一)RecyclerView 高级控件
1、RecyclerView.layoutManager :第一步:绑定布局样式
-
LinerLayoutManager:列表布局
-
GridLayoutManager:网格布局
-
StaggeredLayoutManager:瀑布布局
// 第一个参数context:
// 第二个参数控制方向:VERTICAL 纵向、HORIZONTAL 横向
// 第三个参数指是否反转:false 正序、true 倒序
recyclerView.layoutManager =LinearLayoutManager(context, VERTICAL, false)
recyclerView.layoutManager = GridLayoutManager(context, 2)
recyclerView.layoutManager =StaggeredGridLayoutManager(2, VERTICAL)
2、RecyclerView.Adapter :第二步:绑定数据
// 绑定的数据在第三步处理
// MyAdapter自定义类名,即第三步的类名
recyclerView.adapter = MyAdapter()
3、RecyclerView.ViewHolder :第三步:处理列表子项内容数据
// inner 指内部
// class MyAdapter 继承自 RecyclerView.Adapter
// RecyclerView.Adapter<ViewHolder> 泛型的类型必须为 RecyclerView.ViewHolder 的一个子类(即最下面定义的 ViewHolder 类)
inner class MyAdapter : RecyclerView.Adapter<ViewHolder>() {
// 一、【必有内容】创建ItemView的ViewHolder,用于后续的数据绑定
/* onCreateViewHolder 即 创建一个ViewHolder 对象
ViewGroup 指 RecyclerView
viewType 指 列表上item布局的类型,实现列表复杂item布局时使用
*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// 第一步:LayoutInflater 加载布局资源文件,实例化成一个 view 对象
val view =LayoutInflater.from(context).inflate(R.layout.item_view_staggered, parent, false)
// 第二步:创建ViewHolder对象,将上面得到的view对象传递进去
// ViewHolder 即 下面创建的 ViewHolder类
return ViewHolder(view)
}
// 二、【必有内容】告诉RecyclerView列表上item的条数
override fun getItemCount(): Int {
return 20 // 20 即 展示20条
}
// 三、【必须内容】item 的数据绑定
/*
holder 指 上面创建的 ViewHolder 对象
position 指 当前绑定的数据是列表上的第几个位置
*/
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// 绑定数据:
// 通过 holder 对象来拿到布局文件(ViewHolder对应的布局资源文件)里所编写的一个个实例对象
holder.itemView.item_head.setImageResource(R.drawable.icon_jetpack)
holder.itemView.item_name.text = "【${position}】移动端架构师体系课"
holder.itemView.item_message.text ="移动开发“两极分化”,没有差不多的“中间层,唯有尽早成长为架构师,你的职业道路才能走的更远更稳"
}
}
// 四、创建一个 ViewHolder 即,上面一中的 ViewHolder
// 必须继承自 RecyclerView.ViewHolder。
// 用于后续的数据绑定及列表上下滑动时view复用的功能
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {}
(二)其他控件
1、Toast 消息提示
说明:短小消息提示,会在一段时间后自动消失,不占用任何屏幕空间
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.first_layout)
button1.setOnClickListener {
// this报错的话可能是 this.context
Toast.makeText(this, "提示信息",Toast.LENGTH_SHORT).show()
}
}
2、Menu 菜单项
说明:点击菜单按钮时,会弹出里面具体的内容,不占用任何Activity的空间
3、EditText 输入框
说明:允许用户在控件里输入和编辑内容,并可以在程序中对这些内容进行处理。
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="占位提示文字"
/>
4、ImageView 图片
说明:用于在界面上展示图片的一个控件
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/img_1"
/>
5、ProgressBar 进度条
说明:表示我们的程序正在加载一些数据
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
五、Android 组件
(一)Activity
1、定义:
Activity用于显示用户界面,用户通过Activity交互完成相关操作。一个应用中可以包含0个或多个 Activity,但不包含任何 Activity 的应用程序是无法被用户看见的。
ps:一个界面就是一个Activity,可以翻译为“活动”
2、Activity = 一个kotlin类 + 一个xml
(二)Fragment
1、是什么?
(1)背景:最初是为了适应大屏幕的平板电脑。
(2)现状:使用Fragment可以把页面结构划分成对应的几块,每块使用一个Fragment来管理。可以更加方便的在运行过程中动态地更新Activity中的用户界面,日后迭代更新、维护也是更加方便。
(3)注意事项: Fragment并不能单独使用,需要嵌套在Activity 中使用,自己的生命周期受Activity的生命周期影响。
2、Fragment 与 Activity 的关系?
Fragment并不能单独使用,他需要嵌套在Activity 中使用,尽管他拥有自己的生命周期,但是还是会受到宿主Activity的生命周期的影响,比如Activity 被destory销毁了,他也会跟着销毁!一个Activity可以嵌套多个Fragment。
3、Fragment 生命周期
(1)Activity 加载 Fragment 时:
onAttach
->
onCreate
->
onCreateView
->
onActivityCreated
->
onStart
->
onResume
(2)启动一个新的页面时:
原页面的 Fragment 所在的 Activity 不可见,会执行 onPause
(3)当新页面返回后:
原页面的 Activity 和 Fragment 又可见了,会再次执行 onStart
和
onResume
(4)退出 Activity 时:
Fragment 将会被完全结束, Fragment 会进入销毁状态:
onPause
->
onStop
->
onDestoryView
->
onDestory
->
onDetach
4、如何使用?
(1)动态添加Fragment
// 第一步:在 StudyFragment 文件中:定义 StudyFragment 类
// StudyFragment 类 需要继承自 Fragment,并且绑定对应的布局文件,即括号里的路径
class StudyFragment : Fragment(R.layout.fragment_study) {}
// 第二步:在 Activity 文件中:使用 supportFragmentManager 管理 Fragment ,添加到界面上
class MainActivity:AppCompactActivity{
override fun onCreate(savedInstanceState: Bundle?) {
/* 添加步骤1:
在合适的时机构建 Fragment 对象,即 StudyFragment()
ps:合适的时机比如这里的onCreate时,或者点击时等等
*/
val studyFragment = StudyFragment();
/* 添加步骤2:
使用Activity里的supportFragmentManager对象,调用其 beginTransaction 方法中的 add 方法后,
执行 commitAllowingStateLoss()
ps:
1、R.id.container:MainActivity中的布局文件中的 FrameLayout 布局容器的 id
2、studyFragment:上面构建的 Fragment 对象
3、add 即:将 studyFragment 添加到 R.id.container 这个布局容器中去
4、commitAllowingStateLoss()即:执行本次操作事务
*/
supportFragmentManager.beginTransaction()
.add(R.id.container, studyFragment).commitAllowingStateLoss()
}
}
(2)Fragment常见的操作
// 第一步:构建 fragment 对象
val fragment = StudyFragment()
// 第二步:通过 supportFragmentManager.beginTransaction() 方法,得到 FragmentTransaction 对象
val ft = supportFragmentManager.beginTransaction()
// 第三步:把 fragment 添加到事务中
// 因为 add方法 只能调用一次,所以只有 该fragment未被添加过 时,才能把 fragment添加到事务中
if(!fragment.isAdded()){
ft.add(R.id.container,fragment)
}
//显示出fragment的视图
ft.show(fragment)
//隐藏fragment,使得它的视图不可见
ft.hide(fragment)
//移除fragment
ft.remove(fragment)
// 替换fragment,之前添加过的fragment都会被暂时移除,把当前这个fragment添加到事务中
ft.replace(R.id.container,fragment)
// 第四步:提交事务,使对应操作生效
// 提交事务,执行对 fragment 的 add、replace、show、hide操作
ft.commitAllowingStateLoss()
(3)给 Fragment 对象 传递数据
第一种情况:在创建 fragment 实例时,通过 argments 参数 传递数据
-
传参
class MainActivity:AppcompactActivity{
override fun onCreate(savedInstanceState: Bundle?){
/* 创建 fragment 对象 */
val studyFragment = StudyFragment();
/* 传递数据的方法 */
// 第一步:创建bundle对象
val bundle = Bundle()
// 第二步:填充数据 (数据名,数据)
bundle.putInt("key_int",100)
bundle.putString("key_string","key_string_value")
// 第三步:赋值给 fragment 的 argments 字段
studyFragment.argments= Bundle
/* 添加到事务中并提交 */
supportFragmentManager.beginTransaction().add(R.id.container,studyFragment).commitAllowingStateLoss()
}
}
2.取值
class StudyFragment : Fragment(R.layout.fragment_study) {
// 取出参数
// 在 Fragment 的 onViewCreated 方法里
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// 通过 argments 参数的 getInt 方法查找 数据名 取出
val intArgument = argments?.getInt("key_int")
val stringArgument = argments?.getInt("key_string")
}
}
第二种情况:运行时,Fragment如何获取Activity中的数据、又如何将数据传递到Activity中呢?
(三)Service
1、是什么?
Service是四大组件之一,同样需要在AndroidManifest中注册后,才能使用。
Service启动后默认是运行在主线程中,在执行具体耗时任务过程中要手动开启子线程,应用程序进程被杀死,所有依赖该进程的Service服务也会停止运行。
六、Android 网络编程
(一)OkHttp
1、简介:
一个高效的HTTP客户端,同时具备HTTP与WebSocket功能
ps:安卓版本高于8.0后就不能发起明文请求了,只能https安全协议请求
2、OKHTTP实例创建
3、GET请求
(1)同步
(2)异步
4、POST请求
(1)同步
(2)异步
(3)提交表单
(4)提交字符串
(5)提交键值对
5、GSON数据解析
(1)说明:Gson是Google开源的一个JSON库,被广泛应用在Android开发中
(2)使用步骤:
第一步:在app/build.gradle
中添加以下依赖配置
dependencies {
implementation 'com.google.code.gson:gson:2.8.6'
}
6、全局拦截器
(二)Retrofit
1、RESTFUL网络请求框架发展背景、优缺点介绍
Retrofit
是一个高质量高效率的HTTP请求库,和OkHttp
同样出自Square公司。Retrofit 内部依赖于 OkHttp ,它将 OKHttp 底层的代码和细节都封装了起来,功能上做了更多的扩展,比如:返回结果的自动解析、网络引擎的切换、拦截器......
优点:简化网络请求的代码量
2、注解类型
-
用于标注网络请求方式的注解
-
标记网络请求参数的注解
-
用于标记网络请求和响应格式的注解
3、Retrofit实例创建
4、配置网络请求引擎OKHTTP食品器
5、配置数据解析适配器
6、配置网络请求拦截器
7、Get和Post请求的基本使用
七、项目创建步骤
(一)
1、第一次创建项目会编译同步一定时间,右下角会有项目同步进度显示
2、引用指定的自定义模块方法
方法一:代码引入
//引用自定义工具类模块
implementation(project(mapOf("path" to ":super-common")))//super-common即:指定的模块名
方法二:可视化引入
第一步:
第二步:
3、添加分组注释
4、通用控制器整体规划和实现
http://www.ixuea.com/sections/8474
5、实现动态获取权限功能
http://www.ixuea.com/sections/84745
6、升级项目相关配置:讲; fragment和adapyer
查找依赖目前有那些版本的网址:https://mvnrepository.com/
注意:拿到的项目不要升级,可能导致项目不能运行,升级后需要运行验证一下是否有问题
7、Android屏幕适配原理和实例
http://www.ixuea.com/sections/7738
保存数据的方式:
1、SP(首选项:保存配置信息):自动登录、保存密码等,特点:当程序运行时,首选项中的数据会全部加载进内容,所以SP中不能存太多信息,否则会导致应用卡顿
Sp = getSharedPreferences("name", Context.MODE_PRIVATE)
2、SQLite(原生数据库:保存列表信息):
关系型数据库,特点:嵌入式数据库、体积小、功能强大
sqlite.c 执行程序动态创建数据库
工具:SQLite可视化工具
3、Room(简洁数据库:保存列表信息):封装的SQLite
SQLite数据库的抽象,流程易用的数据库
(二)实战流程
参考视频:2023年Android仿今日头条Kotlin版本企业级项目实战/okhttp/java/kotlin/gradle/零基础
1、启动页面
1.实现启动界面布局和功能_哔哩哔哩_bilibili
视频最后几分钟讲解了一下 android studio 里git使用方法
2、
八、问题汇总
(一)问题1:
解决办法:点击“导入类Log”
(二)引入依赖时报错:Too many characters in a character literal ''com.google.code.gson:gson:2.8.6
1、问题原因:
翻译:字符文字“com.google.code.gson:gson:2.8.6”中的字符太多
原因分析:把多个文字放在了 ' ' (单引号)里,应该放到 " " (双引号)里
2、解决办法:
(三)引入 retrofit 相关依赖时报错:Could not resolve all dependencies for configuration ':app:debugRuntimeClasspath'. Could not determine artifacts for com.tencent.bugly:crashreport:3.4.4: Skipped due to earlier error
1、问题原因:
翻译:无法解析配置“:app:debugRuntimeClasspath”的所有依赖项。无法确定com.tencent的项目。错误:crashreport:3.4.4:由于早期错误而跳过
原因分析:这个警告意味着您的项目中存在旧版的Support库,但您的项目已经设置为使用AndroidX。这可能会导致运行时问题,并且在未来的Gradle插件版本中,这种行为将不再被允许。
2、解决办法:
打开 gradle.properties 文件,添加 android.enableJetifier=true
,再次运行
3、参考链接:
https://blog.csdn.net/weixin_46274756/article/details/130669729