安卓基础学习

29 分钟

前言

最近在有在持续学习Java的安卓开发,不断的把知识记录下。


工具

  1. Android Studio安装
    Studio安装

file

  1. SDK下载
    SDK即软件开发工具包,可将App源码编译成可执行的App应用

file

创建项目

  1. 创建项目
    file

file

这里Minimum SDK后面指的是兼容到安卓几,表示你的应用支持的最低版本,看百分比选,一般目前的都是9.0-10.0。
  1. 内置模拟器
    file

    初始化Gradle要下载半小时,内置模拟器也有十多G,默认在C盘很不爽,可以移动,

file

注册环境变量,然后修改下面的配置,直接把目录移动到想存的位置即可。
file
  1. 观察App运行日志
    Android采用Log日志打印日志,各类日志划分:

    Log.e 表示错误信息,可能导致程序崩溃
    Log.w:表示警告信息
    Log.i:表示一般消息
    Log.d:表示调试信息,可把程序运行变量值打印,方便跟踪调试
    Log.v:表示冗余信息
  2. 真机调试

    1、使用数据库连接到电脑
    2、电脑上会自动安装USB存储设备驱动
    3、打开手机的开发者选项并开启USB调试
    4、将连接的手机设备文件传输模式,并允许计算机进行USB调试
  3. 关于安卓开发语言
    App开发分为两大技术路线,分别为原生开发和混合开发,官方的编程语言包括Java和Kotlin。
    混合开发渲染性能没有原生开发好,但是混合开发可以跨平台,版本更新不需要重新下载API文件。
    关于C和C++,Java是解释型语言,在处理图像和音视频时性能显然就有瓶颈,而C和C++是编译型语言,会
    先翻译成机器语言,在图像和音视频处理时可以调用java的JNI接口调用C和C++程序进行处理,也称NDK。
  4. 目录结构
    file

mainfests:App运行配置文件
java子目录:存放java源代码,后面两个包存放测试用的代码

res目录下:
drawable:存放图形描述和图片文件
Layout:App页面的布局文件
mipmap:App的启动图标
values:存放常量的文件,如样式风格等

Gradle Scripts目录下:
build.gradle:描述项目级和模块级的App工程编译规则
proguard-rules.pro:java代码的混淆规则,保证安全性
gradle.properties:用于编译工程的命令行参数
local.properties:本地配置文件,描述开发者电脑的环境配置
settings.gradle:配置了需要编译的模块

  1. build.gradle的文件概述解释
plugins {
    //使用的插件
    id 'com.android.application'
}

android {
    namespace 'com.example.myapplication'
    compileSdk 33 //编译使用的SDK版本号,33表示使用Android13

    defaultConfig {
        // App的包名
        applicationId "com.example.myapplication"
        //指定App适合运行的最小的SDK版本号,28表示最小在Android9上运行
        minSdk 28
        //目标设备的版本号,表示App最希望在那个版本的Android上运行
        targetSdk 33
        //App的应用版本号
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    //跟单元测试相关
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}
//指定App编译的依赖包信息
dependencies {
    //指定编译的Android高版本支持库
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    //指定单元测试编译用的junit版本号
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
  1. 清单文件

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools">
    
     <application
         android:allowBackup="true"
         android:dataExtractionRules="@xml/data_extraction_rules"
         android:fullBackupContent="@xml/backup_rules"
         android:icon="@mipmap/ic_launcher"
         android:label="@string/app_name"
         android:supportsRtl="true"
         android:theme="@style/Theme.MyApplication"
         tools:targetApi="31">
         <activity
             android:name=".MainActivity"
             android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
    
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
     </application>
    
    </manifest>

android:icon:App手机屏幕显示的图标
android:label:App手机屏幕显示的名称
android:allowBackup:是否允许数据备份,数据丢失时恢复应用
android:theme:指定App显示的风格
android:supportsRtl:是否支持波斯语等从右向左的文字排列顺序语言

activity应用程序组件,提供屏幕,用来交互完成某项任务
android:exported:当前Activity是否可以被另一个Application的组件启动
android:name:启动应用首先启动那个Applicaiton

简单控件即UI

一、界面显示与逻辑处理

  1. 创建新的activity页面
<?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:orientation="vertical"
    android:gravity="center">

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/text2" />



</LinearLayout>
  1. 创建新的MainActivity类,并将类加入Mainifest
package com.example.myapplication;

import android.os.Bundle;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity2 extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

    }
}

<activity android:name=".MainActivity2"/>

  1. 设置跳转按钮
<?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:orientation="vertical"
    android:gravity="center">

    <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>
  1. 写跳转方法
package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv=findViewById(R.id.tv);
        tv.setText("你好,世界!");

        Button button=findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=new Intent();
                intent.setClass(MainActivity.this,MainActivity2.class);
                startActivity(intent);
            }
        });
    }
}

file

二、文本

  1. 文本大小

    px :图像元素,跟随屏幕大小和像素数量关系变化。
    resolution:屏幕垂直和水平方向的像素数量。
    dpi:像素密度,指屏幕上每英寸距离中有多少个像素点。
    Density:指定每平方英寸含有的像素点数量。
    dip/dp:长度单位,同一个单位在不同设备中有不同显示效果。
    sp:专门用于设置字体,大小会根据系统的字体大小改变而改变。
    dip是开发中的长度单位,最后也要转换为px,px=dip*dpi/160
例:如 320*480分辨率 3.6寸的手机:
dpi=(320^2+480^2)^(1/2)/3.6=160 所以 1dp=1px
对于相同尺寸的手机,即使分辨率不同,占用屏幕比例也相同
  1. 设置文本颜色
设置文本的颜色一般可直接设置,也可以通过十六进制设置,如0xFFFFEEDD, 其中先
后十六进制顺序为透明度,红色,绿色,蓝色。
<?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:orientation="vertical"
    android:gravity="center">

    <TextView
        android:id="@+id/text_color"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="直接设置文本颜色" />
    <TextView
        android:id="@+id/text_hex_color"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:textColor="@color/purple_200"
        android:text="十六进制设置文本颜色"/>
    <TextView
        android:id="@+id/text_code_color"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="代码中设置文本颜色"/>
    <TextView
        android:id="@+id/text_background"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="设置文本背景颜色"
        android:background="#ff00ff00"/>


</LinearLayout>
public class MainTextActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_text);
        TextView text_color=findViewById(R.id.text_color);
        text_color.setTextColor(Color.GREEN);
        TextView text_code_color=findViewById(R.id.text_code_color);
        text_code_color.setTextColor(0xff00ff00);
    }
}
  1. 视图

wrap_content:自适应大小,刚好能包含内容
match_parent:当前控件的大小和父布局的大小一样
dp:自行设置dp大小

在代码中设置视图宽高。
调用控件对象getLayoutParams方法获取控件的布局参数。
调用控件对象的setLayoutParams方法,填入修改后布局参数使之生效。

public class ViewBorderActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_view_border);
        TextView text_borer=findViewById(R.id.text_view_border);
        ViewGroup.LayoutParams params=text_borer.getLayoutParams();
        params.width= Utils.dip2px(this,300);
        text_borer.setLayoutParams(params);
    }
}

public class Utils {
    //根据分辨率dp转化为像素px
    public static int dip2px(Context context, float dpValue){
        //获取当前像素密度,1个dp对应多少个像素
        float scale=context.getResources().getDisplayMetrics().density;
        return (int)(dpValue*scale+0.5f);

    }
}

三、布局

  1. 线性布局LinearLayout
orientation为horizontal,内部视图水平方向排列
oritentation为vertical,内部视图竖着排列
  1. 相对布局RelativeLayout
相对布局的下级视图位置由其他视图决定,确定位置参照物分两种:
(1)与该视图自身评级的视图
(2)该视图的上级视图
不设定,默认在左上角
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:background="#ffffff"
        android:text="我在中间"
        android:textColor="#000000"
        android:textSize="10sp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:background="#ffffff"
        android:text="我在上级左边中间"
        android:textColor="#000000"
        android:textSize="10sp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:layout_alignParentBottom="true"
        android:text="我在上级底部对齐"
        android:textSize="10sp"
        android:textColor="#000000"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@id/center"
        android:layout_alignTop="@id/center"
        android:background="#ffffff"
        android:text="我在中间左边"
        android:textColor="#000000"
        android:textSize="10sp" />
</RelativeLayout>
  1. 网格布局GridLayout,支持多行多列的表格排列
网格布局默认从左往右,从上到下,属性如下
columnCount,指定网格列数,即每行能放多少视图
rowCount,指定网格行数,每列能放多少个视图
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:columnCount="2"
    android:rowCount="2">
    <TextView
        android:layout_width="0dp"
        android:layout_columnWeight="1"
        android:layout_height="60dp"
        android:text="红色"
        android:background="#ff0000"
        android:textSize="20sp"
        android:gravity="center"
        android:textColor="#000000"/>
    <TextView
        android:layout_width="0dp"
        android:layout_columnWeight="1"
        android:layout_height="60dp"
        android:text="橙色"
        android:background="#ffaa00"
        android:textSize="20sp"
        android:gravity="center"
        android:textColor="#000000"/>
    <TextView
        android:layout_width="0dp"
        android:layout_columnWeight="1"
        android:layout_height="60dp"
        android:text="绿色"
        android:background="#00ff00"
        android:textSize="20sp"
        android:gravity="center"
        android:textColor="#000000"/>

    <TextView
        android:layout_width="0dp"
        android:layout_columnWeight="1"
        android:layout_height="60dp"
        android:text="紫色"
        android:background="#660066"
        android:textSize="20sp"
        android:gravity="center"
        android:textColor="#000000"/>

</GridLayout>
  1. 滚动视图ScrollView
