Android 开发

Android采用Log工具大一混日志,他将各类日志划分为五个等级:

  • Log.e:错误信息

  • Log.w:警告信息

  • Log.i:一般消息

  • Log.d:调试信息

    Log.d("ning", "onCreate");
    
  • Log.v:冗余信息

模块对应实际的app,运行试运行模块不是运行项目

1.项目的目录结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CJzVDGRz-1679196459953)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311124001595.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OxLHsEZT-1679196459955)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311124556824.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6BBaicY0-1679196459956)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311131521576.png)]

利用xml标记描绘应用界面

把Ap的界面设计与逻辑代码分开的好处:

  • 使用xml文件面搜狐App界面,可以很方便地在Android Studil上预览界面效果。
  • 一个界面布局可以被多出代码复用,反过来,一个java代码也可以适配多个页面布局。

2.手动创建App页面

  • 在layout目录下创建xml文件

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sryHqhra-1679196459956)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311142750842.png)]

  • 创建与xml文件对应的java代码

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IWHgFSMp-1679196459957)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311143113481.png)]

  • 在AndroidManifest.xml中注册页面配置

或者:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qct6pVU3-1679196459957)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311134641976.png)]

3.添加文本信息

4.设置文本大小

  • 在java代码中调用setTextSize方法,即可指定文本大小
  • 在xml文件中则通过属性android:textSize指定文本大小,此时需要指定字号单位
    • px:他是手机屏幕的最小显示单位,与设备的显示屏有关
    • dp:他是与设备无关的显示单位,至于屏幕的尺寸有关
    • sp:他专门用来设置字体大小,在系统设置中可以调整字体大小

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jTbpW25Z-1679196459957)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311151542911.png)]

5.设置文本颜色

  • 在xml文件中通过**android:textColor=“#00ff00”**指定文本的颜色,色值有透明度alpha和RGB联合定义。

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9cwgbSwF-1679196459958)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311153841333.png)]

  • 在java代码中设置字体颜色

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gia8w7JN-1679196459958)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311153929374.png)]

  • 色值有八位十六进制数六位十六进制数两种表的方式,例如八位编码FFEEDDCC中,FF表示透明度(FF不透明)、EE表示红色浓度、DD表示红色浓度、CC表示蓝色浓度。

  • 透明的为FF表示完全不透明,为00表示完全透明。RGB数值越大表示颜色越浓,数值越小,表示颜色越淡,也就越暗。

6.设置文本背景色

  • 在java代码中使用**setBackgroundColor();**方法

    • 也可以使用资源文件中的颜色 eg:使用**setBackgroundResource();**方法

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DkIPFy8W-1679196459958)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311155544789.png)]

  • 在xml中使用android:background

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VzUWxaGm-1679196459959)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311155140767.png)]

7.设置视图的高宽

在xml文件中设置

视图的高通过android:layout_width表达,视图高通过属性android:layout_height表达,值分为以下三种:

  • match_parent:表示与上级视图一致
  • warp_content: 表示与内容自适应
  • 以dp为单位的具体尺寸

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rcJVxPL2-1679196459959)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311203448593.png)]

在代码中设置

  • 首先确保xml中的宽高属性值是warp_content,接着打开对应的java代码,执行以下步骤:

    • 调用控件对象的getLayoutParams方法,获取控件的布局参数。

    • 布局参数的width属性表示宽度,height属性表示高度,修改这两个有效值。

      • 需要新建一个工具类,来进行换算

        package com.example.chapter03.util;import android.content.Context;public class Utils {// 根据手机的分辨率从dp的单位 转换成px(像素)public static int dip2dp(Context context,float dpValue){//获取当前收集的像素密度(1个dp对应几个px)float scale = context.getResources().getDisplayMetrics().density;// 四舍五入取整return (int)(dpValue * scale + 0.5f);}
        }
        

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Oa2FZG5v-1679196459959)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311204012545.png)]

    • 调用控件对象的setLayoutParams方法,填入修改后的布局参数使之生效。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FcbFmO2N-1679196459959)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311203936452.png)]

8.设置视图的间距

设置视图的间距有两种方式;

  • 采用layout_margin属性,他指定了当前视图与周围平级视图之间的距离。包括layout_marginlayout_marginLeftlayout_marginRightlayout_marginToplayout_marginButtom
  • 采用padding属性,他指定了当前视图与内部下级视图之间的距离。包括paddingpaddingLeftpaddingRightpaddingToppaddingButtom

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ogStW2Lf-1679196459960)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311214627005.png)]

9.设置视图的对齐方式

视图的他对齐方式由两种途径:

  • 采用layout_gravity属性,他指定了当前视图相对于上级视图的对齐方式。
  • 采用gravity属性,他制定了夏季视图相对于当前视图的对齐方式。

layout_gravitygravity的取值包括:lefttoprightbottom、还可以用竖线链接各取值,例如“left|top”表示即靠左有靠上,也就是朝左上角对齐

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TIc8WvYX-1679196459960)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230311221222742.png)]

二. 布局方式

2.1 线性布局LinearLayout

  • 线性布局内部的各视图有两种排列方式:

    • orientation属性值为horizontal时,内部视图在水平方向上排列。
    • orientation属性值为vertical时,内部视图在垂直方向上排列。
  • 如果不指定orientation属性,则默认水平方向

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a0mpeixh-1679196459960)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312112642949.png)]

<LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="横排第一个"android:textColor="#0000ff"android:textSize="17dp" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="横排第二个"android:textColor="#00ff00"android:textSize="17dp" />
</LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="竖排第一个"android:textColor="#ff0000"android:textSize="17dp" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="竖排第二个"android:textColor="#ff00ff"android:textSize="17dp" />
</LinearLayout>

2.2 线性布局的权重

  • 指的是线性布局的下级视图各自拥有对大比例的宽高。
  • 权重属性名交layout_weight,该属性不在LinerLayout节点设置,而在线性布局的直接下级视图设置,表示下级视图占据的宽高比例。
    • layout_width0dp时,layout_weight表示水平方向的宽度比例。
    • layout_height0dp时,layout_weight表示竖直方向上的宽度比例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t0hHbfbc-1679196459961)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312113419693.png)]

<LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:background="@color/purple_200"android:text="横排第一个"android:textColor="#0000ff"android:textSize="30dp" /><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:background="@color/black"android:text="横排第二个"android:textColor="#00ff00"android:textSize="30dp" />
</LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="0dp"android:layout_weight="1"android:background="@color/cardview_dark_background"android:text="竖排第一个"android:textColor="#ff0000"android:textSize="30dp" /><TextViewandroid:layout_width="wrap_content"android:layout_height="0dp"android:layout_weight="2"android:background="@color/design_default_color_error"android:text="竖排第二个"android:textColor="#ff00ff"android:textSize="30dp" />
</LinearLayout>

2.3先对布局RelativeLayout

  • 相对布局的下级视图位置有其他视图决定。用于确定下级视位置的参照为分为两种:

    • 与该视图自身平级的视图
    • 该视图的上级视图
  • 如果不设定下级视图的参照物,那么下级视图默认显示在RelativeLayout内部的左上角

属性取值

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".RelativeLayoutActivity"><TextViewandroid:id="@+id/tv_center"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:text="全局中间"android:layout_centerInParent="true"android:textColor="@color/black"android:textSize="30sp"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:text="水平中间"android:layout_centerHorizontal="true"android:textColor="@color/black"android:textSize="30sp"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:text="垂直中间"android:layout_centerVertical="true"android:textColor="@color/black"android:textSize="30sp"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:text="上级左边对齐"android:layout_alignParentLeft="true"android:textColor="@color/black"android:textSize="17sp"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:text="上级右边对齐"android:layout_alignParentRight="true"android:textColor="@color/black"android:textSize="17sp"/><!--<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:text="上级顶部对齐"android:layout_alignParentTop="true"android:textColor="@color/black"android:textSize="17dp"/>--><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:text="上级底部对齐"android:layout_alignParentBottom="true"android:textColor="@color/black"android:textSize="17sp"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:text="全局中间右部对齐"android:layout_toRightOf="@id/tv_center"android:layout_alignBottom="@id/tv_center"android:textColor="@color/black"android:textSize="17sp"/>
</RelativeLayout>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TEsK00Pg-1679196459961)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312115544209.png)]

