【Android基础】第一个Android应用学习记录

本文介绍了第一个android应用的学习记录
xmlns
xmlns 是主节点的namespace命名空间的意思,告诉内部语句可以使用哪些合法的属性参数.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="跳转"/>
</LinearLayout>
- wrap_content:包裹内容,方框的长宽随内容多少而变化。
- id不是必需的,在Java源码中需要find的则需要设置id
- xml文件就是在主节点里写子空间,叶子节点
ImageView的填充方式
设置ImageView填充方式的前提是使用src作为设置图片的来源,否则的话,会导致图片填充方式设置无效的情况。
- scaleType-“matrix”是保持原图大小、从左上角的点开始,以矩阵形式绘图。
- scaleType-“fitXY”是将原图进行横方向(即XY方向)的拉伸后绘制的。
- scaleType-“fitstart”是将原图沿左上角的点(即matrix方式绘图开始的点),按比例缩放原图绘制而成的。
- scaleType-“fitcenter”是将原图沿上方居中的点(即matrix方式绘图第一行的居中的点),按比例缩放原图绘制而成的。
- scaleType=“fitEnd”是将原图沿下方居中的点(即matrix方式绘图最后一行的居中的点),按比例缩放原图绘制而成的。
- scaleType=“Center”是保持原图大小,以原图的几何中心点和ImagView的几何中心点为基准只绘制ImagView大小的图像。
- scaleType=“centerCrop”不保持原图大小,以原图的几何中心点和lmagView的几何中心点为基准,只绘制ImagView大小的图像(以填满lmagView为目标,对原图进行裁剪)
- scaleType=“centerlnside”不保持原图大小,以原图的几何中心点和lmagView的几何中心点为基准,只绘制ImagView大小的图像(以显示完整图片为目标,对原图进行缩放)
完整的页面创建过程包括三个步骤
- 在layout目录下创建XML文件
- 创建与XML文件对应的Java代码
- 在AndroidManifest.xml 中注册页面配置
<activity
android:name=".NewActivity"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.ComposeDemo">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
每次手动创建一个新的activity都要在清单文件中注册一下
或者,可以在new里面一键生成activity,清单文件也注册好了
设置文本
- 在 XML 文件中通过属性 android:text 设置文本
- 在 Java 代码中调用文本视图对象的 setText 方法设置文本
设置文本大小
(1)在Java代码中调节字体大小
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv_hello = findViewById(R.id.tv hello);
tv_hello.setTextSize(40);
}
(2)在xml文件里直接设置textsize
android:text="40sp"
字体大小单位
- 使用sp作为字体大小单位,会随着系统的字体大小改变
- 而dp作为单位则不会随之改变
通常情况下,我们还是建议使用sp作为字体的单位,除非一些特殊的情况,不想跟随系统字体变化的,可以使用dp.
字体颜色设置
同样有两种设置方式
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
TextView tv_hello = findViewById(R.id.tv_hello);
tv_hello.setTextColor(Color.BLUE);
//第一种是在Java代码中获取对象再进行设置
}
<TextView
android:id="@+id/tv_hello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello"
android:textSize="40sp"
android:textColor="@color/purple_200"/>
3秒自动跳转界面的代码
package com.example.zhanfeng_android;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.widget.TextView;
public class Helloworld extends AppCompatActivity {
@Override
protected void onResume(){
super.onResume();
goNextPage();
}
private void goNextPage(){
TextView tv_hello = findViewById(R.id.tv_hello);
tv_hello.setText("3秒后自动跳转下一界面");
new Handler(Looper.myLooper()).postDelayed(mGoNext, 3000);
}
private Runnable mGoNext = new Runnable(){
@Override
public void run(){
startActivity(new Intent(Helloworld.this, NewPage.class));
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
}
所有看得到的控件都可以叫做视图,视图尺寸的设置
视图宽度通过属性android:layout_width表达,视图高度通过属性android:layout_height表达,宽高的取值主要有下列三种:
- match_parent:表示与上级视图保持一致。
- wrap_content:表示与内容自适应,
- 以dp为单位的具体尺寸。
自适应的内容不可超出上级视图,否则会出异常
要在Java代码中设置宽高,需要先将xml中属性设为wrap_content
视图间距
- margin为当前的视图和它的平级视图之间的距离
- padding为当前视图和其下级视图的间距
- padding为控件本身的边框和里面的内容的距离
如果不设置方向就是四周的边框均设置距离
举例:
LinearLayout最好用的就是可以设置内部控件所占的比重。 在子控件里设置 android:layout_weight 可以设置控件占容器的比例
LinearLayout(线性布局)
以水平或垂直方向排列子视图。 通过android:orientation属性设置排列方向。 子视图可以通过android:layout_weight属性设置权重,以实现按比例分配空间。
RelativeLayout(相对布局)
允许子视图相对于其他子视图或父视图进行定位。 通过android:layout_alignParentTop、android:layout_toLeftOf等属性设置相对位置。
FrameLayout(帧布局)
所有子视图都堆叠在左上角,后添加的子视图会覆盖前面的子视图。 通常用于实现叠加效果,如地图上的标记。
TableLayout(表格布局)
以表格形式排列子视图,类似于HTML中的<table>标签。 通过android:stretchColumns属性设置可拉伸的列。
GridLayout(网格布局)
将子视图放置在网格中,可以指定行列数。 通过android:layout_row和android:layout_column属性设置子视图的位置。
ConstraintLayout(约束布局)
以相对位置和约束条件来排列子视图。 每个子视图至少需要两个方向的约束,可以通过app:layout_constraintStart_toEndOf等属性设置约束。
tools命名空间
android的text和tools的text区分。tools是调试时的工具,而android才是运行时实际显示的。
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="real"
tools:text="test_text" />
对齐方式
单独一个gravity是设置下属视图
而layout_gravity是设置自己在父布局中的对齐方式
实例演示,对比代码和界面来看。
布局页面的嵌套
<include layout="@layout/fragment_app_detail"/>
xml文件本质
xml布局文件中的一个个view节点,最终也是会被解析成java代码类采用xml方式进行布局,只不过是为了方便我们开发者进行直观的布局。
其实也可以直接用Java代码来写和修改布局。
git插入技巧
查看最近提交的版本号:git reflog 回退到历史版本:git reset –hard ad2080c
应用权限声明
都要在manifest文件中进行标注
Java和xml布局文件是怎样关联的
检查Manifest文件,找到的启动页面MainActivity。
MainActivity调用onCreate方法–>调用setContentView方法–>R.layout.activity_main找到布局文件。
Gradle文件分析
新手在工程方面碰到的错误很多和gradle文件有关 Gradle是什么,有什么作用? 编译,打包安卓工程的一个工具 Project中的Module
项目级里的Gradle插件版本和Gradle版本的匹配关系要对应
插件版本7.2,那么Gradle版本需要7.3.3以上

而模组级的Gradle文件主要关注其依赖项
android {
namespace = "com.stephen.redfindemo"
compileSdk = 34
defaultConfig {
applicationId = "com.stephen.redfindemo"
minSdk = 30
targetSdk = 34
versionCode = 32
versionName = "2.1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
}
其中各个参数的意义:compileSdkVersion,minSdkVersion,targetSdkVersion,build ToolsVersion
- compileSdkVersion 是编译代码所使用的sdk 版本,并且与sdk manager 里面下载的那些sdk platforms是对应的。也就是说,compileSdk Version使用的版本,在sdk manager 里面必须是已经下载了才能用。最新的as做了优化,即使你没有下,当写上某个版本后,as会自动帮你下载。
- minSdkVersion 是对app可运行的手机设备的最小版本限制。与sdk manager里面下载的东西无关,只是一个标识而已。
- targetSdkVersion 是对app要运行的手机设备的目标版本的标识,也与sdk manager 里面下载的东西无关,标识了该app是为某个版本的手机设备而设计的,在这个目标版本的手机上做了充分的测试。
当你的手机版本大于这个目标版本时,该app也能运行。因为高版本的手机是可以运行低版本软件的。这也符合常理,越先进的手机功能应该越强大嘛,不仅能运行新东西,也能兼容老东西。
因此,minSdkVersion 和targetSdkVersion是对我们开发的app所能运行设备的系统版本的范围约束。最低不能小于minSdkVersion,但没有最高限制。原因上面已经说了,高版本手机可以运行低版本软件嘛。从名字上也可以理解,它叫targetSdkVersion 而没有叫maxSdk Version
build ToolsVersion 是独立出来的一个东西,和上面三个都没关系,就是构建代码的工具的版本。 与sdk manager 里面的sdk tools 下载的东西是对应的。要想使用某个版本,必须得已经下载了对应的sdk Build-tools。
重要关系:minSdkVersion <= targetSdkVersion <= compileSdkVersion
RecyclerView使用流程
首先,在页面里添加recyclerview控件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
第二步,写item的xml控件,以通讯录为例,需要添加一个装头像的ImageView,一个姓名TextView,一个电话号码TextView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/imageView"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/head"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"
android:textSize="30sp"/>
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="20sp"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
第三步定义一个Person类,添加姓名,电话的String,还有头像的ID,自动生成构造器和getter,setter 第四步写MyAdapter类,继承自RecyclerView.Adapter,覆写以下三个方法
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
}
@Override
public int getItemCount() {
return 0;
}
然后再在里面写MyViewHolder类,继承自RecyclerView.ViewHolde,这个类用于装来自item里的控件。
class MyViewHolder extends RecyclerView.ViewHolder{
TextView nametext;
TextView phoneText;
ImageView head;
public MyViewHolder(View itemView) { //传View对象即可
super(itemView); //调用super方法
this.nametext = itemView.findViewById(R.id.textView);
this.phoneText = itemView.findViewById(R.id.textView2);
this.head = itemView.findViewById(R.id.imageView);
}
}
fragment的使用
fragment是将屏幕中的控件集中统一管理,所以本身可以直接作为页面来使用。
使用示例:
第一,建立新的空白fragment
第二,fragment的页面解析方式和activity有点不同,需要用到inflate,在xml里写完界面之后,传到view类
第三,fragment里对于文本和按钮处理方式和activity相同。
第四,在activity的xml文件里添加fragment控件,id必须添加。
以按钮进行多界面切换,fragment管理器的使用
private void replaceFragment(Fragment fragment){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.fragment_container, fragment);
transaction.commit();
}
最后一定要commit才能生效.
activity和fragment的通信
使用bundle类来传递,键值对的形式存储信息。 在fragment的java代码里,使用getarguments()来接收信息,获得的是bundle对象实例。从中解析数据。
动态添加fragment的小结
- 创建一个待处理的fragment
- 获取FragmentManager,一般都是通过getSupportFragmentManager()
- 开启一个事务 transaction,一般调用fragmentManager的beginTransaction()
- 使用transaction进行fragment的替换
- 提交事务
Android的数据存储
SharedPreferences
SharedPreferences是Android平台上一个轻量级的存储类,用来保存应用的一些常用配置,比如Activity状态,Activity暂停时,将此activity的状态保存到SharedPereferences中;当Activity重载,系统回调方法onSaveInstanceState时,再从SharedPreferences中将值取出。SharedPreferences提供了java常规的Long、Int、String等类型数据的保存接口。SharedPreferences类似过去Windows系统上的ini配置文件,但是它分为多种权限,可以全局共享访问。提示最终是以xml方式来保存,整体效率来看不是特别的高,对于常规的轻量级而言比SQLite要好不少,如果真的存储量不大可以考虑自己定义文件格式。该xml在应用程序私有目录下,其他程序无法访问。
使用Handler处理多线程之间的信息传递
了解了Message、Handler、MessageQueue以及Looper的基本概念后,我们再来把异步消息处理的整个流程梳理一遍。首先需要在主线程当中创建一个Handler对象,并重写handleMessage( )方法。然后当子线程中需要进行UI操作时,就创建一个Message对象,并通过Handler将这条消息发送出去。之后这条消息会被添加到MessageQueue的队列中等待被处理,而Looper则会一直尝试从MessageQueue中取出待处理消息,最后分发回Handler的handleMessage ( )方法中。由于Handler是在主线程中创建的,所以此时 handleMessage( )方法中的代码也会在主线程中运行,于是我们在这里就可以安心地进行UI操作了。整个异步消息处理机制的流程示意图如下图所示。
JSON数据解析
- JSONObject 表示一个JSON节点
- JSONObject.opt(“key”)根据键获取值,如果没找到匹配的键,则返回空。(推荐)
- JSONObject.get(“key”)根据键获取值,如果没找到匹配的键,则抛出异常。
根据值的类型获取:
- JSONObject.optString(“key”)
- JSONObject.optInt(“key”)
- JSONObject.optBoolean(“key”)
- JSONObject.optJsONObject(“key”)
- JSONObject.optJSONArray(“key”)