ScrollView,垂直方向滚动,垂直方向滚动时,layout_width属性值设置为math_parent,layout_height属性设置为wrap_content
HorizontalScrollView,水平方向滚动,layout_width属性值设置为wrap_content,layout_height属性设置为match_parent
<?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:orientation="vertical">
    <HorizontalScrollView
        android:layout_width="wrap_content"
        android:layout_height="200dp">
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal">
            <View
                android:layout_width="300dp"
                android:layout_height="match_parent"
                android:background="#00ff00">

            </View>
            <View
                android:layout_width="300dp"
                android:layout_height="match_parent"
                android:background="#00aaff">

            </View>

        </LinearLayout>



    </HorizontalScrollView>
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <View
                android:layout_width="match_parent"
                android:layout_height="400dp"
                android:background="#ff0000">

            </View>
            <View
                android:layout_width="match_parent"
                android:layout_height="400dp"
                android:background="#aa00ff">

            </View>

        </LinearLayout>


    </ScrollView>



</LinearLayout>

四、按钮

Button由TextView派生,区别在于:
Button拥有默认按钮背景(紫色),而TextView无背景。
Button的内部文本默认居中对齐。
Button会默认将英文字母转为大写,testAllCaps可以设置是否转换。

ImageButton显示图片的图像按钮,继承自ImageView
ImageButton只能显示图片,不能显示文本
ImageButton的图像可按比例缩放,Button背景设置的图像会拉伸变形
Button只能靠背景显示一张图片,ImageButton可在前景和背景显示图片,从而实现两张图片叠加效果

例子:设置三个按钮,分别启动和禁用第三个按钮,禁用按钮需要长按才能禁用,第三个按钮点击则显示时间。

<?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:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/button_begin_click"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="启用按钮"
            android:textSize="17sp"/>

        <Button
            android:id="@+id/button_disable_click"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="禁用按钮"
            android:textSize="17sp" />
    </LinearLayout>
    <Button
        android:id="@+id/button_test_click"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="测试禁用的按钮"
        android:textSize="17sp"
        android:enabled="false"/>
    <TextView
        android:id="@+id/button_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="查看测试禁用按钮的结果"
        android:textSize="17sp"
        android:textColor="#000000"/>

</LinearLayout>
package com.example.myapplication.utils;


import java.text.SimpleDateFormat;
import java.util.Date;

public class DateTime {
    public static String getNowTime(){
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("HH:mm:ss");
        return  simpleDateFormat.format(new Date());
    }
}
package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.example.myapplication.utils.DateTime;

public class ButtonTextActivity extends AppCompatActivity {

    private Button button_test_click;
    private TextView button_view;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_button_text);
        Button button_begin_click=findViewById(R.id.button_begin_click);
        Button button_disable_click= findViewById(R.id.button_disable_click);
        button_test_click = findViewById(R.id.button_test_click);
        button_view = findViewById(R.id.button_text_view);
        button_begin_click.setOnClickListener(new MyOnclickListener());
        button_test_click.setOnClickListener(new MyOnclickListener());
        button_disable_click.setOnLongClickListener(new MyOnclickLongListener());

    }
   class MyOnclickListener implements View.OnClickListener{
        @Override
        public void onClick(View view) {
            switch (view.getId()){
                case R.id.button_begin_click:
                    button_test_click.setEnabled(true);
                    break;
                case R.id.button_test_click:
                    String time=String.format("当前时间:%s", DateTime.getNowTime());
                    button_view.setText(time);
            }
        }
    }
    class MyOnclickLongListener implements View.OnLongClickListener{

        @Override
        public boolean onLongClick(View view) {
            button_test_click.setEnabled(false);
            return true;
        }
    }

}

file

五、控件综合训练(简易计算器)

  1. Strings.xml
<resources>
    <string name="app_name">My Application</string>
    <string name="text2">Activity Main</string>
    <string name="simple_calculator">简易计算器</string>
    <string name="cancel">CE</string>
    <string name="divide">÷</string>
    <string name="clear">C</string>
    <string name="multiply">+</string>
    <string name="ride">*</string>
    <string name="minus">-</string>
    <string name="nine">9</string>
    <string name="eight">8</string>
    <string name="seven">7</string>
    <string name="six">6</string>
    <string name="five">5</string>
    <string name="four">4</string>
    <string name="three">3</string>
    <string name="two">2</string>
    <string name="one">1</string>
    <string name="zero">0</string>
    <string name="reciprocal">1/X</string>
    <string name="doc">.</string>
    <string name="equal">=</string>
    <string name="root">√</string>
</resources>
  1. dimens.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="button_font_size">30sp</dimen>
    <dimen name="button_height">90dp</dimen>
    
    
</resources>
  1. layout.xml
<?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:background="#EEEEEE"
    android:orientation="vertical"
    android:padding="5dp">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/simple_calculator"
                android:textColor="@color/black"
                android:gravity="center"
                android:textSize="30sp"/>
            <TextView
                android:id="@+id/tv_result"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/white"
                android:text="0"
                android:textColor="@color/black"
                android:lines="8"
                android:textSize="25sp"
                android:gravity="right|bottom"/>
            <GridLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:columnCount="4"
                android:rowCount="5">
                <Button
                    android:id="@+id/btn_cancel"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/cancel"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_divide"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/divide"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_ride"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/ride"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_clear"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/clear"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_seven"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/seven"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_eight"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/eight"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_nine"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/nine"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_multi"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/multiply"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_four"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/four"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_five"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/five"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_six"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/six"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_minus"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/minus"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_one"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/one"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_two"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/two"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_three"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/three"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_root"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/root"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_reciprocal"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/reciprocal"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_zero"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/zero"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_doc"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/doc"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>
                <Button
                    android:id="@+id/btn_equal"
                    android:layout_width="0dp"
                    android:layout_height="@dimen/button_height"
                    android:layout_columnWeight="1"
                    android:text="@string/equal"
                    android:textColor="@color/black"
                    android:textSize="@dimen/button_font_size"/>

            </GridLayout>

        </LinearLayout>


    </ScrollView>
</LinearLayout>
  1. 主类
package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class CalculatorActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView tv_result;
    //第一个操作数
    private String firstNum="";
    //操作符号
    private String operator="";
    //第二个操作数
    private String secodeNum="";
    //计算结果
    private String result="";
    //显示的文本
    private String showText="";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_calculator);
        tv_result = findViewById(R.id.tv_result);
        findViewById(R.id.btn_cancel).setOnClickListener(this);
        findViewById(R.id.btn_divide).setOnClickListener(this);
        findViewById(R.id.btn_ride).setOnClickListener(this);
        findViewById(R.id.btn_clear).setOnClickListener(this);
        findViewById(R.id.btn_seven).setOnClickListener(this);
        findViewById(R.id.btn_eight).setOnClickListener(this);
        findViewById(R.id.btn_nine).setOnClickListener(this);
        findViewById(R.id.btn_multi).setOnClickListener(this);
        findViewById(R.id.btn_four).setOnClickListener(this);
        findViewById(R.id.btn_five).setOnClickListener(this);
        findViewById(R.id.btn_six).setOnClickListener(this);
        findViewById(R.id.btn_minus).setOnClickListener(this);
        findViewById(R.id.btn_one).setOnClickListener(this);
        findViewById(R.id.btn_two).setOnClickListener(this);
        findViewById(R.id.btn_three).setOnClickListener(this);
        findViewById(R.id.btn_root).setOnClickListener(this);
        findViewById(R.id.btn_reciprocal).setOnClickListener(this);
        findViewById(R.id.btn_zero).setOnClickListener(this);
        findViewById(R.id.btn_doc).setOnClickListener(this);
        findViewById(R.id.btn_equal).setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        String inputText;

        inputText=((TextView) view).getText().toString();
        switch (view.getId()){
            case R.id.btn_cancel:
                if(operator.equals("")) {
                    showText = showText.substring(0, showText.length() - 1);
                    refreshOperate(showText);
                    refreshText(showText);
                    break;
                }
                if(secodeNum.equals("")&&!operator.equals("")){
                    showText = showText.substring(0, showText.length() - 1);
                    CE();
                    refreshText(showText);
                    break;
                }
                else{
                    showText = showText.substring(0, showText.length() - 1);
                    refreshOperate(showText);
                    refreshText(result);
                    break;
                }
            case R.id.btn_clear:
                clear();
                break;
            case R.id.btn_multi:
            case R.id.btn_divide:
            case R.id.btn_ride:
            case R.id.btn_minus:
                operator=inputText;
                refreshText(showText+operator);
                break;
            case R.id.btn_equal:
                double calculate_result=calculateFour();
                refreshOperate(String.valueOf(calculate_result));
                refreshText(showText+"="+result);
                break;
                //开根号
            case R.id.btn_root:
                double sqrt_result=Math.sqrt(Double.parseDouble(firstNum));
                refreshOperate(String.valueOf(sqrt_result));
                refreshText(showText+"√="+result);
                break;
                //求导数
            case R.id.btn_reciprocal:
                double reciprocal_result=1.0/Double.parseDouble(firstNum);
                refreshOperate(String.valueOf(reciprocal_result));
                refreshText(showText+"/="+result);
                break;
            default:
                if (result.length()>0&&operator.equals("")){
                    clear();
                }
                if(operator.equals("")){
                    firstNum=firstNum+inputText;
                }
                else{
                    secodeNum=secodeNum+inputText;
                }
                if(showText.equals("0")&&!inputText.equals(".")){
                    refreshText(inputText);
                }
                else {
                    refreshText(showText + inputText);
                }
                break;
        }

    }
    private  void cancel(){
    }
    private void clear(){
        refreshOperate("");
        refreshText("");
    }
    private double calculateFour(){
        switch (operator){
            case "+":
                return Double.parseDouble(firstNum)+Double.parseDouble(secodeNum);
            case "-":
                return Double.parseDouble(firstNum)-Double.parseDouble(secodeNum);
            case "*":
                return Double.parseDouble(firstNum)*Double.parseDouble(secodeNum);
            default:
                return Double.parseDouble(firstNum)/Double.parseDouble(secodeNum);
        }
    }
    private void CE(){ //7+
        operator="";
    }
    private void refreshOperate(String new_result){
        result=new_result;
        firstNum=result;
        secodeNum="";
        operator="";
    }
    private void refreshText(String text){
        showText=text;
        tv_result.setText(showText);
    }
}
并非是什么完美计算器,仅是复习以上知识操作使用。