2.4网格布局GridLayout

网格布局默认从左往右,从上到下排列,它新增了两个属性:

  • columnCount属性,他只定了网格的列数,级每行能放多少个视图;
  • rowCount属性,他制定了网格的行数,即每列能放多少个视图;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gO1oefzr-1679196459962)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312134552593.png)]

2.5 滚动视图

滚动视图有两种:

  • ScrollView,他是垂直方向的滚动视图;垂直方向滚动是,layout_width属性值设置为mach_parentlayout_height属性设置为wrap_content
  • HorizontalScrollView,水平方向的滚动视图;水平方向滚动时,layout_width属性值设置为wrap_contentlayout_height属性设置为mach_parent

水平方向

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OxQP6wg1-1679196459962)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312135604732.png)]

<HorizontalScrollViewandroid:layout_width="wrap_content"android:layout_height="200dp"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="match_parent"android:orientation="horizontal"><Viewandroid:layout_width="300dp"android:layout_height="match_parent"android:background="#aaff00" /><Viewandroid:layout_width="300dp"android:layout_height="match_parent"android:background="#aaffff" /></LinearLayout>
</HorizontalScrollView>

竖直方向

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3iLJViqY-1679196459962)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312135934368.png)]

<ScrollViewandroid:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><Viewandroid:layout_width="match_parent"android:layout_height="400dp"android:background="#00ff00" /><Viewandroid:layout_width="match_parent"android:layout_height="400dp"android:background="#00ffaa" /></LinearLayout>
</ScrollView>

三. 按钮控件

3.1 button继承与TextView

  • Buton拥有默认的按钮背景,而TextView默认无背景
  • Butto的内部文本默认居中对齐,而TextView的内部文本默认靠左对齐
  • Button会默认将英文字母转为大写,而TextView保持原始英文的大小写

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7QAw2iqr-1679196459963)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312140909002.png)]

button的两个属性

  • textAllCaps属性,他制定了是否讲英文字母转为大写,为true时表示转换成大写,false表示不做大写转换。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O6wje4JK-1679196459963)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312141353610.png)]

  • onClick属性,他用来接管用户的点击动作,制定了点击按钮时要出发那个方法

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5x4lib9I-1679196459963)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312144028251.png)]

3.2点击事件和长按事件

  • 监听器,已实施专门监听控件的动作行为。只有控件发生了指定动作,监听器才会出发开关去执行对应的代码逻辑。
  • 按钮控件有两种常用的监听器:
    • 点击监听器,通过setOnClickListener方法设置。按钮被按住少于500毫秒时,会触发点击事件。
    • 长按监听器,通过setOnLongClickListener方法设置。按钮被按住超过500毫秒时,会触发长按事件。

点击监听器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q0OLzK43-1679196459964)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312152837348.png)]

ButtonClickActivity。java文件
package com.example.chapter03;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;import com.example.chapter03.util.DateUtil;public class ButtonClickActivity extends AppCompatActivity {private Button btn_click_single;private TextView tv_result;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_button_click);btn_click_single = findViewById(R.id.btn_click_single);tv_result = findViewById(R.id.tv_result);btn_click_single.setOnClickListener(new MyViewOnClickListener(tv_result));}// static 静态内部类可以减少内存泄漏static class MyViewOnClickListener implements View.OnClickListener{private final TextView tv_result;public MyViewOnClickListener(TextView tv_result) {this.tv_result = tv_result;}@Overridepublic void onClick(View v){String desc = String.format("%s 您点击了 %s 按钮", DateUtil.getNowTime(),((Button)v).getText());tv_result.setText(desc); //把编好的字符串显示在id为tv_result的文本区域}}
}

另一种写法 适合多个按钮时

package com.example.chapter03;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;import com.example.chapter03.util.DateUtil;public class ButtonClickActivity extends AppCompatActivity implements View.OnClickListener{private Button btn_click_single;private Button btn_click_public;private TextView tv_result;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_button_click);btn_click_single = findViewById(R.id.btn_click_single);tv_result = findViewById(R.id.tv_result);btn_click_single.setOnClickListener(this);
//        btn_click_single.setOnClickListener(new MyViewOnClickListener(tv_result));/***  this指当前的activity实例,让当前这个类实现OnClickListener的接口*  当按钮跟多时这样就可以公用这个activity,不用每个按钮都创建一个监听了*/btn_click_public = findViewById(R.id.btn_click_public);btn_click_public.setOnClickListener(this);}/*** 当按钮很多时,就要进行判断此时被点击的按钮是哪个 if(view.getId() == R.id.btn_click_public)* @param view*/@Overridepublic void onClick(View view) {if(view.getId() == R.id.btn_click_public){String desc = String.format("%s 您点击了 %s 按钮", DateUtil.getNowTime(),((Button)view).getText());tv_result.setText(desc); //把编好的字符串显示在id为tv_result的文本区域}if(view.getId() == R.id.btn_click_single){String desc = String.format("%s 您点击了 %s 按钮", DateUtil.getNowTime(),((Button)view).getText());tv_result.setText(desc); //把编好的字符串显示在id为tv_result的文本区域}}/*// static 静态内部类可以减少内存泄漏static class MyViewOnClickListener implements View.OnClickListener{private final TextView tv_result;public MyViewOnClickListener(TextView tv_result) {this.tv_result = tv_result;}@Overridepublic void onClick(View v){String desc = String.format("%s 您点击了 %s 按钮", DateUtil.getNowTime(),((Button)v).getText());tv_result.setText(desc); //把编好的字符串显示在id为tv_result的文本区域}}*/
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K6Z2AvR7-1679196459964)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312154217436.png)]

长按监听器

提供另一种事件坚挺的方式(匿名内部类,也可以是lambda表达式)

package com.example.chapter03;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;import com.example.chapter03.util.DateUtil;public class ButtonLongClickActivity extends AppCompatActivity {private TextView tv_result;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_button_long_click);tv_result = findViewById(R.id.tv_result);Button btn_long_click = findViewById(R.id.btn_long_click);/*** 匿名内部类*/btn_long_click.setOnLongClickListener(new View.OnLongClickListener() {@Overridepublic boolean onLongClick (View v){String desc = String.format("%s 您点击了 %s 按钮", DateUtil.getNowTime(),((Button)v).getText());tv_result.setText(desc); //把编好的字符串显示在id为tv_result的文本区域return true;}});}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ITBjDKW-1679196459964)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312155608281.png)]

禁用和恢复按钮

等待学习

四. 图像显示

4.1图像视图ImageView

图像视图展示的图片通常位于res/drawable***目录,设置图像视图的显示图片有两种方式:

  • xml文件中,通过属性android:src设置图片资源,属性值格式形如 “@drawable/不含扩展名的图片名称”。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C7ileFoF-1679196459964)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312162704074.png)]

  • java代码中,使用setImageResource方法设置图片资源,方法参数格式形如 “R.drawable.不含扩展名的图片名称

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Fz4vAHB-1679196459964)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312162807137.png)]

图像视图的缩放类型

ImageView默认居中显示,若要改变图片的显示方式,可通过scaleType属性设定,概述性的取值说明如下

4.2 图像按钮Imagebutton

  • Imagebutton是显示图片的图像按钮,但她继承自imageView,而非继承Button
  • ImagebuttonButton的区别:
    • Button即可显示文本也可显示图片,ImageButton只能显示图片。
    • Imagebutton上的图像可以按比例缩放,而Button通过北京市设置的图像会拉伸变形。
    • Button只能考北京显示一张图片,而Imagebutton可分别在前景和背景显示图片,从而实现两张图片叠放的效果。

4.3 同时展示文本与图像

  1. 利用LinearLayout对ImageView和TextView组合布局。
  2. 通过按钮控件Button的drawable***属性设置文本周围的图标。
    • drawableTop:指文字上方的图片。
    • drawableButtom
    • drawableLeft
    • drawableRight
    • drawablepadding:指定图片与文字的间距。

4.4 案例计算器

待学习… P34

五. 活动Activity

