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

【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

而模组级的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”)