file

六、Activity

从当前页面跳转到新页面:
startActivity(new intent(源页面.this,目标页面.class))
当前页面返回上一个页面:
finish();

activity的生命周期:
onCreate 创建活动,把页面加载进内存,进入初始状态
onStart 开始活动,把活动页面显示到屏幕,就绪态
onResume 恢复活动,活动页面进入活跃状态
onPause 暂停活动,页面不能正常交互
onStop 停止活动,页面不在屏幕
onDestroy 销毁活动,回收系统资源,从内存清除
onRestart 重启活动,重新加载内存的页面数据
onNewIntent 重用已有的实例

file

Activity启动模式(栈)
默认启动模式standard,启动的Activity依照顺序被依次压入Task栈。
栈顶复用模式singleTop,栈顶Activity为我们新建的Activity,不会重新创建新的Activity。
栈内复用模式singleTask,栈内存在目标Activity实例,则将task内对应Activity实例之上的Activity出栈,并
将对应Activity置于栈顶。
全局唯一模式singleInstance,为目标Activity创建新的Task栈,新的Task栈只有这一个Activity,如
已经创建目标Activity,则不创建新的Task,将以前的Activity唤醒。
启动模式的设置:intent.setFlags()代码中启动,Mainfest.xml中动态设置launch。

file

例子:登录页面进行登录成功后,即使后退,也不能返回登录页面,而是直接退出程序。

package com.example.activity;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class LoginInputActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login_input);
        Button btn_login=findViewById(R.id.btn_login);
        btn_login.setOnClickListener(new MyOnclickListen());

    }
    class MyOnclickListen implements View.OnClickListener{
        @Override
        public void onClick(View view) {
            Intent intent=new Intent(LoginInputActivity.this,LoginSuccessActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);

        }
    }
}
通过设置启动模式来完成,一旦登录则会清空当前活动栈中的所有实例,然后再同时启动开辟新任务的活动栈,这样登录后,再点击返回则会直接退出程序。
  1. Intent

    Intent各个组件之间信息沟通桥梁,用于组件之间通信,主要完成工作是本次通信请求从哪来,到哪去,要怎么走
    发起方携带本次通信需要的数据,接收方从收到的意图中解析数据。
    发起方若判断接收方处理结果,意图就要负责让接收方回应答数据。
显示Intent,直接指定来源活动与目标活动,精确匹配,三种方式
直接Intent函数中指定:new Intent()
调用意图对象:setClass()
调用意图对象setComponent()
隐式Intent,没有明确指定要跳转的目标活动,只给出一个动作字符串匹配,属于模糊匹配
通过setAction,url,setData()指定动作和数据
常见的隐式动作有:

file

例子1:使用隐式Intent直接进行拨号,发送短信,或跳转到其它APP

package com.example.activity;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class IntentActivity extends AppCompatActivity implements View.OnClickListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_intent);
        Button btn_dail=findViewById(R.id.btn_dail);
        Button btn_cms=findViewById(R.id.btn_cms);
        Button btn_my=findViewById(R.id.btn_mypage);
        btn_dail.setOnClickListener(this);
        btn_cms.setOnClickListener(this);
        btn_my.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        String phone="123456";
        Intent intent=new Intent();
        switch (view.getId()){
            case R.id.btn_dail:
                intent.setAction(Intent.ACTION_DIAL);
                Uri uri=Uri.parse("tel:"+phone);
                intent.setData(uri);
                startActivity(intent);
                break;

            case R.id.btn_cms:
                intent.setAction(Intent.ACTION_SENDTO);
                Uri uri2=Uri.parse("smsto:"+phone);
                intent.setData(uri2);
                startActivity(intent);
                break;
            case R.id.btn_mypage:
                intent.setAction("android.intent.action.Aiwin");
                intent.addCategory(Intent.CATEGORY_DEFAULT);
                startActivity(intent);
                break;
        }
    }
}

<intent-filter>
                <action android:name="android.intent.action.Aiwin" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
最后跳转自己的APP,需要在mainfestxml中添加intent-filter

例子2:A页面发送信息给B页面,B页面再返回回应信息给A页面,需要通过registerForActivityResult()

package com.example.activity;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class ActRequestActivity extends AppCompatActivity implements View.OnClickListener{

    private ActivityResultLauncher<Intent> register;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_act_request);
        Button btn_send=findViewById(R.id.btn_request);
        TextView btn_receive=findViewById(R.id.btn_receive);
        btn_send.setOnClickListener(this);
        register = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
            @Override
            public void onActivityResult(ActivityResult result) {
                    if(result!=null){
                        Intent intent=result.getData();
                        if(intent!=null&result.getResultCode()== Activity.RESULT_OK){
                            Bundle bundle=intent.getExtras();
                            String message=bundle.getString("response");
                            btn_receive.setText(message);
                        }
                    }
            }
        });
    }

    @Override
    public void onClick(View view) {
        Intent intent=new Intent(this,ActResponseActivity.class);
        Bundle bundle=new Bundle();
        bundle.putString("message","你睡了吗?");
        intent.putExtras(bundle);
        register.launch(intent);

    }
}
package com.example.activity;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class ActResponseActivity extends AppCompatActivity implements View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_act_response);
        TextView request=findViewById(R.id.btn_request);
        Button btn_response=findViewById(R.id.btn_response);
        Bundle bundle=getIntent().getExtras();
        String request_content=bundle.getString("message");
        request.setText(request_content);
        btn_response.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        Intent intent=new Intent();
        Bundle bundle=new Bundle();
        bundle.putString("response","我没睡,我爸妈不在家");
        intent.putExtras(bundle);
        setResult(ActRequestActivity.RESULT_OK,intent);
        finish();
    }
}
  1. 应用页面注册快捷方式

在安卓7以后,可以长按页面图标,弹出一些快捷方式,比如长按微信会弹出扫一扫,付款码等
点击即可直接跳转到该页面。

例子:在xml目录创建shortcuts.xml,先修改Mainfest.xml文件

<activity
            android:name=".ActStartActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data
                android:name="android.app.shortcuts"
                android:resource="@xml/shortcuts" />
        </activity>

配置shortcuts.xml文件


<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
    <shortcut
        android:enabled="true"
        android:icon="@mipmap/ic_launcher"
        android:shortcutId="first"
        android:shortcutLongLabel="@string/shortcutLongLabel_first"
        android:shortcutShortLabel="@string/shortcutShortLabel_first">
        <!-- targetClass指定了点击该项菜单后要打开哪个活动页面 -->
        <intent
            android:action="android.intent.action.VIEW"
            android:targetClass="com.example.activity.ActStartActivity"
            android:targetPackage="com.example.activity" />
        <categories
            android:name="android.shortcut.conversation" />
    </shortcut>


    <shortcut
        android:enabled="true"
        android:icon="@mipmap/ic_launcher"
        android:shortcutId="second"
        android:shortcutLongLabel="@string/shortcutLongLabel_second"
        android:shortcutShortLabel="@string/shortcutShortLabel_second">
        <!-- targetClass指定了点击该项菜单后要打开哪个活动页面 -->
        <intent
            android:action="android.intent.action.VIEW"
            android:targetClass="com.example.activity.ActStartActivity"
            android:targetPackage="com.example.activity" />
        <categories
            android:name="android.shortcut.conversation" />
    </shortcut>

</shortcuts>

效果:
file

七. 中级控件

  1. Shape图
形状图形 Shape,形状图形的定义文件是以shape标签为根节点的XML描述文件,一般有四种类型的形状:
rectangle 矩形,默认值
oval 椭圆,corners节点失效
line 直线,必须设置stroke节点
ring 圆环
其中XML中能设置的有:size尺寸,stroker描边,corners圆角,solid填充,padding间隔,gradient渐变

如设置一个椭圆形:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="oval">
    <solid android:color="#ff66aa"/>
    <stroke android:width="1dp" android:color="#aaaaaa"/>

</shape>
  1. 九宫格图片

在Android Stdio中,可以直接把PNG图片转成九宫格图片,利用九宫格图片,能够使图片被拉伸但是不变形,
能够用于适应不同的手机屏幕。

  1. 状态列表图形
简单来说,就是按钮被按下和没被按下显示不同的颜色或者形状等,以便于用户区分按了哪一个按钮,可通过StateListDrawable完成。状态的取值常用的有pressed、checked、focused、selected
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@android:drawable/button_onoff_indicator_on"/>
    <item android:drawable="@android:drawable/button_onoff_indicator_off"/>

</selector>
<?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:orientation="vertical"
    android:gravity="center">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="默认样式按钮"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:background="@drawable/drawable_nine_selector"
        android:padding="5dp"
        android:text="定制样式按钮"/>


</LinearLayout>

在这里插入图片描述

  1. checkbox

    <?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:orientation="vertical"
     android:padding="5dp">
    
     <CheckBox
         android:id="@+id/ck_system"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:padding="5dp"
         android:text="系统的CheckBox" />
    
     <CheckBox
         android:id="@+id/ck_custom"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginTop="10dp"
         android:button="@drawable/checkbox_selector"
         android:padding="5dp"
         android:text="CheckBox换图标"/>
    
    </LinearLayout>
package com.example.middlecontrolactivity;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.CheckBox;
import android.widget.CompoundButton;