5.1 Activity的启动和结束

  • 从当前页面跳转到新页面,跳转代码如下:

    startActivity(new Intent(源页面.this,目标页面.class));
    
  • 从当前页面返回上一个页面,相当于关闭当前页面,返回代码如下:

    finish(); //结束当前的活动页面
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tBc76U90-1679196459965)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312210851335.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EnCZKHkP-1679196459965)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230312210904584.png)]

5.2 Activity生命周期

  • onCreate:创建活动,此时将页面布局加载到内存中,初始化页面。

  • onStart:开始活动,将页面展示在屏幕。

  • onResume:恢复活动,此时页面能够和用户进行交互,例如允许响应用户的点击动作、语序用户输入文字等。

  • onPause:暂停活动,页面进入暂停状态,无法和用户进行交互。

  • onStop:停止活动,页面不在屏幕显示。

  • onDestory:销毁活动,回收Activity占用的资源,彻底销毁该Activity。

  • onRestart:重启活动,重新加载内存中的页面数据,onStop状态可以转为onRestart状态。

  • onNewIntent:重用已存在的活动实例。如果一个Activity已经启动了,并且存在与当前栈,而当前栈的启动模式为SingleTask,SingleInstance,SingleTop(此时在任务栈顶端),那么再次启动该Activity的话,并不会重新进行onCreate,而是会执行onNewIntent方法。

打开新页面的方法调用顺序:

onCreate -> onStart -> onResume。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Teec3fEr-1679196459965)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230313134906680.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uT93QLcP-1679196459966)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230313135142849.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-olND2gGo-1679196459966)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230313135256421.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7N8A4u3q-1679196459966)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230313135427985.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yQbrsG5H-1679196459966)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230313135548384.png)]

5.3 Activity启动模式

不同的Activity可以设置不同的启动模式

eg:微信支付

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y90dw9sO-1679196459967)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230313142229471.png)]

等待学习…

在代码里设置启动标志:

在配置中设置启动模式:

5.4 在活动之间传递消息:

Intent能够让Android各组件之间进行沟通。

Intent主要完成下列工作:

  • 表明本次通信从哪里来,往哪里走,要怎么走。
  • 发送方可以携带消息给接收方,接收方可以从收到的Intent解析数据。
  • 发送方如果想要知道接收方的处理结果,接收方也可以通过Intent返回结果。

Intent组成部分:

显式Intent和隐式Intent

5.4.1显式Intent

直接指定来源互动,属于精确匹配。

创建方式:

  • 在Intent的构造函数中指定:
Intent intent = new Intent(this, NextActivity.class); // 创建一个目标确定的意图
  • 调用setClass指定:
Intent intent = new Intent();
intent.setClass(this, NextActivity.class); // 设置意图要跳转的目标活动
  • 调用setComponent指定:
Intent intent = new Intent();
// 创建包含目标活动在内的组件名称对象
ComponentName component = new ComponentName(this, NextActivity.class);
intent.setComponent(component);
5.4.2 隐式Intent:

没有明确指定所要跳转的页面,而是通过一些动作字符串来让系统自动匹配,属于模糊匹配。

通常是App不想向外暴露Activity的名称,只给出一个事先定义好的标记串。隐式Intent起到了标记过滤的作用。这些标记串可以自己定义,也有系统定义的。

​ 常见的系统动作如下:

跳转到自己的应用时注意:要在跳转后的页面AndroidManifest.xml文件中添加以下语句。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b03ERfkS-1679196459967)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230313194645630.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6xLkfpxZ-1679196459968)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230313194948225.png)]

package com.example.chapter04;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;public class ActionUriActivity extends AppCompatActivity implements View.OnClickListener {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_action_uri);findViewById(R.id.btn_dial).setOnClickListener(this);findViewById(R.id.btn_sms).setOnClickListener(this);findViewById(R.id.btn_my).setOnClickListener(this);}@Overridepublic void onClick(View view) {String phone = "12345";Intent intent = new Intent();switch (view.getId()){// 跳转到拨号页面 给12345 拨号case R.id.btn_dial:// 设置意图的动作行为  打电话intent.setAction(Intent.ACTION_DIAL);// 声明一个拨号的Uri  tel: 是固定的Uri uri1 = Uri.parse("tel:" + phone);intent.setData(uri1);startActivity(intent);break;// 跳转到发短信页面case R.id.btn_sms:// 设置意图的动作行为  发短信intent.setAction(Intent.ACTION_SENDTO);// 声明一个拨号的Uri smsto: 是固定的Uri uri2 = Uri.parse("smsto:" + phone);intent.setData(uri2);startActivity(intent);break;// 跳转到自己的应用chapter03case R.id.btn_my:intent.setAction("android.intent.action.LUN");intent.addCategory(Intent.CATEGORY_DEFAULT);startActivity(intent);break;}}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".ActionUriActivity"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:padding="5dp"android:text="点击按钮向号码12345发送请求"android:textSize="30sp"/><Buttonandroid:id="@+id/btn_my"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="跳到自己页面"/><Buttonandroid:id="@+id/btn_dial"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="跳到拨号页面"/><Buttonandroid:id="@+id/btn_sms"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="跳到短信页面"/>
</LinearLayout>

5.5 向下一个Activity发送数据

  • Intent使用Bundle对象存放代传递的数据信息。

  • Bundle对象操作各类型的读写方法说明见下表:

案例:

  1. 发送Activity

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hLKqwR3A-1679196459969)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230313201335172.png)]

package com.example.chapter04;import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;import androidx.appcompat.app.AppCompatActivity;import com.example.chapter04.util.DateUtil;public class SendActivity extends AppCompatActivity implements View.OnClickListener {private TextView tv_send;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_send);findViewById(R.id.btn_send).setOnClickListener(this);tv_send = findViewById(R.id.tv_send);}@Overridepublic void onClick(View view) {Intent intent = new Intent(this, ReceiveActivity.class);// 新建一个包裹Bundle bundle = new Bundle();bundle.putString("request_time", DateUtil.getNowTime());bundle.putString("request_content",tv_send.getText().toString());intent.putExtras(bundle); // 包裹放进意图对象 注意是 putExtrasstartActivity(intent);}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZS20L2v3-1679196459969)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230313201625898.png)]

  1. 接收Activity

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iX5Ii2BS-1679196459970)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230313201426413.png)]

package com.example.chapter04;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.widget.TextView;public class ReceiveActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_receive);TextView tv_receive = findViewById(R.id.tv_receive);// 仓上一个意图 获取快递包裹Bundle bundle = getIntent().getExtras();String request_time = bundle.getString("request_time");String request_content = bundle.getString("request_content");String desc = String.format("收到请求小写:\n请求时间:%s \n 请求内容:%s",request_time,request_content);tv_receive.setText(desc);}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-37aZOXPv-1679196459971)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230313201653901.png)]

5.6 想上一个Activity返回数据

处理下一个页面的应答数据,详细步骤:

  • 上一个页面打包好请求数据,把数据打包传递给下一个页面。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wFV8NeQl-1679196459971)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314151612504.png)]

  • 下一个页面接收到消息,并将处理过的数据打包好放入intent对象中,结束当前活动

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p0jKwzyE-1679196459972)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314151642365.png)]

    package com.example.chapter04;import androidx.appcompat.app.AppCompatActivity;import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.TextView;import com.example.chapter04.util.DateUtil;public class ActResponseActivity extends AppCompatActivity implements View.OnClickListener {private String mResponse = "开始学啦!";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_act_response);TextView tv_request = findViewById(R.id.tv_request);// 从上一个页面传来的意图中获取快递包裹Bundle bundle = getIntent().getExtras();String request_time = bundle.getString("request_time");String request_content = bundle.getString("request_content");String desc = String.format("%s 请求信息是 %s",request_time ,request_content);tv_request.setText(desc);findViewById(R.id.btn_act_response).setOnClickListener(this);TextView tv_response = findViewById(R.id.tv_response);tv_response.setText("待返回的消息:"+mResponse);}@Overridepublic void onClick(View view) {// 点这个按钮我们要返回上一层,并带一些数据Intent intent = new Intent();// 打包要带回的数据Bundle bundle = new Bundle();bundle.putString("response_time", DateUtil.getNowTime());bundle.putString("response_content", mResponse);intent.putExtras(bundle);// 把bundle放到intent里边去// 携带意图返回上一个页面。RESULT_OK表示处理成功setResult(Activity.RESULT_OK,intent);// 结束当前和活动页面,返回上一个页面finish();}
    }
    
  • 上一个页面通过

    register = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {...}
    

    来调用回调方法。并处理数据。(这里要定义一个私有变量

    private ActivityResultLauncher<Intent> register;
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X5P29f6C-1679196459972)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314151505655.png)]

    package com.example.chapter04;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.AppCompatActivity;import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.TextView;import com.example.chapter04.util.DateUtil;public class ActRequestActivity extends AppCompatActivity implements View.OnClickListener {private String mRequest = "今天学习了吗?";private ActivityResultLauncher<Intent> register;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_act_request);TextView tv_request = findViewById(R.id.tv_request);TextView tv_response = findViewById(R.id.tv_response);tv_request.setText("待发送的消息:" + mRequest);findViewById(R.id.btn_act_request).setOnClickListener(this);// startActivityForResult方法已经过时,下面是新方法// register在onCreate里只能注册一次register = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {// 从Response回来会带用这个  回调方法@Overridepublic void onActivityResult(ActivityResult result) {Intent intent = result.getData();// 判断是否为空 并且处理结果没有异常 就获取信息if (result != null && result.getResultCode() == Activity.RESULT_OK) {Bundle bundle = intent.getExtras();String response_time = bundle.getString("response_time");String response_content = bundle.getString("response_content");String desc = String.format("%s 接受返回的信息是 %s",response_time ,response_content);tv_response.setText(desc);}}});}@Overridepublic void onClick(View view) {Intent intent = new Intent(this, ActResponseActivity.class);// 创建一个新包裹Bundle bundle = new Bundle();bundle.putString("request_time", DateUtil.getNowTime());bundle.putString("request_content", mRequest);intent.putExtras(bundle);register.launch(intent);}
    }
    

5.7 为Activity补充附加信息

从string.xml中获取字符串

  • 在string.xml中定义一个字符串

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gGHFXeQu-1679196459972)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314153306024.png)]

  • 在java代码中使用gerString方法获取对应的字符串值

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-my0AJgBQ-1679196459973)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314153418521.png)]

    getString是继承自Content(上下文)

在代码中获取元数据

  • 调用getPackageManager方法获得当前应用的包管理器
  • 调用包管理器的getActivityInfo方法获得当前活动的信息对象
  • 活动信息对象的mataDataBundle包裹类型,调用包裹对象的getString即可获得指定名称的参数值。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WxlZp3Rs-1679196459973)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314154556418.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VGbXYlcs-1679196459973)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314154626488.png)]

给应用页面注册快捷方式

元数据不仅能传递简单的字符串参数,还能传送更复杂的资源数据,比如支付宝的快捷方式菜单

待学习…

六. 图形Drawable

  • Drawable 类型表达了各种各样的图形,包括图片、色块、画板、北京等。
  • 包含图片在内的图形文件放在res目录的各个drawable目录下,其中drawable目录一般保存描述性XML文件,而图片文件一般放在具体分辨率的drawable目录下。
  • 各视图的background属性、ImageView和ImageButton的src属性、TextView和Button四个方向的drawable**系列属性都可以引用图形文件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IiK6XGCi-1679196459973)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314170011095.png)]

6.1 形状图形

  • Shape图形又称形状图形,让他用来描述常见的几何形状,包括矩形、圆角矩形、圆形、椭圆等等。
  • 形状图形的定义文件是shape标签为根节点的XML文件,他支持四种类型的形状:
    • rectangle:矩形(默认值)
    • oval:椭圆 (此时corners节点会失效)
    • line:直线 (此时必须设置stroke节点,不然会报错)
    • ring:圆环

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dVukZUED-1679196459974)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314174302475.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dEtaUEiq-1679196459974)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314174443231.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8RrYfSmp-1679196459974)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314174721796.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0eHdGBZf-1679196459974)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314174815373.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dajWzzcO-1679196459975)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314174902284.png)]

案例:点击按钮转换背景
  1. 在drawable目录下新建 shapr_oval_rose.xml和shape_rect_gold.cml

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QgMCToaJ-1679196459975)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314173311852.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u3Q6zTcf-1679196459975)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314173434889.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vHkGlUVk-1679196459975)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314173624809.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bm1wuS9k-1679196459975)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314173650038.png)]

  1. 在layout目录下的activity_drawable_shape.xml里设置布局与按钮

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7L8QLTX0-1679196459976)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314173840947.png)]

  2. 编写Activity,对按钮进行事件监听

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-las5G8Vm-1679196459976)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314173901139.png)]

结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wHp65QBs-1679196459976)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314174017650.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BtgadrLx-1679196459976)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314174102285.png)]

6.2 点9图片

待攻克…

6.3 状态列表图形

待攻克…

七. 选择按钮

待攻克…

7.1 复选框CheckBox

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lbIydUoK-1679196459977)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314195850716.png)]

7.2 开关按钮Switch

待攻克…

7.3 单选按钮RadioButton

待攻克…

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wejGjS6F-1679196459977)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230316154353653.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sBLCMqf8-1679196459978)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230316154454450.png)]


八. 文本输入

8.1 编辑框

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G2LKzwQX-1679196459978)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314203839676.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sZVWhbXt-1679196459978)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314204109263.png)]

编辑框也可以自定义形状

  1. 创建一个名为EditBorderActivity的Activity

  2. 在布局里边写三个编辑框

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SdkF1Zug-1679196459978)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314210617209.png)]

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".EditSimpleActivity"><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:hint="这是默认的边框"android:inputType="text"android:padding="5dp" /><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:background="@null"android:hint="去除边框"android:inputType="text"android:padding="5dp" /><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:hint="自定义边框"android:background="@drawable/editext_selector"android:inputType="textPassword"android:paddingLeft="5dp" /></LinearLayout>
    
  3. 在drawable中新建shape_edit_focus.xml(被选中时的样式)和 shape_shape_normal.xml(未被选中时的样式)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0fYt59fP-1679196459979)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230314211021505.png)]

    shape_edit_focus.xml代码<?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"><solid android:color="#ffffff" /><strokeandroid:width="2dp"android:color="#0000ff" /><corners android:radius="5dp" /><!--    指定形状四个方向上的间距--><paddingandroid:bottom="2dp"android:left="2dp"android:right="2dp"android:top="2dp" />
    </shape>----------------------------------------------------------shape_shape_normal.xml代码<?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"><solid android:color="#ffffff" /><strokeandroid:width="2dp"android:color="#aaaaaa" /><corners android:radius="5dp" /><!--    指定形状四个方向上的间距--><paddingandroid:bottom="2dp"android:left="2dp"android:right="2dp"android:top="2dp" /></shape>
    
  4. 运行

8.2 交点变更监视器

待攻克…

8.3 文本变化监听器

待攻克…

九. 对话框

9.1 提醒对话框AlertDialog

  • AlertDialog 可以完成常见的交互操作,;如提示、确认、选择等功能。AlertDialog 借助建造器 AlertDialog.Bulider 才能完成参数设置。
  • 调用建造器的 create 方法生成对话框实例,在调用对话框实例的 show 方法,在页面上弹出提醒对话框。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TSOsdSIt-1679196459979)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230315170004354.png)]

package com.example.chapter05;import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;public class AlertDialogActivity extends AppCompatActivity implements View.OnClickListener {private TextView tv_alert;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_alert_dialog);findViewById(R.id.btn_alert).setOnClickListener(this);tv_alert = findViewById(R.id.tv_alert);}@Overridepublic void onClick(View view) {// 创建对话框的构建器AlertDialog.Builder builder = new AlertDialog.Builder(this);//builder.setTitle("你好!");//builder.setMessage("你在干嘛?");// 设置对话框的 否定 按钮文本监听器builder.setPositiveButton("滚", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {tv_alert.setText("好好好");}});// 设置对话框的 肯定 按钮文本监听器builder.setNegativeButton("卷", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {tv_alert.setText("666");}});// 根据建造器构建提醒对话框对象AlertDialog dialog = builder.create();// 显示提醒对话框dialog.show();}
}------------------------------------------------------------------------------------------------------------
布局文件
------------------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".AlertDialogActivity"android:orientation="vertical"><Buttonandroid:id="@+id/btn_alert"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="弹出提醒对话框"/><TextViewandroid:id="@+id/tv_alert"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="20sp"/></LinearLayout>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-85spDjMS-1679196459979)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230315165728253.png)]