public class CheckBoxAcivity extends AppCompatActivity implements CompoundButton.OnCheckedChangeListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_check_box_acivity);
        CheckBox ck_system=findViewById(R.id.ck_system);
        CheckBox ck_custom=findViewById(R.id.ck_custom);
        ck_system.setOnCheckedChangeListener(this);
        ck_custom.setOnCheckedChangeListener(this);

    }

    @Override
    public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
            String desc=String.format("您%s了这个CheckBox",b ? "勾选":"没勾选");
            compoundButton.setText(desc);
    }
}
  1. Switch

    与checkbox使用是一致的,都是从Compuound类继承而来
    textOn:设置右侧开启时文本
    textOff:设置左侧关闭时文本
    track:设置开关轨道的背景
    thumb:设置开关标识图标
  2. RadioButton

    一般单选按钮只允许选择一个,需要放在RadioGroup里面,对RadioGroup进行监听
<?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:orientation="vertical">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="请选择你的性别"
        android:textColor="@color/black"
        android:textSize="17sp"/>
    <RadioGroup
        android:id="@+id/rg_rb"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/rb_male"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="男"/>
        <RadioButton
            android:id="@+id/rb_female"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="女"/>
    </RadioGroup>
    <TextView
        android:id="@+id/tv_result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="17sp"
        android:textColor="@color/black"/>


</LinearLayout>
package com.example.middlecontrolactivity;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.CompoundButton;
import android.widget.RadioGroup;
import android.widget.TextView;

public class RadioButtonActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener {

    private TextView tv_result;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_radio_button);
        RadioGroup rg_rb=findViewById(R.id.rg_rb);
        tv_result=findViewById(R.id.tv_result);
        rg_rb.setOnCheckedChangeListener(this);
    }

    @Override
    public void onCheckedChanged(RadioGroup radioGroup, int i) {
        switch (i){
            case R.id.rb_male:
                tv_result.setText("你选择的是男性");
                break;
            case R.id.rb_female:
                tv_result.setText("你选择的女性");
                break;
        }
    }
}
  1. EditText、焦点变更事件、文本变化监听器

焦点变更事件可以对鼠标的焦点变更进行监听,比如登录要输入手机号+密码,可以对密码进行焦点监听,当输入密码时,检测手机号是否为11位,若不为,则不能输入密码。
文本变化监听器则可通过对EditText进行监听做出相应的动作,比如当手机号输够十一位后自动关闭键盘。

hint:指定提示文本的内容
maxLength:指定文件允许输入的最大长度
inputType:指定输入的文本类型

输入类型说明
text文本
testPassword文本密码
number整型数
numberSigned带符号的数字
numberDecimal带小数点的数字
numberPassword数字密码
datetime时间日期格式,数字,横线,斜杆,空格,冒号
date日期格式,数字,横线,斜杠
time时间格式

例子:简单的登录判断程序

<?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:padding="5dp"
    android:orientation="vertical">

    <EditText
        android:id="@+id/phone"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入11位手机号"
        android:maxLength="11"
        android:inputType="phone"
        android:textColorHint="@color/black"
/>
    <EditText
        android:id="@+id/password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入密码"
        android:inputType="textPassword"
        android:textColorHint="@color/black"/>
    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="提交"
        android:textSize="17sp"
        android:layout_gravity="right" />
    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="17sp"/>



</LinearLayout>
package com.example.middlecontrolactivity;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.example.middlecontrolactivity.util.ViewUtil;

public class EditTextActivity extends AppCompatActivity implements View.OnClickListener, View.OnFocusChangeListener {
    private  EditText phone;
    private  EditText password;
    private TextView v;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_edit_text);
        v=findViewById(R.id.text);
        Button button = findViewById(R.id.button);
        phone=findViewById(R.id.phone);
        password=findViewById(R.id.password);
        button.setOnClickListener(this);
        password.setOnFocusChangeListener(this);//焦点变更事件
        phone.addTextChangedListener(new HideTextWatcher(phone,11)); //输够位数则自动关闭键盘(文本监听)
        password.addTextChangedListener(new HideTextWatcher(phone,6));//输够位数则自动关闭键盘


    }


    @Override
    public void onClick(View view) {
        String p=phone.getText().toString();
        String pass=password.getText().toString();
        if(p.equals("123456") && pass.equals("123456")){
            v.setText("登录成功");
        }
        else{
            v.setText("登录失败");
        }
    }

    @Override
    public void onFocusChange(View view, boolean b) {
        if(b){
            String sure_phone=phone.getText().toString();
            if(TextUtils.isEmpty(sure_phone)||sure_phone.length()<11){
                phone.requestFocus();
                Toast.makeText(this,"请输入11位号码",Toast.LENGTH_SHORT).show();
            }
        }
    }
    private class HideTextWatcher implements  TextWatcher{
        private  EditText mView;
        private  int mMaxLength;
        public HideTextWatcher(EditText v, int maxLength) {
            mView=v;
            mMaxLength=maxLength;
        }

        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void afterTextChanged(Editable editable) {
            String str=editable.toString();
            if(str.length()==mMaxLength){
                ViewUtil.hideOneInputMethod(EditTextActivity.this,mView);
            }
        }
    }
}
package com.example.middlecontrolactivity.util;

import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.view.inputmethod.InputMethodManager;

public class ViewUtil {
    public  static  void hideOneInputMethod(Activity act, View v){
        //从系统服务中获取到输入法管理器
        InputMethodManager imm= (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE);
        //通过token关闭屏幕上的输入法键盘
        imm.hideSoftInputFromWindow(v.getWindowToken(),0);
    }
}
  1. 提醒对话框

    就是类似于卸载手机应用时的弹出的框,选择确定或者取消,分别对不同的选择进行不同的监听。
package com.example.middlecontrolactivity;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class AlertDialogActivity extends AppCompatActivity implements View.OnClickListener {
        private  Button button;
        private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_alert_dialog);
        button=findViewById(R.id.alert_btn);
        textView=findViewById(R.id.text);
        button.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        AlertDialog.Builder builder=new AlertDialog.Builder(this);
        builder.setTitle("亲爱的用户");
        builder.setMessage("你真的要卸载吗?");
        builder.setPositiveButton("确定",(dialog,which)->{
            textView.setText("虽然依依不舍,但是终究离开");
        });
        builder.setNegativeButton("再想想",(dialog,which)->{
            textView.setText("我依旧会陪伴");
        });
        AlertDialog alertDialog=builder.create();
        alertDialog.show();
    }
}
  1. 日期、时间对话框
<?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:orientation="vertical"
    android:padding="5dp">

    <Button
        android:id="@+id/btn_date"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="请选择日期"/>
    <DatePicker
        android:id="@+id/dp_date"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:datePickerMode="spinner"
        android:calendarViewShown="false"/>
    <Button
        android:id="@+id/btn_sure"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="确定"/>

    <TextView
        android:id="@+id/date_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="17sp"/>
</LinearLayout>
package com.example.middlecontrolactivity;

import androidx.appcompat.app.AppCompatActivity;

import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.TextView;

import org.w3c.dom.Text;

import java.util.Calendar;

public class DatePickerDialog extends AppCompatActivity implements View.OnClickListener, android.app.DatePickerDialog.OnDateSetListener {
    private Button btn_date;
    private  Button btn_sure;
    private DatePicker dp_date;
    private  TextView date_text;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_date_picker_dialog);
        btn_date=findViewById(R.id.btn_date);
        btn_sure=findViewById(R.id.btn_sure);
        dp_date=findViewById(R.id.dp_date);
        date_text=findViewById(R.id.date_text);
        btn_date.setOnClickListener(this);
        btn_sure.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.btn_sure:
                String desc=String.format("你选择的日期是%s年%s月%s日",dp_date.getYear(),dp_date.getMonth()+1,dp_date.getDayOfMonth());
                date_text.setText(desc);
                break;
            case R.id.btn_date:
                Calendar calendar=Calendar.getInstance();
                int year= calendar.get(Calendar.YEAR);
                int month= calendar.get(Calendar.MONTH);
                int day= calendar.get(Calendar.DAY_OF_MONTH);
                android.app.DatePickerDialog dialog=new android.app.DatePickerDialog(this,this,year,month,day);
                dialog.show();
                break;
        }
    }

    @Override
    public void onDateSet(DatePicker datePicker, int year, int month, int day) {
        String desc=String.format("你选择的日期是%s年%s月%s日",year,month+1,day);
        date_text.setText(desc);
    }
}
日期和时间所用的方式是一致的,只需将DatePicker改为TimePicker即可,同时DatePickerDialog改为TimePickerDialog即可。

八、综合案列(登录与找回密码)

设置两个页面,通过两种方式登录,手机号与验证码登录,并且可以跳转到另外的页面找回密码,通过Intent包裹数据进行不同页面的传输和传回,
并对手机号和密码,验证码框进行监听,达到长度则撤销键盘,达不到长度或不正确弹出提醒对话框。

UI界面涉及:
login.xml:

<?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:orientation="vertical">

    <RadioGroup
        android:id="@+id/rg_login"
        android:layout_width="match_parent"
        android:layout_height="@dimen/item_layout_height"
        android:orientation="horizontal">
    <RadioButton
        android:id="@+id/rb_password"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="@string/login_by_password"
        android:checked="true"/>
        <RadioButton
            android:id="@+id/rb_verifycode"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="@string/login_by_verifycode"/>
    </RadioGroup>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/item_layout_height"
        android:orientation="horizontal">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:text="@string/phone_number"
        android:gravity="center"
        android:textColor="@color/black"
        android:textSize="@dimen/common_font_size"/>
    <EditText
        android:id="@+id/et_phone"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:hint="@string/input_phone_number"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:maxLength="11"
        android:textColor="@color/black"
        android:inputType="phone"
        android:textSize="@dimen/common_font_size"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/item_layout_height"
        android:orientation="horizontal">
        <TextView
            android:id="@+id/tv_password"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="@string/login_password"
            android:gravity="center"
            android:textColor="@color/black"
            android:textSize="@dimen/common_font_size"/>
        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1">
            <EditText
                android:id="@+id/et_password"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:hint="@string/input_password"
                android:layout_marginTop="5dp"
                android:layout_marginBottom="5dp"
                android:maxLength="6"
                android:textColor="@color/black"
                android:inputType="numberPassword"
                android:textSize="@dimen/common_font_size"/>

            <Button
                android:id="@+id/btn_forget"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_alignParentEnd="true"
                android:text="@string/forget_password"
                android:textColor="@color/black"
                android:textSize="@dimen/common_font_size" />
        </RelativeLayout>
        
    </LinearLayout>
    <CheckBox
        android:id="@+id/ck_remember"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/remember_password"
        android:textColor="@color/black"
        android:textSize="@dimen/common_font_size"/>
    <Button
        android:id="@+id/btn_login"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/login"
        android:textSize="20sp"/>
</LinearLayout>

forgetpassword.xml:

<?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:orientation="vertical"
    android:padding="5dp">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/item_layout_height"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="@string/input_new_pasword"
            android:gravity="center"
            android:textColor="@color/black"
            android:textSize="@dimen/common_font_size"/>
        <EditText
            android:id="@+id/et_password"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:hint="@string/input_new_password"
            android:layout_marginTop="5dp"
            android:layout_marginBottom="5dp"
            android:maxLength="11"
            android:textColor="@color/black"
            android:inputType="phone"
            android:textSize="@dimen/common_font_size"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/item_layout_height"
        android:orientation="horizontal">
        <TextView
            android:id="@+id/new_password"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="@string/sure_new_password"
            android:gravity="center"
            android:textColor="@color/black"
            android:textSize="@dimen/common_font_size"/>
        <EditText
                android:id="@+id/sure_new_password"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:hint="@string/input_new_password_again"
                android:layout_marginTop="5dp"
                android:layout_marginBottom="5dp"
                android:maxLength="6"
                android:textColor="@color/black"
                android:inputType="numberPassword"
            android:textSize="@dimen/common_font_size"/>

    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/item_layout_height"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="@string/verifycode"
            android:gravity="center"
            android:textColor="@color/black"
            android:textSize="@dimen/common_font_size"/>
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
        <EditText
            android:id="@+id/et_verifycode"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:hint="@string/input_verifycode"
            android:layout_marginTop="5dp"
            android:layout_marginBottom="5dp"
            android:maxLength="6"
            android:textColor="@color/black"
            android:inputType="numberPassword"
            android:textSize="@dimen/common_font_size"/>
        <Button
            android:id="@+id/get_verifycode"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentEnd="true"
            android:textSize="@dimen/common_font_size"
            android:text="@string/get_verifycode"/>
        </RelativeLayout>
    </LinearLayout>
    <Button
        android:id="@+id/confirm"
        android:layout_width="match_parent"
        android:layout_height="@dimen/item_layout_height"
        android:text="@string/done"
        android:textSize="@dimen/common_font_size"/>
</LinearLayout>

strings.xml:

<resources>
    <string name="app_name">MiddleControlActivity</string>
    <string name="login_by_password">密码登录</string>
    <string name="login_by_verifycode">验证码登录</string>
    <string name="phone_number">手机号码:</string>
    <string name="input_phone_number">请输入手机号码</string>
    <string name="login_password">登录密码:</string>
    <string name="input_password">请输入密码</string>
    <string name="forget_password">忘记密码</string>
    <string name="remember_password">记住密码</string>
    <string name="login">登&#160;&#160;&#160;录</string>
    <string name="input_new_pasword">输入新密码</string>
    <string name="input_new_password">请输入新密码</string>
    <string name="sure_new_password">确认新密码</string>
    <string name="input_new_password_again">请再次输入新密码</string>
    <string name="verifycode">&#160;&#160;&#160;验证码:</string>
    <string name="input_verifycode">请输入验证码</string>
    <string name="get_verifycode">获取验证码</string>
    <string name="done">确&#160;&#160;&#160;定</string>
</resources>

dimens.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="common_font_size">17sp</dimen>
    <dimen name="button_font_size">20sp</dimen>
    <dimen name="item_layout_height">50dp</dimen>
</resources>

file
file
file

登录逻辑:

package com.example.middlecontrolactivity;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;

import com.example.middlecontrolactivity.util.ViewUtil;

import java.util.Random;

public class LoginMainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener, View.OnClickListener {
        private TextView tv_password;
        private EditText et_password;
        private Button btn_forget;
        private CheckBox ck_remember;
        private EditText et_phone;
        private RadioButton rb_password;
        private RadioButton rb_verifycode;
        private  ActivityResultLauncher<Intent> register;
        private  Button btn_login;
        private  String mPassword="123456";
        private  String mVerifyCode;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login_main);
        RadioGroup rb_login=findViewById(R.id.rg_login);
        et_phone = findViewById(R.id.et_phone);
        tv_password=findViewById(R.id.tv_password);
        et_password=findViewById(R.id.et_password);
        btn_forget=findViewById(R.id.btn_forget);
        ck_remember=findViewById(R.id.ck_remember);
        rb_password = findViewById(R.id.rb_password);
        rb_verifycode=findViewById(R.id.rb_verifycode);
        btn_login=findViewById(R.id.btn_login);
        btn_login.setOnClickListener(this);
        et_phone.addTextChangedListener(new HideTextWatcher(et_phone,11));
        et_password.addTextChangedListener(new HideTextWatcher(et_password,6));
        rb_login.setOnCheckedChangeListener(this);
        btn_forget.setOnClickListener(this);
        register = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
            @Override
            public void onActivityResult(ActivityResult result) {
                         Intent intent=result.getData();
                         if(intent!=null&&result.getResultCode()== Activity.RESULT_OK)    {
                             mPassword=intent.getStringExtra("new_password");
                         }

            }
        });


    }

    @SuppressLint("NonConstantResourceId")
    @Override
    public void onCheckedChanged(RadioGroup radioGroup, int checkId) {
        switch (checkId){
            case R.id.rb_password:
                tv_password.setText(R.string.login_password);
                et_password.setHint(R.string.input_password);
                btn_forget.setText(R.string.forget_password);
                ck_remember.setVisibility(View.VISIBLE);
                break;
            case R.id.rb_verifycode:
                tv_password.setText(R.string.verifycode);
                et_password.setHint(R.string.input_verifycode);
                btn_forget.setText(R.string.get_verifycode);
                ck_remember.setVisibility(View.GONE);
                break;
        }
    }


    @SuppressLint({"DefaultLocale", "NonConstantResourceId"})
    @Override
    public void onClick(View view) {
        String phone=et_phone.getText().toString();
        switch (view.getId()){
            case R.id.btn_forget:
                if(phone.length()<11){
                    Toast.makeText(this,"请输入正确的手机号",Toast.LENGTH_SHORT).show();
                    return ;
                }
            if(rb_password.isChecked()){
                //通过Intent包裹数据传递到忘记密码界面
                Intent intent=new Intent(this,ForgetPasswordActivity.class);
                intent.putExtra("phone",phone);
                register.launch(intent);
            }
            else if(rb_verifycode.isChecked()){
                 //弹出对话框,提醒用户记住
                mVerifyCode=String.format("%06d",new Random().nextInt(999999));
                AlertDialog.Builder builder=new AlertDialog.Builder(this);
                builder.setTitle("请记住验证码");
                builder.setMessage("手机号"+phone+",本次验证码是"+mVerifyCode+",请输入验证码");
                builder.setPositiveButton("好的",null);
                AlertDialog dialog=builder.create();
                dialog.show();
            }
            break;
            case R.id.btn_login:
                if(rb_password.isChecked()){
                  if(!mPassword.equals(et_password.getText().toString())){
                     Toast.makeText(this,"请输入正确的密码",Toast.LENGTH_SHORT) .show();
                     return ;
                  }
                  loginSuccess();
                }
                else if(rb_verifycode.isChecked()){
                    if(!mVerifyCode.equals(et_password.getText().toString())){
                        Toast.makeText(this,"请输入正确的验证码",Toast.LENGTH_SHORT);
                        return;
                    }
                    loginSuccess()     ;
                }
                break;

        }
    }



    //EditText监听器,到达位数则自动关闭键盘
    private class HideTextWatcher implements TextWatcher {
        private EditText mView;
        private int mLength;
        public HideTextWatcher(EditText e, int MaxLength) {
            this.mView=e;
            this.mLength=MaxLength      ;
        }

        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void afterTextChanged(Editable editable) {
               if(editable.length()==mLength){
                   ViewUtil.hideOneInputMethod(LoginMainActivity.this,mView);
               }
        }
    }
    private void loginSuccess(){
        String desc=String.format("您的手机号码是%s,恭喜你通过登录验证,点击确定返回",et_phone.getText().toString());
        AlertDialog.Builder builder=new AlertDialog.Builder(this) ;
        builder.setMessage(desc);
        builder.setPositiveButton("确定返回", (dialogInterface, i) -> {
            finish();
        });
        builder.setNegativeButton("我再看看",null);
        Dialog dialog=builder.create();
        dialog.show();


    }
}

找回密码逻辑:

package com.example.middlecontrolactivity;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import java.util.Random;