9.2 日期对话框DataPickerDialog

待攻克…


9.3 时间对话框 TimePickerDialog

待攻克…

案例:找回密码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".loginMainActivity"><RadioGroupandroid:id="@+id/rg_login"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><RadioButtonandroid:id="@+id/rd_password"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:checked="true"android:text="密码登录"android:textSize="17sp" /><RadioButtonandroid:id="@+id/rd_verifycode"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:text="验证码登录"android:textSize="17sp" /></RadioGroup><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid:layout_width="wrap_content"android:layout_height="45dp"android:gravity="center"android:text="手机号码"android:textColor="@color/black"android:textSize="17sp" /><EditTextandroid:id="@+id/et_phone"android:layout_width="0dp"android:layout_height="match_parent"android:layout_marginTop="5dp"android:layout_marginBottom="5dp"android:layout_weight="1"android:background="@drawable/editext_selector"android:hint="请输入手机号码"android:inputType="number"android:maxLength="11"android:paddingStart="5dp"android:textColor="@color/black"android:textColorHint="@color/purple_200"android:textSize="17sp" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="45dp"android:orientation="horizontal"><TextViewandroid:id="@+id/tv_password"android:layout_width="wrap_content"android:layout_height="match_parent"android:gravity="center"android:text="@string/Login_password"android:textColor="@color/black"android:textSize="17sp" /><RelativeLayoutandroid:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"><EditTextandroid:id="@+id/et_password"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginBottom="5dp"android:layout_marginTop="5dp"android:background="@drawable/editext_selector"android:hint="@string/input_password"android:inputType="numberPassword"android:maxLength="6"android:paddingStart="5dp"android:textColor="@color/black"android:textColorHint="@color/purple_200"android:textSize="17sp" /><Buttonandroid:id="@+id/btn_forget"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_alignParentEnd="true"android:text="@string/forget_password"android:textSize="17sp"/></RelativeLayout></LinearLayout><CheckBoxandroid:id="@+id/ck_remember"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="记住密码"android:textColor="@color/black"android:textSize="15sp"/><Buttonandroid:id="@+id/btn_login"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="17sp"android:text="登录"/></LinearLayout>

找回页面没有学

十. 数据存储

共享参数的用法

  • SharedPreference 是Android的一个轻量级存储工具,采用的存储结构是Key-Value的键值对方式。
  • 共享参数的存储介质是符合XML规范的配置文件。保存路径是: /data/data/应用包名/shared_prefs/文件名.xml

共享参数主要是用于如下场合:

  • 简单且鼓励的数据。弱势复杂且相互间有关的数据,则要保存在数据库中。
  • 文本形式的数据。若是二进制数据,则要保存在文件。
  • 需要持久化存储的数据。在App退出后再次启动时,之前保存的数据依然有效。

实际开发中,共享参数经常存储的数据有App的个性化配置信息、用户使用App的行为信息、临时需要保存的片段信息等。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dnroIcwQ-1679196459980)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230316210630830.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MX2mFzIY-1679196459980)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230316210606222.png)]

读取内容:

package com.example.chapter06;import androidx.appcompat.app.AppCompatActivity;import android.content.Context;
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.TextView;public class ShareWriteActivity extends AppCompatActivity implements View.OnClickListener {private EditText et_name;private EditText et_age;private EditText et_height;private EditText et_weight;private CheckBox cb_marry;private SharedPreferences preferences;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_share_write);et_name = findViewById(R.id.et_name);et_age = findViewById(R.id.et_age);et_height = findViewById(R.id.et_height);et_weight = findViewById(R.id.et_weight);cb_marry = findViewById(R.id.cb_marry);Button btn_save = findViewById(R.id.btn_save);btn_save.setOnClickListener(this);// 共享  第一个参数是名字(自己起) 第二个参数是模式preferences = getSharedPreferences("config", Context.MODE_PRIVATE);// 下次打开的时候重新读取出来reload();}private void reload() {// getString 第一个参数是 key 第二个参数是默认值,当获取不到值时就用默认值代替 可以写nullString name = preferences.getString("name","");if(name!=""){et_name.setText(name);}int age = preferences.getInt("age",0);if(age!=0){et_age.setText(String.valueOf(age)); // 要转换一下,否则编辑的实收会去string.xml文件中去找age}float height = preferences.getFloat("height",0f);if(height!=0f){et_height.setText(String.valueOf(height));}float weight = preferences.getFloat("weight",0f);if(weight!=0f){et_weight.setText(String.valueOf(weight));}boolean married = preferences.getBoolean("married", false);cb_marry.setChecked(married);}@Overridepublic void onClick(View view) {String name = et_name.getText().toString();String age = et_age.getText().toString();String height = et_height.getText().toString();String weight = et_weight.getText().toString();// 想要用 首先获得编辑器SharedPreferences.Editor editor = preferences.edit();editor.putString("name", name);editor.putInt("age", Integer.parseInt(age));editor.putFloat("height", Float.parseFloat(height));editor.putFloat("weight",Float.parseFloat(weight));// checkBox 返回的是Boolean类型editor.putBoolean("married", cb_marry.isChecked());// 提交要保存的信息editor.commit();}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FXpOJWoh-1679196459980)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230316211720826.png)]

案例:记住密码

十一. 数据库SQLite

**注意:**值支持增加字段,不支持修改字段,也不支持删除字段。一次只能添加一个。

ALTER TABLE tablename ADD COLUMN columnname VARCHAR;

数据库操作语言

  • 与Mysql类似

11.1 数据库管理器SQLiteDatabase:

  • 管理类,用于数据库层面的操作
  • openDatabase:打开指定路径的数据库。
  • isOpen:判断数据库是否己打开。
  • close:关闭数据库。
  • getVersion:获取数据库的版本号
  • setVersion:设置数据库的版本号
  • 事务类,用于事务层面的操作
    • beginTransaction:开始事务。
    • setTransactionsuccessful:设置事务的成功标志。
    • endTransaction:结束事务。执行本方法时,系统会判断之前是否调用了
    • setTransactionSuccessful方法,如果之前己调用该方法就提交事务,如果没有调用该方法就回滚事务。
  • 数据处理类,用于数据表层面的操作
    • execsQL:执行拼接好的SQL控制语句。—股用于建表、州表、变更表结构。
    • delete:删除符合条件的记录。
    • update:更新符合条件的记录信息
    • insert:插入一条记录。
    • query:执行查询操作,并返口结果集的游标。
    • rawQuery:执行拼接好的SQL查询语句,并返回结果集的游标。

在实际开发中比较经常用到的是查询语句,建议先写好查询操作的select语句,再调用rawQuery方法执行查询语向。

创建删除数据库:

package com.example.chapter06;import androidx.appcompat.app.AppCompatActivity;import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;public class DatabaseActivity extends AppCompatActivity implements View.OnClickListener {private TextView tv_database;private String mDatabaseName;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_database);Button btn_create_database = findViewById(R.id.btn_create_database);Button btn_delete_database = findViewById(R.id.btn_delete_database);tv_database = findViewById(R.id.tv_database);// 实现事件监听btn_create_database.setOnClickListener(this);btn_delete_database.setOnClickListener(this);// getFilesDir 获得 文件路径在data/data/包名/files目录 目前没有// 点击创建按钮的时候会创建这个文件mDatabaseName = getFilesDir() + "/test.db";}@Overridepublic void onClick(View view) {String desc = null;switch (view.getId()) {// 如果存在数据库就打开,不存在就创建case R.id.btn_create_database:SQLiteDatabase db = openOrCreateDatabase(mDatabaseName, Context.MODE_PRIVATE, null);desc = String.format("数据库%s创建%s", db.getPath(), (db != null) ? "SUCCESS": "FAIL");tv_database.setText(desc);break;// 删除数据库case R.id.btn_delete_database:boolean result = deleteDatabase(mDatabaseName);desc = String.format("数据库%s删除%s", mDatabaseName, result ? "SUCCESS": "FAIL");tv_database.setText(desc);break;}}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fhpIWEJg-1679196459981)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230317193414030.png)]