public class ForgetPasswordActivity extends AppCompatActivity implements View.OnClickListener {
    private String mPhone;
    private String mVerifyCode;
    private EditText et_password;
    private EditText sure_password;
    private  EditText et_verifycode;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_forget_password);
        mPhone=getIntent().getStringExtra("phone");
        et_password=findViewById(R.id.et_password);
        sure_password=findViewById(R.id.sure_new_password);
        findViewById(R.id.get_verifycode).setOnClickListener(this);
        findViewById(R.id.confirm).setOnClickListener(this);
        et_verifycode=findViewById(R.id.et_verifycode);
    }

    @SuppressLint({"NonConstantResourceId", "DefaultLocale"})
    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.get_verifycode:
                mVerifyCode=String.format("%06d",new Random().nextInt(999999));
                AlertDialog.Builder builder=new AlertDialog.Builder(this);
                builder.setTitle("请记住验证码");
                builder.setMessage("手机号"+mPhone+",本次验证码是"+mVerifyCode+",请输入验证码");
                builder.setPositiveButton("好的",null);
                AlertDialog dialog=builder.create();
                dialog.show();
                break;
            case R.id.confirm:
                String password=et_password.getText().toString();
                String password_second=sure_password.getText().toString();
                String verifyCode=et_verifycode.getText().toString();
                if(password.length()<6){
                    Toast.makeText(this,"请输入6位的密码",Toast.LENGTH_SHORT).show();
                    return;
                }
                if(!password.equals(password_second)){
                    Toast.makeText(this,"两次密码不一致",Toast.LENGTH_SHORT).show();
                    return;
                }
                if(!verifyCode.equals(mVerifyCode)){
                    Toast.makeText(this,"验证码不正确",Toast.LENGTH_SHORT).show();
                    return ;
                }
                Toast.makeText(this,"密码修改成功",Toast.LENGTH_SHORT).show();
                Intent intent=new Intent();
                intent.putExtra("new_password",password);
                setResult(Activity.RESULT_OK,intent);
                finish();
                break;
        }
    }
}

# 数据存储

一、SharedPreferences

SharePreferences是Android的轻量级存储工具,采用存储结构是Key-Value的键值对方式,重量级存储的是SQLite数据库
共享参数的存储介质是符合XML规范的配置文件,保存路径是:/data/data/应用包名/shared_prefs/文件名.xml。
使用场景:
简单且孤立的数据,文本形式的数据,需持久化存储的数据(在App退出后再次启动,保存数据依旧有效),实际开发中,经常存储用户的个性化配置信息,行为信息,临时需要保存的片段信息等。

例子:一个页面用于提交个人的姓名,年龄,身高,体重,是否结婚的信息,提交后,关闭程序再次打开信息依旧能够显示。

可以使用sharedPreferences用于存储提交过的信息,存储在xml中,再应用程序再次打开时,通过getSharedPreferences从中获取,并设置edittext的内容即可。
<?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:orientation="vertical"
    android:padding="5dp">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="姓名:"
            android:textSize="17sp"
            android:textColor="@color/black"/>
        <EditText
            android:id="@+id/name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入你的姓名"
            android:textSize="17sp"
            android:textColor="@color/black"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="年龄:"
            android:textSize="17sp"
            android:textColor="@color/black"/>
        <EditText
            android:id="@+id/age"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入你的年龄"
            android:textSize="17sp"
            android:inputType="number"
            android:textColor="@color/black"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="身高:"
            android:textSize="17sp"
            android:textColor="@color/black"/>
        <EditText
            android:id="@+id/height"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入你的身高"
            android:textSize="17sp"
            android:inputType="number"
            android:textColor="@color/black"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="体重:"
            android:textSize="17sp"
            android:textColor="@color/black"/>
        <EditText
            android:id="@+id/weight"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入您的体重"
            android:inputType="number"
            android:textSize="17sp"
            android:textColor="@color/black"/>
    </LinearLayout>
    <CheckBox
        android:id="@+id/married"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:checked="false"
        android:textColor="@color/black"
        android:text="已婚"
        android:textSize="17sp" />
    <Button
        android:id="@+id/save"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="保存到共享参数"
        android:textSize="17sp"
        android:textColor="@color/black"/>
</LinearLayout>
package com.example.datastorage;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

public class ShareWriteActivity extends AppCompatActivity implements  View.OnClickListener {
    private EditText name;
    private EditText age;
    private EditText weight;
    private EditText height;
    private CheckBox married;
    private Button save;
    private  SharedPreferences sharedPreferences;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_share_write);
        name=findViewById(R.id.name);
        age=findViewById(R.id.age);
        weight=findViewById(R.id.weight);
        height=findViewById(R.id.height);
        married=findViewById(R.id.married);
        save=findViewById(R.id.save);
        sharedPreferences = getSharedPreferences("personalInformation",MODE_PRIVATE);
        save.setOnClickListener(this);
        reload();
    }
    public void reload(){
        String re_name=sharedPreferences.getString("name",null);
        String re_age= String.valueOf(sharedPreferences.getInt("age",0));
        String re_weight= String.valueOf(sharedPreferences.getFloat("weight",0f));
        String re_height= String.valueOf(sharedPreferences.getFloat("height",0f));
        boolean re_married=sharedPreferences.getBoolean("married",false);
        name.setText(re_name);
        age.setText(re_age);
        weight.setText(re_weight);
        height.setText(re_height);
        married.setChecked(re_married);
    }
    @Override
    public void onClick(View view) {
        String et_name=name.getText().toString();
        String et_age=age.getText().toString();
        String et_weight=weight.getText().toString();
        String et_height=height.getText().toString();
        boolean et_married=married.isChecked();
        @SuppressLint("CommitPrefEdits") SharedPreferences.Editor editor=sharedPreferences.edit();
        editor.putString("name",et_name);
        editor.putInt("age",Integer.parseInt(et_age));
        editor.putFloat("weight",Float.parseFloat(et_weight));
        editor.putFloat("height",Float.parseFloat(et_height));
        editor.putBoolean("married",et_married);
        editor.apply();
        Toast toast=Toast.makeText(this,"提交成功",Toast.LENGTH_SHORT);
        toast.show();
    }
}

可以看到在提交后,会在/data/data/应用程序名中生成一个xml文件。
file
file

二、SQLite

SQLite与mysql几乎一致,SQLite不支持boolean类型,当输出true和false时会自动转换成0和1.
  1. 数据库的打开和删除
package com.example.datastorage;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class CreateSqliteDatabase extends AppCompatActivity implements View.OnClickListener {
    private Button create;
    private Button delete;
    private TextView textView;
    private String DatabaseName;
    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_create_sqlite_database);
        create=findViewById(R.id.bt_create);
        delete=findViewById(R.id.bt_delete);
        textView=findViewById(R.id.text);
        create.setOnClickListener(this);
        delete.setOnClickListener(this);
        DatabaseName=getFilesDir()+"/test.db";
    }

    @SuppressLint("NonConstantResourceId")
    @Override
    public void onClick(View view) {
        String desc;
        switch (view.getId()){
            case R.id.bt_create:
                SQLiteDatabase db=openOrCreateDatabase(DatabaseName,MODE_PRIVATE,null);
                desc=String.format("数据库%s创建%s",db.getPath(),(db!=null)?"成功":"失败");
                textView.setText(desc);
                break;
            case R.id.bt_delete:
                boolean result=deleteDatabase(DatabaseName);
                desc=String.format("数据库%s删除%s",DatabaseName,result?"成功":"失败");
                textView.setText(desc);
                break;
        }
    }
}
  1. 数据库的增删改查

DatabaseUserHelper.java

package com.example.datastorage.database;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import com.example.datastorage.entity.User;

import java.util.ArrayList;
import java.util.List;

public class DatabaseUserHelper extends SQLiteOpenHelper {
    private static final String DB_NAME="user.db";
    private static final String TABLE_NAME="user_info";

    private static final int DB_VERSION=1;
    private static DatabaseUserHelper databaseUserHelper=null;

    public DatabaseUserHelper(Context context) {
        super(context,DB_NAME,null,DB_VERSION);
    }
    //单例模式获取数据库实例
    public static  DatabaseUserHelper getInstance(Context context){
        if(databaseUserHelper==null){
            databaseUserHelper=new DatabaseUserHelper(context);
        }
        return databaseUserHelper;
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        String sql= "CREATE TABLE IF NOT EXISTS "+TABLE_NAME+"(_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,name VARCHAR NOT NULL,age INTEGER NOT NULL,height LONG NOT NULL,weight float NOT NULL,married INTEGER NOT NULL);";
        sqLiteDatabase.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
    public Long insert(User user){
        SQLiteDatabase db=databaseUserHelper.getWritableDatabase();
        ContentValues values=new ContentValues();
        values.put("name",user.name);
        values.put("age",user.age);
        values.put("weight",user.weight);
        values.put("height",user.height);
        values.put("married",user.married);
        //如果插入的数据是空的,nullColumnHack可以给予一列列名进行插入。
        return db.insert(TABLE_NAME,null,values);
    }
    public long deleteByName(String name){
        SQLiteDatabase db=databaseUserHelper.getWritableDatabase();
        return db.delete(TABLE_NAME, "name=?", new String[]{name});

    }
    public long update(User user) {
        ContentValues values=new ContentValues();
        values.put("name",user.name);
        values.put("age",user.age);
        values.put("weight",user.weight);
        values.put("height",user.height);
        values.put("married",user.married);
        SQLiteDatabase db = databaseUserHelper.getWritableDatabase();
        return db.update(TABLE_NAME,values,"name=?",new String[]{user.name});
    }
    public List<User> queryAll(){
        List<User> list=new ArrayList<>();
        SQLiteDatabase db=databaseUserHelper.getWritableDatabase();
        //返回一个游标
        Cursor cursor=db.query(TABLE_NAME,null,null,null,null,null,null);
        while(cursor.moveToNext()){
            User user=new User();
            user.id=cursor.getInt(0);
            user.name=cursor.getString(1);
            user.age=cursor.getInt(2);
            user.height=cursor.getLong(3);
            user.weight=cursor.getFloat(4);
            user.married= cursor.getInt(5) != 0;
            list.add(user);
        }
        return list;
    }
}

User.java类

package com.example.datastorage.entity;

import androidx.annotation.NonNull;

public class User {
    public int id;
    public String name;
    public int age;
    public long height;
    public float weight;
    public boolean married;
    