11.2 数据库帮助器SQLiteOpenHelper

由于SQLiteDatabase存在局限性,一不小心就会重复打开数据库,处理数据库的升级也不方便;因此Android提供了数据库帮助器SQLiteOpenHelper,帮助开发者合理使用SQLite。

SQLiteOpenHelper的具体使用步骤如下:

  • 步骤一,新建一个继承自SQLiteOpenHelper的数据库操作类,按提示重写onCreate和onUpgrade两个方法。其中,onCreate方法只在第一次打开数据库时执行,在此可以创建表结构;而onUpgrade方法在数据库版本升高时执行,在此可以根据新旧版本号变更表结构。
  • 步骤二,为保证数据库安全使用,需要封装几个必要方法,包括获取单例对象、打开数据库连接、关闭数据库连接,说明如下:
    • 获取单例对象:确保在App运行过程中数据库只会打开一次,避免重复打开引起错误。
    • 打开数据库连接:SQLite有锁机制,即读锁和写锁的处理;故而数据库连接也分两种,读连接可调用getReadableDatabase方法获得,写连接可调用getWritableDatabase获得。
    • 关闭数据库连接:数据库操作完毕,调用数据库实例的close方法关闭连接。
  • 步骤三, 提供对表记录增加、删除、修改、查询的操作方法。能被SQLite直接使用的数据结构是ContentValues类,它类似于映射Map,也提供了put和get方法存取键值对。
    • 区别之处在于:ContentValues的键只能是字符串,不能是其他类型。ContentValues主要用于增加记录和更新记录,对应数据库的insert和update方法。
    • 记录的查询操作用到了游标类Cursor,调用query和rawQuery方法返回的都是Cursor对象,若要获取全部的查询结果,则需根据游标的指示一条一条遍历结果集合。Cursor的常用方法可分为3类,说明如下:

案例:记住密码优化:

十二. 存储卡读写

12.1 外部存储的私有空间

获取外部存储私有空间

// 外部存储私有空间
directory = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString();
// 代码示例
package com.example.chapter06;import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;import androidx.appcompat.app.AppCompatActivity;import com.example.chapter06.util.FileUtil;
import com.example.chapter06.util.ToastUtil;import java.io.File;
import java.io.IOException;public class FileWriteActivity extends AppCompatActivity implements View.OnClickListener {private EditText et_name;private EditText et_age;private EditText et_height;private EditText et_weight;private CheckBox cb_marry;private SharedPreferences preferences;private String path = null;private TextView tv_txt;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_file_write);et_name = findViewById(R.id.et_name);et_age = findViewById(R.id.et_age);et_height = findViewById(R.id.et_height);et_weight = findViewById(R.id.et_weight);cb_marry = findViewById(R.id.cb_marry);tv_txt = findViewById(R.id.tv_txt);findViewById(R.id.btn_save).setOnClickListener(this);findViewById(R.id.btn_read).setOnClickListener(this);}@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.btn_save:String name = et_name.getText().toString();String age = et_age.getText().toString();String height = et_height.getText().toString();String weight = et_weight.getText().toString();StringBuilder builder = new StringBuilder();builder.append("姓名:").append(name);builder.append("\n年龄:").append(age);builder.append("\n身高:").append(height);builder.append("\n体重:").append(weight);builder.append("\n婚否:").append(cb_marry.isChecked() ? "是" : "否");String directory = null;String fileName = System.currentTimeMillis() + ".txt"; // 文件名用当前时间加上.txt// 外部存储空间directory = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString();path = directory + File.separator + fileName;  // File.separator相当于 '/'Log.d("lun",path); // 打印日志,输出path路径 方便查看try {FileUtil.saveText(path, builder.toString());ToastUtil.show(this,"Save Success!");} catch (IOException e) {throw new RuntimeException(e);}break;case R.id.btn_read:try {String txt = FileUtil.openFile(path); // 获取字符串tv_txt.setText(txt);} catch (IOException e) {throw new RuntimeException(e);}break;}}
}

工具类 FileUtil 用来写和读文件

package com.example.chapter06.util;import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;public class FileUtil {// 把字符串保存到指定路径文本文件public static void saveText(String path, String txt) throws IOException {BufferedWriter os = null;try {os = new BufferedWriter(new FileWriter(path));os.write(txt);} catch (IOException e) {e.printStackTrace();} finally {if (os != null) {os.close();}}}// 从指定路径的文本文件读取内容public static String openFile(String path) throws IOException {BufferedReader is = null;StringBuilder builder = new StringBuilder();try {is = new BufferedReader(new FileReader(path));String line = null;while ((line = is.readLine()) != null) {builder.append(line);}} catch (FileNotFoundException e) {e.printStackTrace();} finally {if (is != null) {is.close();}}return builder.toString();}
}

由于权限问题,无法查看这个文件,但是确实已经写入文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gYQkc9DO-1679196459981)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230318102746228.png)]

12.2 外部存储的公共空间

  • 再之前代码中重定义directory
// 外部存储的公共空间
directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString();
  • 设置应用权限:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yty4lsjI-1679196459982)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230318103836745.png)]

  • 结果:可以在 /storage/emulated/0/Download/1679106879845.txt 找到,并且删除app该文件也不会删除

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MqFZVE9O-1679196459982)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230318103956322.png)]

12.3 内部存储私有空间

// 内部存储私有空间
directory = getFilesDir().toString();

保存到 /data/user/0/com.example.chapter06/files/1679107374636.txt 目录,应用卸载后此文件也被卸载。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NL0O6d3w-1679196459982)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230318104522706.png)]

十三 在存储卡上读写图片文件

Android 的位图工具是 Bitmap,App读写Bitmap可以使用性能更好的BufferedOutpuStream和BufferedInputStream。

Android 还提供了BitmapFactory 工具用于读取各种来源的图片,相关方法如下:

  • decodeResource: 从资源文件中读取图片信息。
  • decodeFile:从指定路径的图片读取奥Bitmap对象。
  • decodeStream:从输入流中读取位图数据。

案例:

package com.example.chapter06;import androidx.appcompat.app.AppCompatActivity;import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.nsd.NsdManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
import android.widget.ImageView;import com.example.chapter06.util.FileUtil;
import com.example.chapter06.util.ToastUtil;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;public class ImageWriteActivity extends AppCompatActivity implements View.OnClickListener {private ImageView iv_image;private String path;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_image_write);findViewById(R.id.btn_read_image).setOnClickListener(this);findViewById(R.id.btn_save_image).setOnClickListener(this);iv_image = findViewById(R.id.iv_image);}@Overridepublic void onClick(View view) {switch (view.getId()){case R.id.btn_save_image:String fileName = System.currentTimeMillis() + ".jpeg";// 获取当前app的外部私有存储空间path = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + File.separatorChar+ fileName;Log.d("lun",path);// 从制定资源文件中获取位图对象Bitmap b1 = BitmapFactory.decodeResource(getResources(), R.drawable.girl1);// 把位图对象保存为图片文件try {FileUtil.saveImage(path,b1);ToastUtil.show(this, "Save Success!"); } catch (IOException e) {throw new RuntimeException(e);}break;case R.id.btn_read_image:try {Bitmap b2 = FileUtil.openImage(path);iv_image.setImageBitmap(b2);} catch (IOException e) {throw new RuntimeException(e);}break;}}
}

在java代码中读取图片还可以这样写

//也可以不实用工具类
Bitmap b2 = BitmapFactory.decodeFile(path);
iv_image.setImageBitmap(b2);
-----------------------------------------------------------------------------------------
// 直接调用setImageURI方法,指定图像视图的路径对象
iv_image.setImageURI(Uri.parse(path));

工具类存储与读取图片

/*** 把位图数据保存到指定路径的图片文件* Bitmap 提供了compress方法*/public static void saveImage(String path, Bitmap bitmap) throws IOException {FileOutputStream fos = null; // 文件输出流try{fos = new FileOutputStream(path); // 输出到path路径里去// 把位图数据压缩到文件输出流中bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);}catch (Exception e){throw new RuntimeException(e);}finally {if (fos != null) fos.close();}
}// 从指定路径读取位图数据
public static Bitmap openImage(String path) throws IOException {Bitmap bitmap = null;FileInputStream fis = null;try{fis = new FileInputStream(path);bitmap = BitmapFactory.decodeStream(fis);}catch (Exception e){e.printStackTrace();}finally {if(fis != null){fis.close();}}return bitmap;
}

十四 Application

14.1 Application的生命周期

ApplicationAndroid 的一大组件,在App运行过程中有且仅有一个 Application 贯穿整个生命周期

Application 在 mainActivity 创建之前就会创建

示例:新建一个名为 MyApplication 的java类

package com.example.chapter06;import android.app.Application;
import android.content.res.Configuration;
import android.util.Log;import androidx.annotation.NonNull;public class MyApplication extends Application {// 在APP启动的时候调用@Overridepublic void onCreate() {super.onCreate();Log.d("lun","onCreate");}// APP 终止时调用 在真实的产品中不会被调用,只在系统开发的时候可以调用@Overridepublic void onTerminate() {super.onTerminate();Log.d("lun","onTerminate");}// 在配置改变的时候调用,例如横屏变成竖屏@Overridepublic void onConfigurationChanged(@NonNull Configuration newConfig) {super.onConfigurationChanged(newConfig);Log.d("lun","onConfigurationChanged");}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BdLyOrfm-1679196459982)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230318115910785.png)]

14.2 利用Application 操作全局变量

全局的优势是其他代码都可以引用该变量,因此全局变量是共享数据和消息传递的好帮手。

适合在Application 中保存的全局变量主要有以下类型:

  • 会频繁读取的信息,如用户名,手机号。
  • 不方便有意图传递的消息,例如位图对象、非字符串类型的集合对象。
  • 容易因频繁分配内存而意外导致内存泄漏的对象,如handler等。

案例:

  • 新建一个 APPWriteActivity
package com.example.chapter06;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;public class AppWriteActivity extends AppCompatActivity implements View.OnClickListener {private EditText et_name;private EditText et_age;private EditText et_height;private EditText et_weight;private CheckBox cb_marry;private MyApplication app;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_app_write);et_name = findViewById(R.id.et_name);et_age = findViewById(R.id.et_age);et_height = findViewById(R.id.et_height);et_weight = findViewById(R.id.et_weight);cb_marry = findViewById(R.id.cb_marry);Button btn_save = findViewById(R.id.btn_save);btn_save.setOnClickListener(this);app = MyApplication.getInstance();reload(); //在创建主活动的时候就调用reload方法,把之前的诗句调取出来}private void reload() {String name = app.infoMap.get("name");if(name == null){return;} // 第一次运行时因为没有数据,所以拿不到,要判断一下,没有数据直接返回String age = app.infoMap.get("age");String height = app.infoMap.get("height");String weight = app.infoMap.get("weight");String marry = app.infoMap.get("marry");et_name.setText(name);et_age.setText(age);et_height.setText(height);et_weight.setText(weight);if(marry.equals("是")){cb_marry.setChecked(true);}else {cb_marry.setChecked(false);}}@Overridepublic void onClick(View view) {String name = et_name.getText().toString();String age = et_age.getText().toString();String height = et_height.getText().toString();String weight = et_weight.getText().toString();app.infoMap.put("name", name);app.infoMap.put("age", age);app.infoMap.put("height", height);app.infoMap.put("weight", weight);app.infoMap.put("marry", cb_marry.isChecked() ? "是":"否");}
}
package com.example.chapter06;import android.app.Application;
import android.content.res.Configuration;
import android.util.Log;import androidx.annotation.NonNull;import java.util.HashMap;public class MyApplication extends Application {private static MyApplication mApp;// 声明一个共欧诺个的信息映射对象,可当做全局变量使用public HashMap<String, String> infoMap = new HashMap<>();public static MyApplication getInstance() {return mApp;}// 在APP启动的时候调用@Overridepublic void onCreate() {super.onCreate();mApp = this;Log.d("lun", "onCreate");}// APP 终止时调用 在真实的产品中不会被调用,只在系统开发的时候可以调用@Overridepublic void onTerminate() {super.onTerminate();Log.d("lun", "onTerminate");}// 在配置改变的时候调用,例如横屏变成竖屏@Overridepublic void onConfigurationChanged(@NonNull Configuration newConfig) {super.onConfigurationChanged(newConfig);Log.d("lun", "onConfigurationChanged");}
}

一般数据不用静态变量保存,用Application保存全局变量


14.3 利用Room优化数据库操作

导入 Room:

//    添加Roomimplementation 'androidx.room:room-runtime:2.5.0'annotationProcessor 'androidx.room:room-compiler:2.5.0'

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LJeODQvC-1679196459983)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230318182147671.png)]

Room框架的编码步骤:

  • 编写 数据库表 对应的 实体类,该类添加“@Entity” 注解。
  • 编写 数据库表 对应的 持久化类,该类添加“@Dao” 注解。
  • 编写 数据库表 对应的 数据库类,该类从RoomDatabase派生而来,并添加“@Database” 注解。
  • 在自定义的 Application 类中生明数据库的唯一示例。
  • 在操作 数据库表 的地方 获取 表的持久化对象。

示例:

新建一个实体类 BookInfo

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AgtwpKrd-1679196459983)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230318201530382.png)]

package com.example.chapter06.entiy;import androidx.room.Entity;
import androidx.room.PrimaryKey;/*** 实体类BookInfo 对应数据库BookInfo表*/
@Entity
public class BookInfo {@PrimaryKey(autoGenerate = true)private int id;  // 主键 自动增长private String name;private String author;private String press;private Double price;public int getId() {return id;}public void setId(int 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 Double getPrice() {return price;}public void setPrice(Double price) { this.price = price; }@Overridepublic String toString() {return "BookInfo{" +"id=" + id +", name='" + name + '\'' +", author='" + author + '\'' +", press='" + press + '\'' +", price='" + price + '\'' +'}';}
}

再新建一个BookDao 持久化类(是一个接口,实现数据库的增删改查语句)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sgS4tAzb-1679196459989)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230318201911134.png)]

package com.example.chapter06.dao;import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;import com.example.chapter06.entiy.BookInfo;import java.util.List;@Dao
public interface BookDao {@Insert// ... 表示可以传多个参数void insert(BookInfo... book);@Deletevoid delete(BookInfo... book);// 删除所有@Query("delete from bookinfo")void deleteAll();@Updateint update(BookInfo... book);@Query("select * from bookinfo")List<BookInfo> queryAll();@Query("select * from BookInfo where name = :name order by id desc limit 1")BookInfo queryByName(String name);
}

新建DookDatabase数据库类,该类从RoomDatabase派生而来,并添加“@Database” 注解。(是抽象类)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G2wjZJNO-1679196459989)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230318201946134.png)]

在Activity中实现接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FstzjoJs-1679196459990)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230318202246470.png)]