    public User(String name, int age, long height, float weight, boolean married) {
        this.name = name;
        this.age = age;
        this.height = height;
        this.weight = weight;
        this.married = married;
    }

    public User(){
    }


    @NonNull
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                ", weight=" + weight +
                ", married=" + married +
                '}';
    }
}

xml类:

<?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:orientation="vertical"
    android:padding="5dp">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="姓名:"
            android:textSize="17sp"
            android:textColor="@color/black"/>
        <EditText
            android:id="@+id/name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入你的姓名"
            android:textSize="17sp"
            android:textColor="@color/black"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="年龄:"
            android:textSize="17sp"
            android:textColor="@color/black"/>
        <EditText
            android:id="@+id/age"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入你的年龄"
            android:textSize="17sp"
            android:inputType="number"
            android:textColor="@color/black"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="身高:"
            android:textSize="17sp"
            android:textColor="@color/black"/>
        <EditText
            android:id="@+id/height"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入你的身高"
            android:textSize="17sp"
            android:inputType="number"
            android:textColor="@color/black"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="体重:"
            android:textSize="17sp"
            android:textColor="@color/black"/>
        <EditText
            android:id="@+id/weight"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入您的体重"
            android:inputType="number"
            android:textSize="17sp"
            android:textColor="@color/black"/>
    </LinearLayout>
    <CheckBox
        android:id="@+id/married"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:checked="false"
        android:textColor="@color/black"
        android:text="已婚"
        android:textSize="17sp" />
    <Button
        android:id="@+id/save"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="添加"
        android:textSize="17sp"
        android:textColor="@color/black"/>
    <Button
        android:id="@+id/delete"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="删除"
        android:textSize="17sp"
        android:textColor="@color/black"/>
    <Button
        android:id="@+id/update"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="修改"
        android:textSize="17sp"
        android:textColor="@color/black"/>
    <Button
        android:id="@+id/query"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="查询"
        android:textSize="17sp"
        android:textColor="@color/black"/>
</LinearLayout>

Activity类:

package com.example.datastorage;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;

import com.example.datastorage.database.DatabaseUserHelper;
import com.example.datastorage.entity.User;
import com.example.datastorage.util.ToastUtil;

import java.util.List;

public class SQLiteHelperActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText name;
    private EditText age;
    private EditText weight;
    private EditText height;
    private CheckBox married;
    private Button save;
    private Button delete;
    private Button update;
    private Button query;
    private DatabaseUserHelper databaseUserHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sqlite_helper);
        name=findViewById(R.id.name);
        age=findViewById(R.id.age);
        weight=findViewById(R.id.weight);
        height=findViewById(R.id.height);
        married=findViewById(R.id.married);
        save=findViewById(R.id.save);
        delete=findViewById(R.id.delete);
        update=findViewById(R.id.update);
        query=findViewById(R.id.query);
        save.setOnClickListener(this);
        delete.setOnClickListener(this);
        update.setOnClickListener(this);
        query.setOnClickListener(this);

    }

    @Override
    protected void onStart() {
        super.onStart();
         databaseUserHelper=DatabaseUserHelper.getInstance(this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        //关闭数据库连接
        databaseUserHelper.close();
    }

    @SuppressLint("NonConstantResourceId")
    @Override
    public void onClick(View view) {
        String et_name=name.getText().toString();
        String et_age=age.getText().toString();
        String et_weight=weight.getText().toString();
        String et_height=height.getText().toString();
        User user=null;
        switch (view.getId()){
            case R.id.save:
                user=new User(et_name,
                        Integer.parseInt(et_age),
                        Long.parseLong(et_height),
                        Long.parseLong(et_weight),
                        married.isChecked());
                if(databaseUserHelper.insert(user)>0){
                    ToastUtil.show(this,"添加成功");
                }
                break;
            case R.id.delete:
                if(databaseUserHelper.deleteByName(et_name)>0){
                    ToastUtil.show(this,"删除成功");
                }
            case R.id.update:
                user=new User(et_name,
                        Integer.parseInt(et_age),
                        Long.parseLong(et_height),
                        Long.parseLong(et_weight),
                        married.isChecked());
                if(databaseUserHelper.update(user)>0){
                    ToastUtil.show(this,"更新成功");
                }
            case R.id.query:
                List<User> list=databaseUserHelper.queryAll();
                for (User u :list){
                    Log.d("query",u.toString());
                }
                break;
        }

    }
}
  1. 事务管理

    事务类
    beginTransaction:开始事务
    setTransactionSuccessful:设置事务成功标志
    endTransaction:结束事务
    事务的作用就是保证数据的一致性和完整性(避免异常和错误等导致的数据信息异常),能让多个并发访问数据库的时候彼此不被干扰。
  2. Onupgrade方法

    onupgrade方法在数据库版本更新的时候会被执行,即上文的DB_VERSION不为1的时候,数据库在运行的时候会自动比对,不一致则会被执行。

如将版本号变为2,在upgrade中为数据库新添加字段

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        String sql="ALTER TABLE "+TABLE_NAME+" ADD COLUMN phone VARCHAR";
        sqLiteDatabase.execSQL(sql);
    }

file

九、外部存储空间

Android把外部存储分成了两块区域,一块是所有应用均可访问的公共空间,另一块是只有应用自己才可以访问的存储空间,私有空间只要应用卸载了
就消失了,但是公共空间即使应用被卸载了,数据依旧会放在里面。

例子:将姓名,身高,年龄,体重,已婚分别保存到不同的外部存储空间,然后将其读取出来,卸载应用后会发现数据依旧存在外部存储空间。

package com.example.datastorage;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;

import com.example.datastorage.util.FileUtil;
import com.example.datastorage.util.ToastUtil;

import java.io.File;
import java.io.IOException;

public class FileWriteActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText name;
    private EditText age;
    private EditText weight;
    private EditText height;
    private CheckBox married;
    private TextView tv_text;
    private String path;
    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_file_write);
        name=findViewById(R.id.name);
        age=findViewById(R.id.age);
        weight=findViewById(R.id.weight);
        height=findViewById(R.id.height);
        married=findViewById(R.id.married);
        tv_text=findViewById(R.id.tv_text);
        Button save = findViewById(R.id.save);
        Button bt_read= findViewById(R.id.bt_read);
        save.setOnClickListener(this);
        bt_read.setOnClickListener(this);
    }

    @SuppressLint("NonConstantResourceId")
    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.save:
                String et_name=name.getText().toString();
                String et_age=age.getText().toString();
                String et_weight=weight.getText().toString();
                String et_height=height.getText().toString();
                boolean et_married=married.isChecked();
                String stringBuilder = "姓名:" + et_name +
                        "年龄:" + et_age +
                        "身高:" + et_height +
                        "体重:" + et_weight +
                        "婚否:" + (et_married ? "是" : "否");
                //外部私有存储空间
                String directory=null;
                String fileName=System.currentTimeMillis()+".txt";
                directory=getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS).toString();
                path=directory+ File.separatorChar+fileName;
                //外部公共存储空间
//               directory=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).toString();
//                path=directory+ File.separatorChar+fileName;
                    FileUtil.saveText(path, stringBuilder);
                    ToastUtil.show(this,"保存成功");
                    Log.d("路径:",path);
                break;
            case R.id.bt_read:
                tv_text.setText(FileUtil.queryText(path));
                break;

        }
    }
}
package com.example.datastorage.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FileUtil {
    public  static  void saveText(String path,String txt) {
        BufferedWriter os=null;
        try {
            os=new BufferedWriter(new FileWriter(path));
            os.write(txt);

        } catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            if(os!=null){
                try{
                    os.close();
                }
                catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
    public static  String queryText(String path){
        BufferedReader is=null;
        StringBuilder stringBuilder=new StringBuilder();
        try{
            is=new BufferedReader(new FileReader(path));
            String line=null;
            while((line=is.readLine())!=null){
                stringBuilder.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stringBuilder.toString();
    }
}
注意存到外部公共空间,需要在Mainifest.xml中加入权限。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission-sdk-23 android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission-sdk-23 android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:requestLegacyExternalStorage="true"
        android:theme="@style/Theme.MyApplication">
        <activity
            android:name=".FileWriteActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
  1. 存储卡中读取图片
Andorid的位图工具是Bitmap,App读写Bitmap可以使用性能更好的OuputStream和InputStream
Android还提供BitmapFactory工具用于读取各种来源图片,方法如下:
decodeResource:从资源文件中读取图片信息
decodeFile:该方法可将指定路径图片读取到Bitmap对象
decodeStream:从输入流中读取位图数据

例子:通过bitmap读取图片存储到存储卡中,然后读取到ImageView中显示。

    public static void saveImage(String path, Bitmap bitmap) {
        FileOutputStream outputStream=null;
        try {
            outputStream=new FileOutputStream(path);
            //通过bitmap压缩文件输出流
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
        }
        catch (Exception e){
            e.printStackTrace();
        }
        finally {
            if(outputStream!=null){
                try{
                    outputStream.close();
                }
                catch (Exception e){
                    e.printStackTrace();
                }
            }
        }

    }
    public static  Bitmap openImage(String path){
        FileInputStream inputStream=null;
        Bitmap bitmap=null;
        try{
            inputStream=new FileInputStream(path);
            bitmap= BitmapFactory.decodeStream(inputStream);
        }catch (Exception e){
            e.printStackTrace();
        }
        finally {
            if(inputStream!=null){
                try{
                    inputStream.close();
                }
                catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        return bitmap;
    }
}
package com.example.datastorage;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

import com.example.datastorage.util.FileUtil;
import com.example.datastorage.util.ToastUtil;

import java.io.File;

public class ImageWriteActivity extends AppCompatActivity implements View.OnClickListener{
    private ImageView imageView;
    private String path;
    @SuppressLint("MissingInflatedId")
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_image_write);
        Button bt_read=findViewById(R.id.bt_read);
        Button bt_save=findViewById(R.id.bt_save);
        imageView=findViewById(R.id.bt_image);
        bt_read.setOnClickListener(this);
        bt_save.setOnClickListener(this);
    }

    @SuppressLint("NonConstantResourceId")
    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.bt_save:
                String filename=System.currentTimeMillis()+".jpeg";
                path=getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + File.separatorChar +filename;
                Log.d("图片保存路径",path);
                Bitmap bitmap= BitmapFactory.decodeResource(getResources(),R.drawable.image);
                FileUtil.saveImage(path,bitmap);
                ToastUtil.show(this,"保存成功");
                break;
            case R.id.bt_read:
//                imageView.setImageBitmap(FileUtil.openImage(path));
                Bitmap bitmap1=BitmapFactory.decodeFile(path);
                imageView.setImageBitmap(bitmap1);

                break;
        }
    }
}
  1. Application

    Application是Android的一大组件,在App的运行过程中有且只有一个Application对象,贯穿整个生命周期,创建在Acitivity之前。
    Application有如下的三种方法:
    onCreate(),启动程序时调用。
    onTerminate(),App退出时调用,用于模拟环境测试,不会在真实产品中回调。
    OnConfigurationChange(),配置改变时调用,如竖屏变横屏。
    一般用于读取一些要频繁读取的小型数据,因为存放的位置是内存,因此不能放太多太大的数据。

例子:将一个人的信息存放到Application变量中。

MyApplication.java类:

package com.example.datastorage;

import android.app.Application;
import android.util.Log;

import java.util.HashMap;

public class MyApplication  extends Application {
    private static  MyApplication application;
    public HashMap<String,String> stringHashMap=new HashMap<>();

    public static MyApplication getInstance(){
        return  application;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        application=this;
        Log.d("App状态:","App启动");
    }
}
package com.example.datastorage;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;

import java.util.Objects;

public class AppWriteActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText name;
    private EditText age;
    private EditText weight;
    private EditText height;
    private CheckBox married;
    private Button save;
    private  MyApplication myApplication;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_app_write);
        name=findViewById(R.id.name);
        age=findViewById(R.id.age);
        weight=findViewById(R.id.weight);
        height=findViewById(R.id.height);
        married=findViewById(R.id.married);
        save=findViewById(R.id.save);
        save.setOnClickListener(this);
        myApplication=MyApplication.getInstance();
        reload();
    }

    private void reload() {
        String app_name=myApplication.stringHashMap.get("name");
        if(app_name==null){
            return ;
        }
        String app_age= myApplication.stringHashMap.get("age");
        String app_weight=myApplication.stringHashMap.get("weight");
        String app_height=myApplication.stringHashMap.get("height");
        String app_married=myApplication.stringHashMap.get("married");
        name.setText(app_name);
        age.setText(app_age);
        weight.setText(app_weight);
        height.setText(app_height);
        if(Objects.equals(app_married, "是")){
            married.setChecked(true);
        }
        else{
            married.setChecked(false);
        }
    }

    @Override
    public void onClick(View view) {
        String et_name=name.getText().toString();
        String et_age=age.getText().toString();
        String et_weight=weight.getText().toString();
        String et_height=height.getText().toString();
        boolean et_married=married.isChecked();
        myApplication.stringHashMap.put("name",et_name);
        myApplication.stringHashMap.put("age",et_age);
        myApplication.stringHashMap.put("weight",et_weight);
        myApplication.stringHashMap.put("height",et_height);
        myApplication.stringHashMap.put("married",et_married ?"是":"否");
    }
}
只要程序没有被关闭,Application存放的东西就依旧存在,程序关闭后,数据被回收就不存在了。

十、Jetpack Room

Room框架基于SQLite,通过注解技术极大的简化了数据库操作,减少了原来相当一部分的代码量,跟Java后端开发的Mybatis大致相同,就是可以直接使用注解完成数据库的操作。

使用Room之前要修改build.grandle模块文件,在dependencies中添加两行:

implementation 'androidx.room:room-runtime:2.5.1'
annotationProcessor 'androidx.room:room-compiler:2.5.1'

例子:写一个书籍数据库的增删改查

Room框架编码过程一般分为以下五步:
  1. @Entity:编写书籍信息表对应的实体类
  2. @Dao:编写书籍信息表对应的持久化类
  3. @Database:编写书籍信息表对应的数据库类,由RoomDatabase派生
  4. 在自定义的Application类中声明数据库唯一实例
  5. 在操作书籍信息表的地方获取数据表的持久化对象
  6. 创建数据库实体类
package com.example.datastorage.entity;

import androidx.room.Entity;
import androidx.room.PrimaryKey;

@Entity
public class Book {

    @PrimaryKey(autoGenerate = true)
    public Integer id;
    public String name;
    public String author;
    public String press;
    public String price;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getPress() {
        return press;
    }

    public void setPress(String press) {
        this.press = press;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", press='" + press + '\'' +
                ", price='" + price + '\'' +
                '}';
    }

}
  1. 创建Dao接口
package com.example.datastorage.Dao;

import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;

import com.example.datastorage.entity.Book;

import java.util.List;

@Dao
public interface BookDao {
    @Insert
    void insert(Book... books);
    @Delete
    void delete(Book...books);

    @Query("DELETE FROM Book")
    void deleteAll();
    @Update
    int update(Book...books);

    @Query("SELECT *FROM Book")
    List<Book> queryAll();

    @Query("SELECT *FROM Book where name=:name order by id desc limit 1")
    Book queryByName(String name);

}
  1. 持久化类
package com.example.datastorage.database;

import androidx.room.Database;
import androidx.room.RoomDatabase;

import com.example.datastorage.Dao.BookDao;
import com.example.datastorage.entity.Book;

//exportSchema表示是否导出数据库信息的json串(便于检查调试),设为true需要gradle指定json的生成路径。
@Database(entities = {Book.class},version = 1,exportSchema = false)
public abstract  class BookDatabase  extends RoomDatabase {
    //获得数据库某张表的持久化对象
    public abstract BookDao bookDao();

}

Application启动类:

package com.example.datastorage;

import android.app.Application;
import android.util.Log;

import androidx.room.Room;

import com.example.datastorage.database.BookDatabase;

import java.util.HashMap;

public class MyApplication  extends Application {
    private static  MyApplication application;
    public HashMap<String,String> stringHashMap=new HashMap<>();

    public static MyApplication getInstance(){
        return  application;
    }
    private BookDatabase bookDatabase;
    @Override
    public void onCreate() {
        super.onCreate();
        application=this;
        Log.d("App状态:","App启动");
        //构建书籍数据库实例,允许数据库迁移和主线程运行
        bookDatabase= Room.databaseBuilder(this,BookDatabase.class,
                "book").addMigrations()
                .allowMainThreadQueries()
                .build();
    }
    public BookDatabase getBookDB(){
        return bookDatabase;
    }
}
  1. 使用类:
package com.example.datastorage;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;

import com.example.datastorage.Dao.BookDao;
import com.example.datastorage.entity.Book;
import com.example.datastorage.util.ToastUtil;

import java.util.List;

public class RoomWriteActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText name;
    private EditText Author;
    private EditText press;
    private EditText price;
    private BookDao bookDao;
    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_room_write);
        name=findViewById(R.id.bookName);
        Author=findViewById(R.id.author);
        press=findViewById(R.id.press);
        price=findViewById(R.id.price);
        Button bt_save=findViewById(R.id.save);
        Button bt_query=findViewById(R.id.query);
        Button bt_delete=findViewById(R.id.delete);
        Button bt_update=findViewById(R.id.update);
        bt_save.setOnClickListener(this);
        bt_query.setOnClickListener(this);
        bt_delete.setOnClickListener(this);
        bt_update.setOnClickListener(this);
        bookDao=MyApplication.getInstance().getBookDB().bookDao();

    }

    @SuppressLint("NonConstantResourceId")
    @Override
    public void onClick(View view) {
        String put_name=name.getText().toString();
        String put_author=Author.getText().toString();
        String put_press=press.getText().toString();
        String put_price=price.getText().toString();
        switch (view.getId()){
            case R.id.save:
                Book book=new Book();
                book.setName(put_name);
                book.setAuthor(put_author);
                book.setPress(put_press);
                book.setPrice(put_price);
                bookDao.insert(book);
                ToastUtil.show(this,"保存成功");
                break;
            case R.id.delete:
                Book b2=new Book();
                b2.setId(2);
                bookDao.delete(b2);
                ToastUtil.show(this,"删除成功");
                break;
            case R.id.query:
                List<Book> list=bookDao.queryAll();
                for(Book b : list){
                    Log.d("查询书籍:", b.toString());
                }
                break;
            case R.id.update:
                Book b4=bookDao.queryByName(put_name);
                Book b3=new Book();
                b3.setId(b4.getId());
                b3.setName(put_name);
                b3.setAuthor(put_author);
                b3.setPress(put_press);
                b3.setPrice(put_price);
                bookDao.update(b3);
                ToastUtil.show(this,"修改成功");
                break;
        }
    }
}

十一、正文字数太多,开启下一篇

~  ~  The   End  ~  ~


 赏 
承蒙厚爱,倍感珍贵,我会继续努力哒!
logo图像
tips
文章二维码 分类标签:开发开发
文章标题:安卓基础学习
文章链接:https://aiwin.fun/index.php/archives/2852/
最后编辑:2024 年 1 月 4 日 16:55 By Aiwin
许可协议: 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
(*) 8 + 9 =
本文共 1 条评论。您也快来参与吧!
    11月28日 美国 发自Windows 10 回复

    你的文章总是能给我带来欢乐,谢谢你!