package com.example.chapter06;import androidx.appcompat.app.AppCompatActivity;import android.icu.text.UnicodeSetSpanner;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;import com.example.chapter06.dao.BookDao;
import com.example.chapter06.database.UserDBHelper;
import com.example.chapter06.entiy.BookInfo;
import com.example.chapter06.util.ToastUtil;import java.util.List;public class RoomWriteActivity extends AppCompatActivity implements View.OnClickListener {private EditText et_name;private EditText et_author;private EditText et_press;private EditText et_price;private BookDao bookDao;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_room_write);et_name = findViewById(R.id.et_name);et_author = findViewById(R.id.et_author);et_press = findViewById(R.id.et_press);et_price = findViewById(R.id.et_price);findViewById(R.id.btn_select).setOnClickListener(this);findViewById(R.id.btn_delete).setOnClickListener(this);findViewById(R.id.btn_insert).setOnClickListener(this);findViewById(R.id.btn_update).setOnClickListener(this);// 构建一个DaobookDao = MyApplication.getInstance().getBookDB().bookDao();}@Overridepublic void onClick(View view) {// 获取输入的文本String name = et_name.getText().toString();String author = et_author.getText().toString();String press = et_press.getText().toString();String price = et_price.getText().toString();// 实现不同按钮的监听switch (view.getId()){case R.id.btn_insert:// 声明一个书籍信息对象BookInfo b1 = new BookInfo();b1.setName(name);b1.setAuthor(author);b1.setPress(press);b1.setPrice(Double.parseDouble(price));bookDao.insert(b1);ToastUtil.show(this, "Save Success!");break;case R.id.btn_select:List<BookInfo> list = bookDao.queryAll();for (BookInfo b : list) {Log.d("lun", b.toString());}break;case R.id.btn_update:BookInfo b2 = new BookInfo();// 更新首先要根据名字查询到已有记录BookInfo b3 = bookDao.queryByName(name);b2.setId(b3.getId()); // 根据记录id来更改b2.setName(name);b2.setAuthor(author);b2.setPress(press);b2.setPrice(Double.parseDouble(price));int update = bookDao.update(b2);if(update != 0){ToastUtil.show(this, "Update Success!");}else {ToastUtil.show(this, "Update Fail!");}break;case R.id.btn_delete:// 首先先根据名字查询,返回一个bookInfo对象String str = "asd";BookInfo bookInfo = bookDao.queryByName(str);// 通过获取到的对象删除bookDao.delete(bookInfo);ToastUtil.show(this, "Delete Success!");break;}}
}
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_room_write);et_name = findViewById(R.id.et_name);et_author = findViewById(R.id.et_author);et_press = findViewById(R.id.et_press);et_price = findViewById(R.id.et_price);findViewById(R.id.btn_select).setOnClickListener(this);findViewById(R.id.btn_delete).setOnClickListener(this);findViewById(R.id.btn_insert).setOnClickListener(this);findViewById(R.id.btn_update).setOnClickListener(this);// 构建一个DaobookDao = MyApplication.getInstance().getBookDB().bookDao();
}@Override
public void onClick(View view) {// 获取输入的文本String name = et_name.getText().toString();String author = et_author.getText().toString();String press = et_press.getText().toString();String price = et_price.getText().toString();// 实现不同按钮的监听switch (view.getId()){case R.id.btn_insert:// 声明一个书籍信息对象BookInfo b1 = new BookInfo();b1.setName(name);b1.setAuthor(author);b1.setPress(press);b1.setPrice(Double.parseDouble(price));bookDao.insert(b1);ToastUtil.show(this, "Save Success!");break;case R.id.btn_select:List<BookInfo> list = bookDao.queryAll();for (BookInfo b : list) {Log.d("lun", b.toString());}break;case R.id.btn_update:BookInfo b2 = new BookInfo();// 更新首先要根据名字查询到已有记录BookInfo b3 = bookDao.queryByName(name);b2.setId(b3.getId()); // 根据记录id来更改b2.setName(name);b2.setAuthor(author);b2.setPress(press);b2.setPrice(Double.parseDouble(price));int update = bookDao.update(b2);if(update != 0){ToastUtil.show(this, "Update Success!");}else {ToastUtil.show(this, "Update Fail!");}break;case R.id.btn_delete:// 首先先根据名字查询,返回一个bookInfo对象String str = "asd";BookInfo bookInfo = bookDao.queryByName(str);// 通过获取到的对象删除bookDao.delete(bookInfo);ToastUtil.show(this, "Delete Success!");break;}
}

}

Android 开发 入门相关推荐

  1. 《Android 开发入门与实战(第二版)》——6.6节配置改变

    本节书摘来自异步社区<Android 开发入门与实战(第二版)>一书中的第6章,第6.6节配置改变,作者eoe移动开发者社区 组编 , 姚尚朗 , 靳岩,更多章节内容可以访问云栖社区&qu ...

  2. android开发入门_Android开发入门

    android开发入门 Android is an open source, Linux-based mobile operating system. Android was developed by ...

  3. 《Android 开发入门》我为什么要在Android找工作越来越难的时候开始学习它

    近期一方面是所在的公司招聘Java开发人员很难招到合适的,投简历的人很少:而另一方面,经常听身边的人说Android.iOS方面找工作不好找,特别是没什么经验的,经验比较少的!说是不好找,但在我家所在 ...

  4. Android开发入门 - 简易开心消消乐界面设计

    Android开发入门 - 简易开心消消乐界面设计 第一步,点击File->NEW->new module,进入以下界面,选择第一个,即运行在手机和平板电脑上.点击next. 第二步,在第 ...

  5. Google Android开发入门与实战

    Google Android开发入门与实战 [作 者]靳岩;姚尚朗 [同作者作品] [作译者介绍]  [出 版 社] 人民邮电出版社     [书 号] 9787115209306  [上架时间] 2 ...

  6. 《Android 开发入门与实战(第二版)》——导读

    本节书摘来自异步社区<Android 开发入门与实战(第二版)>一书中的目录,作者eoe移动开发者社区 组编 , 姚尚朗 , 靳岩,更多章节内容可以访问云栖社区"异步社区&quo ...

  7. 《Google Android 开发入门与实战》

    <Google Android 开发入门与实战>(含1张DVD光盘) 市 场 价:¥55 书 号:9787115209306 出版日期:2009 年6月 开 本:16开 页码:340 [内 ...

  8. Android开发入门与实战之Android应用安装卸载

    当一个Android开发者完整的开发完毕一个程序应用软件结束后要进行软件测试,这就是软件测试员的来历,那么在这之前,要进行Android开发应用的安装与卸载. Android开发入门与实战之Andro ...

  9. 《Android 开发入门与实战(第二版)》——6.10节本章小结

    本节书摘来自异步社区<Android 开发入门与实战(第二版)>一书中的第6章,第6.10节本章小结,作者eoe移动开发者社区 组编 , 姚尚朗 , 靳岩,更多章节内容可以访问云栖社区&q ...

  10. 《Google Android开发入门与实战随书视频》

    1.[eoeAndroid特刊]第一期 Andriod 1.5 SDK简介   http://download.csdn.net/source/2399809 2.[eoeAndroid特刊]第二期  ...

最新文章

  1. 在Ubuntu上编译opencv 2.4.13源码支持android平台操作步骤
  2. pyodbc psutil wmi paramiko
  3. laravel mysql 视图_视图入门:Laravel 支持的视图格式以及在路由中的基本使用
  4. react native ScrollView
  5. 统一对比学习框架?没错它来了。
  6. 【shell】通过shell编写ping包及arp的监控并发送短信
  7. 每天一点正则表达式积累(六)
  8. listary文件查找程序下载和使用
  9. 数据库变为可疑_SQL数据库可疑解决方法
  10. 车道线检测预处理(1)------ 融合白线黄线+高斯
  11. Ubutntu18.04 root用户下谷歌浏览器打不开
  12. 作为一本书,我是如何把别的Java系列卷死的!
  13. selenium webdriver 使用webDriver点击ENTER建的两种方法
  14. Python OpenCV crosscheck交叉特征点出现错误解决办法
  15. 什么是5G advanced
  16. [数据结构] UVa1471 Defense Lines 防线
  17. 中兴通讯加入星策开源社区 携手推动企业智能化转型建设
  18. PV操作详解(附详细例题解析和总结)
  19. ad9516-4时钟芯片配置注意事项
  20. 嗯,我们出了一套做爬虫必备的 JS 逆向课程

热门文章

  1. 什么是json对象?
  2. 简练网软考知识点整理-项目选择和优先级排列方法
  3. 简练网软考知识点整理-项目整体绩效测量基准
  4. 3-2存储系统-主存与CPU的连接外部存储器
  5. matplotlib中cmap与color参数的设置
  6. HTML5期末大作业:旅游网页设计与实现——旅游风景区网站HTML+CSS+JavaScript 景点静态网页设计 学生DW静态网页设计...
  7. PyCharm激活记录
  8. 设计一个分数类java_设计一个学生类,学生类中应包括学号,姓名,语文成绩,数学成绩,英语成绩,同时还要提供两个方法,一个方...
  9. 【黑客免杀攻防】读书笔记1 - 初级免杀基础理论(反病毒软件特征码提取介绍、免杀原理、壳)...
  10. Gym - 100203A Ariel 暴力+位运算