Android 开发学习笔记 环境搭建 本文档使用集成开发环境IDEA学习
官方下载:https://developer.android.com/?hl=zh-cn
创建项目 1.点击新建项目(new project)选择需要的模板工程文件
2.下一步后更改工程文件相关说明
Name(名字)
Package name (包名)
Save location (保存位置)
Langeuage (项目语言) 本项目使用的是JAVA语言
Minimum SDK (最低支持系统) tip:意味着你当前的开发最低支持你选择的系统版本,比如Android 7,这样低于这个系统版本的手机将无法使用此APK
Build configuration language (构建配置语言) tip:推荐默认
等待下载 创建完成项目后,需要等待相关文件的下载比如gradle(构建工具)的下载,如果遇到下载慢的情况可以通过修改gradle来源来解决
① 修改Gradle来源 在项目的gradle/wrapper/gradle-wrapper.properties
这个文件中可以看到配置:
1 2 3 4 5 distributionBase=GRADLE\_USER\_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE\_USER\_HOME zipStorePath=wrapper/dists distributionUrl=http\://services.gradle.org/distributions/gradle-6.5-all.zip
其中distributionUrl
指定了Gradle发行版的地址,而这个http://services.gradle.org/distributions/gradle-6.5-all.zip
访问起来是很慢的;
所以我们修改这个配置即可;
可以将其修改为国内的一个源,如:
1 distributionUrl=https\://code.aliyun.com/kar/gradle-all-zip/raw/master/gradle-6.5-all.zip
在这里提供了Gradle 6.x的阿里云地址:
但其实在2019年3月,Gradle开启了在中国地区的CDN,下载Gradle的distribution已经不需要翻墙!
修改gradle文件夹下面的gradle-wrapper.properties中的http://services.gradle.org
为:
http://downloads.gradle-dn.com
即可!
但是经过我实测,http://downloads.gradle-dn.com
的下载速度还是不太行……,所以还是推荐使用阿里云的CDN的方法!
② 手动下载Gradle 在项目的gradle/wrapper/gradle-wrapper.properties
这个文件中可以看到配置:
1 2 3 4 5 distributionBase=GRADLE\_USER\_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE\_USER\_HOME zipStorePath=wrapper/dists distributionUrl=http\://services.gradle.org/distributions/gradle-6.5-all.zip
然后找到 gradle-6.5-all.zip 这就是你要下载的版本,去网上手动下载一个;
然后找到 $User/.gradle/wrapper/dists
中创建一个对应版本的文件夹以及下面的一个SHA256签名的目录,直接将zip拷贝进去(无需解压缩);
关闭项目,重新打开即可;
强烈不推荐手动下载Gradle;
你甚至都可以将上述配置中的distributionUrl
修改为网上的一个地址,重新打开项目,这时项目会自动从这个地址下载Gradle,而避免手动下载、复制压缩包;
③ 使用本地Gradle 如果本地存在了Gradle,可以使用本地的Gradle;
在Android Studio
设置,找到Gradle
,指定本地Gradle位置;
但是这样就无法实现Gradle Wrapper支持多版本构建的优势了!
其他:Gradle依赖镜像源 Gradle下载依赖较慢的问题,基本上都已经被讲烂了,解决方法就是:换镜像源!
把maven库地址改成阿里云的地址,找到根目录下的build.gradle
,进行如下修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 buildscript { repositories { + maven{url 'http://maven.aliyun.com/nexus/content/groups/public/'} + maven{url "https://jitpack.io" } google() - // jcenter() - // mavenCentral() } } allprojects { repositories { + maven{url 'http://maven.aliyun.com/nexus/content/groups/public/'} google() - // jcenter() } }
项目结构 了解项目结构可以让我们更容易学习
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 MyApplication .gradle: Gradle编译系统,版本由wrapper指定(无须手动修改) .idea: IDE所需要的文件(无须手动修改) app: 开发项目的所有代码和资源文件 build: app模块编译输出的文件 libs: 放置引用的类库文件 src: 放置应用的主要文件目录 AndroidTest: 单元测试目录 main: 主要的项目目录和代码 java: 项目的源代码 res: 项目的资源 drawable: 存放各种位图文件(.png,.jpg,.9png,.gif等)和drawable类型的XML文件 drawable-v24: 存放自定义Drawables类(Android API 24开始,可在XML中使用) layout: 存放布局文件 menu: 存放菜单文件 mipmap-hdpi: 存放高分辨率图片资源 mipmap-mdpi: 存放中等分辨率图片资源 mipmap-xdpi: 存放超高分辨率图片资源 mipmap-xxdpi: 存放超超高分辨率图片资源 mipmap-xxxdpi: 存放超超超高分辨率图片资源 raw: 存放各种原生资源(音频,视频,一些XML文件等) values: 存放各种配置资源(颜色,尺寸,样式,字符串等) xml AndroidManifest.xml: 项目的清单文件(名称、版本、SDK、权限等配置信息) test .gitignore: 忽略的文件或者目录 app.iml: app模块的配置文件 build.gradle: app模块的gradle编译文件 proguard-rules.pro: app模块的代码混淆配置文件 gradle: wrapper的jar和配置文件所在的位置 .gitattributes: 用于设置文件的对比方式 .gitignore: 忽略的文件或者目录 build.gradle: 项目的gradle编译文件 gradle.properties: gradle相关的全局属性设置 没有会下载,有会自动配置 gradlew: 编译脚本,可以在命令行执行打包 gradlew.bat: windows下的gradle wrapper可执行文件 MyApplication.iml: 保存该模块的相关信息 README.md: 文本编辑器,记录一些相关信息 local.properties: 配置SDK/NDK所在的路径 setting.gradle: 设置相关的gradle脚本 External Libraries: 项目依赖的库,编译时自动下载
APP 1 2 3 4 5 manifests AndroidManifest.xml: 项目的清单文件(名称、版本、SDK、权限等配置信息) java: 项目的源代码 src: 放置应用的主要文件目录(子目录可参考Project的介绍) Gradle Scripts: gradle编译相关的脚本(具体文件的说明可参考Project的介绍)
开发前准备 在正式开发前,我们需要先配置好虚拟设备,方便我们开发时调试,IDEA提供两种调试方法。
创建虚拟设备 IDEA提供两种方式,分别是物理连接和虚拟连接,推荐使用第二种方法,更加方便。
1.使用ADB连接手机 需要准备一台手机,打开手机的安卓调试ADB,然后连接电脑。
2.创建一个虚拟设备 创建一个虚拟设备,通过打开右侧菜单栏的 Device Manager (设备管理),点击加号创建一个新的虚拟设备。
点击后进入创建页面,左栏是提供的个各种不同的设备选择,这里选择手机(Phone)。
然后在右侧可以看到不同尺寸和分辨率的手机,选择合适的就可以。
下一步后,就是选择不同的手机系统了,官方提供了多种安卓版本,选择自己需要的就好,在Target一栏中可以看到不同的安卓版本。
点击Release Name一栏对应的系统名称旁边的下载按钮,同意协议后,开始自动下载系统SDK到你的项目路径中,下载完成后,继续点击下一步直到完成安装即可,就此已经成功创建好了对应的虚拟设备。
启动虚拟设备 运行虚拟设备需要找到右栏中的 Device Manager (设备管理),看到你创建的设备后,点击运行即可。
运行后可以在 Running Devices (运行中设备) 里看到。
开发 TextView 使用TextView可以在容器中创建一个文本,通过设置不同的属性改变文本的样式,包括颜色,尺寸,排版等等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?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:id ="@+id/main" android:layout \_width ="match\_parent" android:layout \_height ="match\_parent" tools:context =".MainActivity" ><TextView android:id ="@+id/tv\_one" android:text ="hello world" android:textColor ="@color/black" android:textStyle ="italic" android:background ="#FFFF0000" android:gravity ="center" android:layout \_width ="match\_parent" android:layout \_height ="match\_parent" ></TextView > </LinearLayout >
在上述代码中,有一些属性的值是@开头,这是使用了规定好的样式,在正式开发中,不会将属性值直接写在代码中,而是在values文件夹里定义好不同的String,在组件里引用即可。
比如
1 android:id="@+id/tv\_one"
实际上是为了让MainActivity.java里的findViewById方法使用
1 2 3 setContentView(R.layout.activity\_main); TextView tv\_one = findViewById(R.id.tv\_one); tv\_one.setText("Hello Lain" );
通过ID寻找到组件后,使用Set方法改变组件的其他属性值,这里将TextView的Text修改为Hello Lain,有趣的是,我已经在xml的组件里也定义了Text的属性值为 Hello World
1 android:text="hello world"
这种情况会优先Java代码,所以Hello World被修改为Hello Lain。
另一个情况是使用已经定义好的属性值,比如
1 android:textColor="@color/black"
实际上这个值被存储在app\src\main\res\values\colors.xml里,如下
1 2 3 4 5 <?xml version="1.0" encoding="utf-8" ?> <resources > <color name ="black" > #FF000000</color > <color name ="white" > #FFFFFFFF</color > </resources >
在这个目录下,还有其他的xml文件,对应着不同的使用场景,默认有三个分别是,colors.xml负责定义好的颜色样式,strings.xml负责项目中的所有显示文字,themes.xml负责主题。
比如我希望TextView的Text属性值为Hello Lain,我可以直接在strings.xml里添加一个值,这样每次使用相同的值,我直接调用这里的名字即可。
1 2 3 4 <resources > <string name ="app\_name" > financing</string > <string name ="lain" > Hello Lain</string > </resources >
调用时
1 android:text="@string/lain"
属性
属性 (Attribute)
描述 (Description)
text
设置文本内容 (Sets the text content)
textColor
设置文本颜色 (Sets the text color)
textSize
设置文本大小 (Sets the text size)
textStyle
设置文本样式,如粗体、斜体 (Sets text style such as bold, italic)
gravity
设置文本的对齐方式 (Sets the text alignment)
fontFamily
设置文本字体 (Sets the text font family)
padding
设置文本的内边距 (Sets the text padding)
background
设置文本的背景 (Sets the text background)
maxLines
设置最大行数 (Sets the maximum number of lines)
singleLine
设置是否单行显示 (Sets whether to display in a single line)
ellipsize
设置超出范围时的省略方式 (Sets the ellipsis mode for overflow)
阴影
属性 (Attribute)
描述 (Description)
shadowColor
设置阴影的颜色 (Sets the color of the shadow)
shadowDx
设置阴影在水平方向的偏移量 (Sets the horizontal offset of the shadow)
shadowDy
设置阴影在垂直方向的偏移量 (Sets the vertical offset of the shadow)
shadowRadius
设置阴影的半径 (Sets the radius of the shadow)
跑马灯 想要实现跑马灯需要设置5个属性分别为:
android:singleLine:内容单行显示
android:focusable:是否可以获取焦点
android:focusablelnTouchMode:用于控制视图在触摸模式下是否可以聚焦
android:ellipsize:在哪里省略文本
android:marqueeRepeatLimit:字幕动画重复的次数
首先修改文字内容,让其无法一行显示完全:
1 2 3 4 <resources > <string name ="app\_name" > financing</string > <string name ="lain" > Hello Lain,Hello Lain,Hello Lain,Hello Lain,Hello Lain,Hello Lain,Hello Lain,Hello Lain,Hello Lain</string > </resources >
通过添加这五个属性实现文字跑马灯效果
1 2 3 4 5 6 android:singleLine="true" android:focusable="true" android:focusableInTouchMode="true" android:ellipsize="marquee" android:marqueeRepeatLimit="marquee\_forever" android:clickable="true"
除了上述五个属性外,还需要添加一个获取点击焦点的属性,这样当点击后返回为true,开始循环跑马灯。
这样实现的跑马灯效果必须点击后才能使用,这样并不够高效,所以接下来通过自定义一个组件来实现无需点击自动获取焦点的功能。
通过在com.example里创建一个类,并且继承原组件,此时需要添加构造函数后才能正常使用,最后在重写判断焦点的方法返回为true,这样不论点击,都会循环重复。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.example.financing;import android.content.Context;import android.util.AttributeSet;import android.widget.TextView;import androidx.annotation.Nullable;public class TextViewLain extends TextView {public TextViewLain (Context context) {super (context);} public TextViewLain (Context context, @Nullable AttributeSet attrs) {super (context, attrs);} public TextViewLain (Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super (context, attrs, defStyleAttr);} @Override public boolean isFocused () {return super .isFocused();} }
这段代码是Java中的一个方法重写(override)。它重写了一个名为isFocused()
的方法,该方法原本是从父类(superclass)继承而来的。在重写中,它调用了super.isFocused()
,意味着它调用了父类中的isFocused()
方法。这个方法的作用是判断当前对象是否具有焦点(focus)。
更改返回值:
1 2 3 4 5 @Override public boolean isFocused () {return true ;}
由于我们重写了TextView,在xml中使用它也应该调用新的类,所以变成了这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <com.example.financing.TextViewLain android:id ="@+id/tv\_one" android:text ="@string/lain" android:textColor ="@color/black" android:textStyle ="italic" android:background ="#FFFF0000" android:gravity ="center" android:singleLine ="true" android:focusable ="true" android:focusableInTouchMode ="true" android:ellipsize ="marquee" android:marqueeRepeatLimit ="marquee\_forever" android:layout \_width ="match\_parent" android:layout \_height ="match\_parent" ></com.example.financing.TextViewLain >
再次运行,会发现自动实现了跑马灯效果。
Button类继承于TextView
基本属性
属性 (Attribute)
描述 (Description)
android:text
设置按钮显示的文本 (Sets the text displayed on the button)
android:id
按钮的唯一标识符 (Unique identifier for the button)
android:onClick
按钮点击时触发的方法 (Method to be invoked when the button is clicked)
android:background
设置按钮的背景 (Sets the background for the button) tip:因为更新的原因,使用这个属性需要将values\themes.xml里改为DarkActionBar.Bridge才可以使用
android:layout_width
设置按钮的宽度 (Sets the width of the button)
android:layout_height
设置按钮的高度 (Sets the height of the button)
android:enabled
设置按钮是否可用 (Sets whether the button is enabled)
android:visibility
设置按钮的可见性 (Sets the visibility of the button)
位置属性
android:layout_gravity
按钮的布局位置。
android:gravity
按钮内文本的对齐方式。
android:textSize
按钮文本的字体大小。
android:textColor
按钮文本的颜色。
android:padding
按钮内边距。
android:layout_margin
按钮外边距。
android:layout_alignParentLeft
按钮是否与父容器的左边对齐。
android:layout_alignParentRight
按钮是否与父容器的右边对齐。
android:layout_alignParentTop
按钮是否与父容器的顶部对齐。
android:layout_alignParentBottom
按钮是否与父容器的底部对齐。
android:layout_alignParentStart
按钮是否与父容器的开始位置对齐。
android:layout_alignParentEnd
按钮是否与父容器的结束位置对齐。
android:layout_centerHorizontal
按钮是否水平居中。
android:layout_centerVertical
按钮是否垂直居中。
android:layout_toLeftOf
按钮位于某个视图的左侧。
android:layout_toRightOf
按钮位于某个视图的右侧。
android:layout_above
按钮位于某个视图的上方。
android:layout_below
按钮位于某个视图的下方。
android:layout_alignLeft
按钮是否与另一个视图的左边对齐。
android:layout_alignRight
按钮是否与另一个视图的右边对齐。
android:layout_alignTop
按钮是否与另一个视图的顶部对齐。
android:layout_alignBottom
按钮是否与另一个视图的底部对齐。
点击改变背景颜色 如果要实现点击改变按钮背景颜色的效果,和html中使用判断是否点击的属性改变值不同,需要根据规则在res里编写具体规则,在xml中引用规则即可。
1 2 3 4 5 <Button android:layout \_width ="100dp" android:layout \_height ="100dp" android:backgroundTint ="@color/btn\_color" android:text ="hello" />
创建color文件夹和具体xml,然后编写代码:
来自:res/color/btn_color.xml
1 2 3 4 5 <?xml version="1.0" encoding="utf-8" ?> <selector xmlns:android ="http://schemas.android.com/apk/res/android" > <item android:color ="@color/black" android:state \_pressed ="true" /> <item android:color ="#EFEFEF" /> </selector >
判断点击后为true,改变颜色为balck,否则默认情况为白色#EFEFEF
举一反三,其他情况也是使用同样的方法进行引用和判断。
点击事件 当你在Android Studio中创建一个按钮(Button)时,你通常会想要添加一个点击事件,以便在用户点击按钮时执行特定的操作。以下是几种常见的按钮点击事件及其使用方法:
1. 使用匿名内部类 1 2 3 4 5 6 button.setOnClickListener(new View .OnClickListener() { @Override public void onClick (View v) {} });
2. 使用Lambda表达式(适用于Java 8及以上) 1 2 3 button.setOnClickListener(v -> { });
3. 在 XML 中添加 onClick 属性(不推荐使用,仅适用于单一事件) 在布局文件中添加 onClick 属性:
1 2 3 4 5 6 <Button android:id ="@+id/button" android:layout \_width ="wrap\_content" android:layout \_height ="wrap\_content" android:text ="Click me!" android:onClick ="onButtonClick" />
然后在相应的活动(Activity)中添加一个公共方法:
1 2 3 public void onButtonClick (View view) {}
这些是一些常见的按钮点击事件的使用方法。你可以根据自己的需要选择其中一种或多种来实现按钮的点击功能。
在 Android Studio 中,按钮可以响应多种点击事件以及触摸事件。以下是一些常见的按钮事件类型:
点击事件(onClick) 点击事件是用户单击按钮时触发的事件。当用户点击按钮时,执行预定义的操作。
长按事件(onLongClick) 长按事件是用户长时间按住按钮时触发的事件。通常用于触发需要长时间按住才执行的操作,例如弹出上下文菜单或启动拖放操作。
触摸事件(onTouch) 触摸事件是用户触摸按钮(包括按下、移动和抬起)时触发的事件。可以根据手指在按钮上的动作执行不同的操作,例如实现自定义的手势识别或按钮效果。
按下事件(onPress) 按下事件是用户按下按钮时触发的事件,通常在用户按下按钮但尚未释放时执行。与点击事件不同,按下事件不需要用户释放按钮即可触发。
释放事件(onRelease) 释放事件是用户释放按钮时触发的事件,与按下事件相对应。通常与按下事件结合使用,以执行需要在用户按下按钮后立即释放时执行的操作。
在我理解看来,如果官方自带的事件无法满足你的开发需求,可以自定义一个点击事件,用来实现更高客制化的需求。
例子: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Button btn = findViewById(R.id.btn\_text);btn.setOnClickListener(new View .OnClickListener() { @Override public void onClick (View v) {Log.e(TAG,"HELLO Click" ); } }); btn.setOnLongClickListener(new View .OnLongClickListener() { @Override public boolean onLongClick (View v) {return false ;} }); btn.setOnTouchListener(new View .OnTouchListener() { @Override public boolean onTouch (View v, MotionEvent event) {return false ;} });
EditText 属性
属性
描述
android:id
用于指定EditText的唯一标识符。
android:hint
当EditText为空时显示的提示文本。
android:text
设置EditText的文本内容。
android:inputType
指定EditText的输入类型,例如文本、数字、密码等。
android:maxLines
指定EditText的最大行数。
android:maxLength
指定EditText的最大字符数。
android:imeOptions
定义EditText的输入法选项。
android:singleLine
设置EditText是否为单行模式。
android:imeActionLabel
设置输入法操作的标签文本。
使用EditText也十分简单,当点击按钮的时候,获取到当前Text组件的内容,然后转换为String类型做操作,这里就不演示了。
ImageView 属性
属性
描述
android:src
设置ImageView显示的图像资源。
android:scaleType
设置图像的缩放类型。
android:tint
设置图像的着色。
android:adjustViewBounds
设置是否根据图像尺寸调整ImageView的边界。
android:maxWidth
设置ImageView的最大宽度。
android:maxHeight
设置ImageView的最大高度。
android:srcCompat
设置兼容的图像资源。
android:cropToPadding
设置是否裁剪ImageView的填充。
android:background
设置ImageView的背景图像。
android:foreground
设置ImageView的前景图像。
android:alpha
设置ImageView的透明度。
android:elevation
设置ImageView的高度。
android:visibility
设置ImageView的可见性。
android:rotation
设置ImageView的旋转角度。
android:rotationX
设置ImageView围绕X轴的旋转角度。
android:rotationY
设置ImageView围绕Y轴的旋转角度。
android:translationX
设置ImageView在X轴上的平移量。
android:translationY
设置ImageView在Y轴上的平移量。
android:scaleX
设置ImageView的X轴缩放比例。
android:scaleY
设置ImageView的Y轴缩放比例。
使用ImageView组件,必须要设置的属性有宽高,然后就是src,这其中路径是@开头的,一开始我并不明白@的原理,但我发现@中的基本都在res里,所以我认为当@drawable/ceshi.jpg的时候,实际上就是res/drawable/ceshi.jpg
ProgressBar 进度条可以用于加载数据时候展示的组件,它拥有多种样式和形态。
通常常用的两种分别是圆圈形状和条状,可以使用style去设定。
当你在使用 Android Studio 中的 ProgressBar 时,你可以设置多种属性来自定义其外观和行为。以下是一些常用的属性:
属性
描述
android:progress
设置当前进度值。
android:max
设置进度的最大值。
android:indeterminate
设置是否显示为不确定进度。
android:progressDrawable
设置进度条的前景drawable。
android:indeterminateDrawable
设置不确定进度条的drawable。
android:progressTint
设置进度条颜色。
android:progressBackgroundTint
设置进度条背景颜色。
android:indeterminateTint
设置不确定进度条颜色。
android:indeterminateDuration
设置不确定进度条动画的持续时间。
android:visibility
设置进度条的可见性。
下面是一个简单的示例,演示如何在 XML 中使用 ProgressBar:
1 2 3 4 5 6 7 8 9 10 11 <ProgressBar android:id ="@+id/progressBar" android:layout \_width ="wrap\_content" android:layout \_height ="wrap\_content" android:layout \_centerInParent ="true" android:progress ="50" android:max ="100" android:indeterminate ="false" android:progressTint ="@color/colorAccent" android:indeterminateTint ="@color/colorPrimaryDark" android:visibility ="visible" />
在这个示例中,进度条被设置为在屏幕中央显示,当前进度为 50%(android:progress="50"
),最大进度为 100(android:max="100"
),显示为确定进度(android:indeterminate="false"
)。进度条的颜色通过 android:progressTint
和 android:indeterminateTint
属性设置。
你可以根据你的需求调整这些属性,以实现你想要的 ProgressBar 外观和行为。
如果需要更高的定制可以创建一个方法,每次点击按钮或者做其他事件的时候调用方法增加进度条的值。
Notfication Android Studio 中的通知(Notification)是一种用户界面元素,用于向用户显示关于应用程序当前状态或事件的信息。通知可以显示在设备的状态栏中,并且可以展开以显示更多详细信息。通知通常用于向用户显示新消息、更新或其他重要事件。
以下是使用通知的基本步骤:
创建 NotificationCompat.Builder 对象,并设置通知的标题、内容等属性。
通过设置 Intent 或 PendingIntent 来定义通知的点击行为。
将通知发送到通知管理器(NotificationManager)以显示通知。
下面是一个简单的示例,演示如何在 Android Studio 中使用通知:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import android.app.NotificationChannel;import android.app.NotificationManager;import android.content.Context;import android.os.Build;import androidx.core.app.NotificationCompat;public class NotificationHelper {private static final String CHANNEL\_ID = "example\_channel" ;private static final CharSequence CHANNEL\_NAME = "Example Channel" ;private static final String CHANNEL\_DESCRIPTION = "This is an example notification channel" ;public static void showNotification (Context context, String title, String content) {NotificationCompat.Builder builder = new NotificationCompat .Builder(context, CHANNEL\_ID) .setSmallIcon(R.drawable.ic\_notification) .setContentTitle(title) .setContentText(content) .setPriority(NotificationCompat.PRIORITY\_DEFAULT); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION\_SERVICE);if (Build.VERSION.SDK\_INT >= Build.VERSION\_CODES.O) {NotificationChannel channel = new NotificationChannel (CHANNEL\_ID, CHANNEL\_NAME, NotificationManager.IMPORTANCE\_DEFAULT);channel.setDescription(CHANNEL\_DESCRIPTION); notificationManager.createNotificationChannel(channel); } notificationManager.notify(/\*notification\_id\*/ 1 , builder.build()); } }
在这个示例中,我们创建了一个名为 showNotification
的静态方法,该方法接受上下文、通知的标题和内容作为参数。然后,我们创建了一个 NotificationCompat.Builder 对象,并设置了通知的小图标、标题和内容。你可以根据需要设置其他属性,如点击通知时的操作。
最后,我们通过 NotificationManager 将通知显示出来,并在需要时创建了一个通知渠道(Notification Channel),这是为了兼容 Android Oreo 及更高版本。
要使用这个示例,你需要在调用 showNotification
方法之前创建一个 PendingIntent,并将其设置为通知的点击行为。
我自己写的通知,明明是照着教程写的,但是却没办法使用,报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private NotificationManager manager;private Notification notification;manager = (NotificationManager) getSystemService(NOTIFICATION\_SERVICE); if (Build.VERSION.SDK\_INT >= Build.VERSION\_CODES.O){NotificationChannel channel = new NotificationChannel ("leo" , "报错" ,NotificationManager.IMPORTANCE\_HIGH); manager.createNotificationChannel(channel); }else { notification = new NotificationCompat .Builder(this ,"leo" ) .setContentTitle("官方通知" ) .setContentText("您的输入不合规" ) .setSmallIcon(R.drawable.ic\_launcher\_background) .build(); }
使用这个通知
1 manager.notify(1 ,notification);
**Android Studio 中的 Toolbar 是用来创建应用程序的顶部操作栏或工具栏的。**它通常位于屏幕的顶部,并包含应用程序的主要操作按钮、导航按钮和其他重要控件。Toolbar 提供了一种简洁而强大的方式来组织应用程序的用户界面,使用户可以轻松地访问应用程序的各种功能。
一些 Toolbar 的主要功能包括:
导航按钮 :通常位于 Toolbar 的左侧,用于返回上一个屏幕或打开导航菜单。
应用程序标题 :通常位于 Toolbar 的中心,显示当前屏幕的标题或应用程序的名称。
操作按钮 :位于 Toolbar 的右侧或左侧,用于执行与当前屏幕相关的操作,如搜索、分享、设置等。
溢出菜单 :当屏幕空间有限时,Toolbar 可以自动将一些操作按钮隐藏在溢出菜单中,用户可以通过点击溢出菜单按钮来访问这些隐藏的操作。
举例:
假设我们正在开发一个新闻阅读应用程序。在这个应用程序中,Toolbar 可以具有以下功能:
导航按钮 :返回按钮,允许用户从新闻详情页面返回到新闻列表页面。
应用程序标题 :显示当前正在阅读的新闻标题,让用户清楚地知道自己在浏览哪篇新闻。
操作按钮 :分享按钮,允许用户将当前正在阅读的新闻内容分享给其他人。
溢出菜单 :包含一些额外的操作,如设置、反馈、帮助等,以便用户可以轻松地访问这些功能。
通过 Toolbar,用户可以方便地浏览新闻、返回上一个页面、分享新闻内容,并且可以访问一些额外的功能,提升了应用程序的易用性和功能性。
AlertDialog AlertDialog弹窗 创建弹窗
1 2 3 4 5 6 AlertDialog alertDialog1 = new AlertDialog .Builder(this ).setTitle("报错" ) .setMessage("输入内容非法" ) .setIcon(R.mipmap.ic\_launcher) .create();
调用
要注意的是,创建弹窗注意作用域的问题,如果写在判断里,又可以this是获取不到的,会报红。
除此之外还能设置更多属性以实现不同功能,详细参考:https://blog.csdn.net/qq_35698774/article/details/79779238
使用他人的项目 在github上,有很多大佬开源了自己的项目,通过使用他们的项目,来快速部署自己项目中的其中一个功能,这里使用我这次项目中的Titanic for Android来作为教学。
使用他人项目的时候,请务必标注来源,这是对原作者的尊重,同时也是开源社区需要自觉遵守的制度。
本次使用开源项目Titanic for Android —— romainpiel
这是一个美化字体的项目,通过观察README可以知道如何使用,首先我们需要将项目克隆到本地方便查看和复制。
通过使用git clone进行克隆,在code按钮中复制git地址然后进行克隆。
1 git clone https://github.com/romainpiel/Titanic.git
具体的git教程可以看我的另一个笔记。
克隆完成后,分析项目,找到关键的java代码,复制到自己的项目,然后按照README教程进行调用。
在这个项目中,library里是核心java代码,需要将Titanic.java和TitanicTextView.ava复制到自己的项目中,其中Titanic代码打开后是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 package com.romainpiel.titanic.library;import android.animation.Animator;import android.animation.AnimatorSet;import android.animation.ObjectAnimator;import android.animation.ValueAnimator;import android.os.Build;import android.view.animation.LinearInterpolator;/\*\* \* Titanic \* User: romainpiel \* Date: 14 /03 /2014 \* Time: 09:34 \*/ public class Titanic {private AnimatorSet animatorSet;private Animator.AnimatorListener animatorListener;public Animator.AnimatorListener getAnimatorListener () {return animatorListener;} public void setAnimatorListener (Animator.AnimatorListener animatorListener) {this .animatorListener = animatorListener;} public void start (final TitanicTextView textView) {final Runnable animate = new Runnable () {@Override public void run () {textView.setSinking(true ); ObjectAnimator maskXAnimator = ObjectAnimator.ofFloat(textView, "maskX" , 0 , 200 );maskXAnimator.setRepeatCount(ValueAnimator.INFINITE); maskXAnimator.setDuration(1000 ); maskXAnimator.setStartDelay(0 ); int h = textView.getHeight();ObjectAnimator maskYAnimator = ObjectAnimator.ofFloat(textView, "maskY" , h/2 , - h/2 );maskYAnimator.setRepeatCount(ValueAnimator.INFINITE); maskYAnimator.setRepeatMode(ValueAnimator.REVERSE); maskYAnimator.setDuration(10000 ); maskYAnimator.setStartDelay(0 ); animatorSet = new AnimatorSet (); animatorSet.playTogether(maskXAnimator, maskYAnimator); animatorSet.setInterpolator(new LinearInterpolator ()); animatorSet.addListener(new Animator .AnimatorListener() { @Override public void onAnimationStart (Animator animation) {} @Override public void onAnimationEnd (Animator animation) {textView.setSinking(false ); if (Build.VERSION.SDK\_INT < Build.VERSION\_CODES.JELLY\_BEAN) {textView.postInvalidate(); } else { textView.postInvalidateOnAnimation(); } animatorSet = null ; } @Override public void onAnimationCancel (Animator animation) {} @Override public void onAnimationRepeat (Animator animation) {} }); if (animatorListener != null ) {animatorSet.addListener(animatorListener); } animatorSet.start(); } }; if (!textView.isSetUp()) {textView.setAnimationSetupCallback(new TitanicTextView .AnimationSetupCallback() { @Override public void onSetupAnimation (final TitanicTextView target) {animate.run(); } }); } else { animate.run(); } } public void cancel () {if (animatorSet != null ) {animatorSet.cancel(); } } }
通过观察代码,发现这个文件没有继承任何类,代表这是一个功能类,同时通过详细阅读代码,发现这是用来控制美化字体的动态效果,通过着色器让文字的遮罩按照波浪的样子往上移动。
然后是TitanicTextView.ava,不难发现TextView是Android的一个组件,打开代码后,发现果然如此:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 package com.romainpiel.titanic.library;import android.content.Context;import android.content.res.ColorStateList;import android.graphics.Bitmap;import android.graphics.BitmapShader;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.Shader;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.widget.TextView;/\*\* \* Titanic \* romainpiel \* 13 /03 /2014 \*/ public class TitanicTextView extends TextView {public interface AnimationSetupCallback {public void onSetupAnimation (TitanicTextView titanicTextView) ;} private AnimationSetupCallback animationSetupCallback;private float maskX, maskY;private boolean sinking;private boolean setUp;private BitmapShader shader;private Matrix shaderMatrix;private Drawable wave;private float offsetY;public TitanicTextView (Context context) {super (context);init(); } public TitanicTextView (Context context, AttributeSet attrs) {super (context, attrs);init(); } public TitanicTextView (Context context, AttributeSet attrs, int defStyle) {super (context, attrs, defStyle);init(); } private void init () {shaderMatrix = new Matrix (); } public AnimationSetupCallback getAnimationSetupCallback () {return animationSetupCallback;} public void setAnimationSetupCallback (AnimationSetupCallback animationSetupCallback) {this .animationSetupCallback = animationSetupCallback;} public float getMaskX () {return maskX;} public void setMaskX (float maskX) {this .maskX = maskX;invalidate(); } public float getMaskY () {return maskY;} public void setMaskY (float maskY) {this .maskY = maskY;invalidate(); } public boolean isSinking () {return sinking;} public void setSinking (boolean sinking) {this .sinking = sinking;} public boolean isSetUp () {return setUp;} @Override public void setTextColor (int color) {super .setTextColor(color);createShader(); } @Override public void setTextColor (ColorStateList colors) {super .setTextColor(colors);createShader(); } @Override protected void onSizeChanged (int w, int h, int oldw, int oldh) {super .onSizeChanged(w, h, oldw, oldh);createShader(); if (!setUp) {setUp = true ; if (animationSetupCallback != null ) {animationSetupCallback.onSetupAnimation(TitanicTextView.this ); } } } /\*\* \* Create the shader \* draw the wave with current color for a background \* repeat the bitmap horizontally, and clamp colors vertically \*/ private void createShader () {if (wave == null ) {wave = getResources().getDrawable(R.drawable.wave); } int waveW = wave.getIntrinsicWidth();int waveH = wave.getIntrinsicHeight();Bitmap b = Bitmap.createBitmap(waveW, waveH, Bitmap.Config.ARGB\_8888);Canvas c = new Canvas (b);c.drawColor(getCurrentTextColor()); wave.setBounds(0 , 0 , waveW, waveH); wave.draw(c); shader = new BitmapShader (b, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP); getPaint().setShader(shader); offsetY = (getHeight() - waveH) / 2 ; } @Override protected void onDraw (Canvas canvas) {if (sinking && shader != null ) {if (getPaint().getShader() == null ) {getPaint().setShader(shader); } shaderMatrix.setTranslate(maskX, maskY + offsetY); shader.setLocalMatrix(shaderMatrix); } else { getPaint().setShader(null ); } super .onDraw(canvas);} }
这个类继承了TextView,这代表如果要使用这个文件,则是导入组件,README中也是这样告诉你的。
How to use
Add a TitanicTextView
to your layout:
1 2 3 4 5 6 7 <com.romainpiel.titanic.TitanicTextView android:id="@+id/titanic\_tv" android:text="@string/loading" android:layout\_width="wrap\_content" android:layout\_height="wrap\_content" android:textColor="#212121" android:textSize="70sp"/>
至此最关键的部分已经搞定,复制文件的时候需要注意层级关系,同时复制完成后可能会遇到报错的情况,这是因为自己的项目一些引入的路径可能不对,需要重新更改下路径,比如官方给出的com.romainpiel.titanic.TitanicTextView在自己的项目中并不对,因为我的层级不是这样的,对我而言,则是使用:com.romainpiel.titanic.library.TitanicTextView,举一反三,其他也是如此。
注意将所有用到的文件都复制进去,这里还有一张资源图片就不过多讲了。
至此,已经成功使用了他人的项目,一些细节的修改可以通过阅读代码来做到。
导入依赖 项目自带的功能已经无法满足当前的开发,这时候就需要导入依赖来获得更多的功能支持,这里我用我目前需要的依赖作为演示来告诉你如何导入依赖。
在我做的项目中,我需要一个可以将数据转换为excol表格的功能,在网上翻阅显示需要使用apache官方制作的依赖API,叫做org.apache.poi,确定好需要导入的版本,然后打开——项目结构——依赖——找到+号——点击第一个lib,可以看到点击+号后有两个选择,这方便代表在线寻找lib和通过jar包导入,我没有jar包,所以使用搜索。
搜索org.apache.poi后,找到具体的依赖和选好需要的版本后,点击应用和确定,开始自动导入依赖进行下载。
亦或者本地下载jar包后,可以在libs中炸包。
等待下载完成后即可。
页面跳转 一个页面所能展示的组件总是有限的,虽然你可以通过隐藏组件的方式来做到伪跳转页面,但是这样显然会让代码变的臃肿,同时不方便维护。
IDEA有提供更加便捷的跳转页面的方式,只需要创建一个页面,然后几行代码,一切就会帮你搞定。
在您的项目中创建两个活动(Activity),即两个页面。您可以通过在项目资源管理器中右键单击“app”文件夹并选择“New -> Activity -> Empty Activity”来创建新的活动。
创建完成后,会发现多了两个文件,分别是代表Main的MainActivit2,和在layout里的activity_main2.xml,其中一个是到这个页面被创建的时候会执行的代码块和用来给页面布局的xml。
想要实现跳转,也只需要一个契机,比如创建一个按钮,点击后跳转,这需要使用提供好的方法。
1 2 3 4 5 6 7 8 9 10 11 Button btn\_jump = findViewById(R.id.btn\_jump); btn\_jump.setOnClickListener(new View .OnClickListener() { @Override public void onClick (View v) {Log.e("TAG" ,"JUMP被点击了" ); Intent intent = new Intent (MainActivity.this , MainActivity2.class);startActivity(intent); } });
获取第一个页面的按钮,然后重写点击方法,通过new Intent来填写两个参数,来告诉代码从哪里跳转到哪里,比如我从第一个页面跳转到第二个页面就是,MainActivity.this,.this不就是当前吗,然后MainActivity2.class,则是第二个页面的类。
至此跳转完成。
这部分我参考了掘金的一篇文章:https://juejin.cn/s/android%20studio%E5%AE%9E%E7%8E%B0%E4%B8%A4%E4%B8%AA%E9%A1%B5%E9%9D%A2%E7%9A%84%E8%B7%B3%E8%BD%AC
文章内容也贴在下方:
android studio实现两个页面的跳转 要在 Android Studio 中实现两个页面的跳转,您可以按照以下步骤进行操作:
创建一个新的 Android Studio 项目。
在您的项目中创建两个活动(Activity),即两个页面。您可以通过在项目资源管理器中右键单击“app”文件夹并选择“New -> Activity -> Empty Activity”来创建新的活动。
在第一个活动中,添加一个按钮或其他视图元素,以触发跳转到第二个活动。您可以在 XML 布局文件中添加该元素,如下所示:
1 2 3 4 5 6 xml复制代码<Button android:id ="@+id/btn\_go\_to\_second\_activity" android:layout \_width ="wrap\_content" android:layout \_height ="wrap\_content" android:text ="Go to Second Activity" />
在第一个活动的 Java 代码中,获取对该按钮的引用,并为其设置一个点击监听器。在监听器中,创建一个 Intent 对象,并使用 startActivity() 方法将其传递给第二个活动。代码如下所示:
1 2 3 4 5 6 7 8 java复制代码Button btnGoToSecondActivity = findViewById(R.id.btn\_go\_to\_second\_activity); btnGoToSecondActivity.setOnClickListener(new View .OnClickListener() { @Override public void onClick (View view) {Intent intent = new Intent (FirstActivity.this , SecondActivity.class);startActivity(intent); } });
在第二个活动中,您可以添加返回第一个活动的按钮。同样,您可以在 XML 布局文件中添加该元素,如下所示:
1 2 3 4 5 6 xml复制代码<Button android:id ="@+id/btn\_go\_back" android:layout \_width ="wrap\_content" android:layout \_height ="wrap\_content" android:text ="Go Back" />
在第二个活动的 Java 代码中,获取对该按钮的引用,并为其设置一个点击监听器。在监听器中,使用 finish() 方法关闭第二个活动,返回第一个活动。代码如下所示:
1 2 3 4 5 6 7 java复制代码Button btnGoBack = findViewById(R.id.btn\_go\_back); btnGoBack.setOnClickListener(new View .OnClickListener() { @Override public void onClick (View view) {finish(); } });
通过以上步骤,您可以在 Android Studio 中实现两个页面之间的跳转。请注意,在创建 Intent 对象时,您需要指定要跳转到的活动类名。同时,在第二个活动中返回第一个活动时,您可以使用 finish() 方法关闭第二个活动。
SharedPreferences 使用 通过创建xml,和使用它的编辑方法实现添加数据删除数据或者其他操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public void ShowContainer () {SharedPreferences sharedPreferences = getSharedPreferences("my\_data" , MODE\_PRIVATE);Map<String, String> dataMap = parseStringToMap(sharedPreferences.getAll().toString()); System.out.println(dataMap.values() + "size:" + dataMap.size()); LinearLayout container = findViewById(R.id.main\_line);container.removeAllViews(); for (int i = dataMap.size() - 1 ; i >= 0 ; i--) {TextView textView = new TextView (AddActivity.this );textView.setText(dataMap.get(String.valueOf(i+1 ))); textView.setTextSize(30 ); container.addView(textView); } }
这个方法新建对象创建了my_data.xml将文件存储在这里。
不管是在模拟器运行还是在真机运动,如果你需要找到文件的具体位置那么可以阅读下面文章:
通過使用SharedPreferences可以将数据保存在本地,在一篇博文中,提到:
SharedPreferences 会在应用包目录中生成一个xml文件,将数据保存在里面,可以实现数据持久性保存。
创建的数据,保存在 Data -> Data -> 包名 -> shared_prefs 文件夹中
博文地址:https://www.cnblogs.com/gfwei/p/11781050.html
但在我的实际寻找中,我没有在com.sharedPreferences里找到,可能是因为我是在模拟器运行中找的,我是在我的项目包名里面找到了这个文件,确实是my_data.xml。这个包名的意思就是项目的包名。
Sqlite 创建帮助类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package com.example.financing;import android.content.Context;import android.database.DatabaseErrorHandler;import android.database.sqlite.SQLiteDatabase;import androidx.annotation.Nullable;public class DBOpenHelper extends android .database.sqlite.SQLiteOpenHelper {public DBOpenHelper (@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {super (context, name, factory, version);} public DBOpenHelper (@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version, @Nullable DatabaseErrorHandler errorHandler) {super (context, name, factory, version, errorHandler);} @Override public void onCreate (SQLiteDatabase db) {String sql = "CREATE TABLE expenditure (" +"id INTEGER PRIMARY KEY AUTOINCREMENT," +"amount REAL," +"category TEXT," +"date DATE," +"transaction\_method TEXT," +"account TEXT," +"payee TEXT," +"location TEXT," +"attachment TEXT," +"notes TEXT)" ;db.execSQL(sql); } @Override public void onUpgrade (SQLiteDatabase db, int oldVersion, int newVersion) {} }
使用一个数据库
在上述代码中,null
和1
是用于创建数据库以及获取可写数据库的参数。
对于null
参数,它表示数据库游标工厂(CursorFactory
),用于控制查询结果集指针的行为。如果你不需要自定义行为,可以将其设置为null
,系统将使用默认的游标工厂。
而对于1
参数,它表示数据库版本号(database version),用于管理数据库的升级和降级。每当你对数据库进行结构上的改变时,你需要递增版本号。这样在下一次打开数据库时,系统会调用onUpgrade()
方法,你可以在该方法中执行数据库的升级操作。对于刚开始创建的数据库,版本号通常设置为1。
这些参数可以根据你的实际需求进行自定义调整。
保存变量 有时候我们会想要保存一些变量到本地,来实现比如打开APP加载背景路径等,这样的好处是,当你想要换背景,只需要复制到内部存储里然后改变变量的值就可以在下次加载的时候启用成功了。
什么是 SharedPreferences? SharedPreferences
是 Android 提供的一种轻量级的数据存储机制,适合于保存小量的简单数据,如用户设置、应用状态等。它以键值对(key-value pairs)的形式存储数据,便于进行快速读取和写入。
主要特点
轻量级 :适合存储少量数据。
持久性 :即使应用关闭或设备重启,数据仍会被保留。
简单易用 :API 简洁直观,方便开发者使用。
使用方法 1. 获取 SharedPreferences 实例 使用 getSharedPreferences()
方法获取指定名称的 SharedPreferences
对象。
1 SharedPreferences sharedPreferences = getSharedPreferences("MyAppPrefs" , MODE\_PRIVATE);
"MyAppPrefs"
:这是您自定义的文件名,用于存储键值对。
MODE_PRIVATE
:表示该文件只能被当前应用访问。
2. 写入数据 使用 SharedPreferences.Editor
对象来编辑 SharedPreferences
数据。可以使用 putString()
, putInt()
, putBoolean()
等方法来存储不同类型的数据。
1 2 3 4 5 SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString("username" , "john\_doe" ); editor.putInt("age" , 30 ); editor.putBoolean("isLoggedIn" , true ); editor.apply();
apply()
:异步保存数据,不会阻塞主线程。如果需要立即写入,可以使用 commit()
,但会同步写入,相对较慢。
3. 读取数据 通过 getString()
, getInt()
, getBoolean()
等方法读取之前保存的数据。可以提供一个默认值,以防在没有找到对应键时返回 null。
1 2 3 String username = sharedPreferences.getString("username" , "default\_user" ); int age = sharedPreferences.getInt("age" , 0 ); boolean isLoggedIn = sharedPreferences.getBoolean("isLoggedIn" , false );
4. 移除数据 如果您需要删除某个键对应的数据,可以使用 remove()
方法。
1 2 editor.remove("username" ); editor.apply();
5. 清空所有数据 如果您想要清空 SharedPreferences
中的所有数据,可以使用 clear()
方法。
1 2 editor.clear(); editor.apply();
保存的文件类型
文件位置 :SharedPreferences
文件通常保存在以下路径:
1 /data/data/<your\_package\_name>/shared\_prefs/MyAppPrefs.xml
其中 <your_package_name>
是您应用的包名,例如 com.example.myapp
。
文件类型 :保存的数据以 XML 格式存储。例如,文件内容可能类似于:
1 2 3 4 5 <map > <string name ="username" value ="john\_doe" /> <int name ="age" value ="30" /> <boolean name ="isLoggedIn" value ="true" /> </map >
在Android studio中清理虚拟机设备
当我们不断调试项目,反复运行设备,虚拟机里可能会多出很多文件,当我们需要清理的时候,通过打开虚拟机管理窗口,然后找到需要清理的设备,点击最右边的三个带你,找到 wipe Data 可以清理干净了
重要组件 Activity和Fragment是Android应用程序中的两个重要组件。
**Activity(活动)**是用户与应用程序交互的主要界面单元。每个Activity都是一个单独的屏幕,它负责处理用户输入、加载布局、管理生命周期等。通常,一个应用程序由多个Activity组成,每个Activity代表一个屏幕,用户通过在不同的Activity之间进行转换来与应用程序进行交互。
**Fragment(片段)**是Activity界面的一部分或一块可重用的UI组件。一个Activity可以包含多个Fragment,并且Fragment可以在运行时动态添加、移除或替换。Fragment具有自己的生命周期,并且可以嵌套在Activity的布局中。使用Fragment可以使界面更加模块化和灵活,有助于构建适应不同屏幕尺寸和方向的响应式界面。
它们之间的主要区别在于:
生命周期管理 :Activity有自己的生命周期方法(如onCreate,onStart,onResume等),而Fragment也有类似的生命周期方法,但与Activity的生命周期方法不完全相同。Fragment的生命周期受到其宿主Activity的生命周期影响。
布局管理 :Activity有自己的布局文件(XML文件),定义整个屏幕的布局结构,而Fragment通常嵌套在Activity的布局中,可以与Activity共享同一个布局文件,也可以使用独立的布局文件。
重用性和灵活性 :Fragment的设计目的是提高UI组件的重用性和灵活性。通过在不同的Activity中重用Fragment,可以减少重复代码,简化开发流程,并且能够更灵活地构建多屏幕应用程序。
总的来说,Activity是整个应用程序的主要组成部分,而Fragment是Activity的一部分,用于实现界面的模块化和重用。在学习Android开发时,通常建议先学习Activity,然后深入理解Fragment的使用。
案例 学习Andriod Studio是为了开发一款理财软件,在学习的过程中我也会记录开发过程,只有实践和理论同时进行,才能让学习的效率更高。
开屏展示 目前我要做的第一件事情就是开发一个开屏展示,我希望打开软件的时候,先展示一个页面,几秒中后关闭页面,展示软件主页内容。
这个开屏可以用于,显示广告,显示LOGO,显示教程等等等。
编写逻辑:我首先编写一个组件,目前我使用的是TextView,文本组件,然后创建一个对应的类继承这个组件,当加载这个组件的时候,有一个计时器倒数五秒后,隐藏本组件。
代码:
页面端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <?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:id ="@+id/main" android:layout \_width ="match\_parent" android:layout \_height ="match\_parent" tools:context =".MainActivity" ><com.example.financing.TextViewLain android:id ="@+id/tv\_one" android:layout \_width ="match\_parent" android:layout \_height ="match\_parent" android:background ="#3488B5" android:ellipsize ="marquee" android:focusable ="true" android:textSize ="50dp" android:focusableInTouchMode ="true" android:gravity ="center" android:marqueeRepeatLimit ="marquee\_forever" android:singleLine ="true" android:text ="@string/lain" android:textColor ="@color/black" android:textStyle ="italic" ></com.example.financing.TextViewLain > <TextView android:layout \_width ="match\_parent" android:layout \_height ="match\_parent" android:text ="hello" > </TextView > </LinearLayout >
JAVA端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package com.example.financing;import android.content.Context;import android.util.AttributeSet;import android.widget.TextView;import android.os.Handler;import androidx.annotation.Nullable;public class TextViewLain extends TextView {public TextViewLain (Context context) {super (context);init(); } public TextViewLain (Context context, @Nullable AttributeSet attrs) {super (context, attrs);init(); } public TextViewLain (Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super (context, attrs, defStyleAttr);init(); } private void init () {setFocusable(true ); setFocusableInTouchMode(true ); } @Override protected void onAttachedToWindow () {super .onAttachedToWindow();new Handler ().postDelayed(new Runnable () {@Override public void run () {TextViewLain.this .setVisibility(GONE); } }, 5000 ); } @Override public boolean isFocused () {return true ;} }
至此,实现了我需要的效果,但我认为这个消失转场有些生硬,之后有机会修改一下。
之所以五秒后显示Hello,则是利用了从上往下渲染的规则,开屏的View遮住了Hello,只有View消失后才能显示Hello。
开屏展示后期完成数据展示的逻辑后,会将比较常用的数据直接展示,如收入,支出等等,当然可以自定义,也可以取消展示。
但目前先显示品牌LOGO。
基础记账 制作基础记账功能首先分析需求。
首先需要一个输入框可以输入文本,然后需要一个添加按钮,点击按钮的时候会读取输入框里的内容,和目前已经有的数据做加法运算。
显示运算结果需要两个TextView,用来显示两个数据,第一个是总和,第二个是每次相加的结果,这样可以看到自己目前花了多少钱,和每笔详细的消费。
第一个显示数据好做,创建一个TextView,然后用set方法直接修改组件的默认Text就可以。瓦问题是第二个显示,因为要显示多个内容,所以必须每次添加后创建一个新的TextView,用来显示当前一笔的详细消费。
这里在我查阅资料后想出了这种写法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 <?xml version="1.0" encoding="utf-8" ?> <androidx.constraintlayout.widget.ConstraintLayout 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:id ="@+id/main" android:layout \_width ="match\_parent" android:layout \_height ="match\_parent" tools:context =".MainActivity" ><com.example.financing.TextViewLain android:id ="@+id/tv\_one" android:layout \_width ="0dp" android:layout \_height ="wrap\_content" android:background ="#3488B5" android:ellipsize ="marquee" android:focusable ="true" android:focusableInTouchMode ="true" android:gravity ="center" android:marqueeRepeatLimit ="marquee\_forever" android:singleLine ="true" android:text ="@string/lain" android:textColor ="@color/black" android:textSize ="24sp" android:textStyle ="italic" app:layout \_constraintEnd \_toEndOf ="parent" app:layout \_constraintStart \_toStartOf ="parent" app:layout \_constraintTop \_toTopOf ="parent" /><EditText android:id ="@+id/edit\_text" android:layout \_width ="0dp" android:layout \_height ="wrap\_content" android:layout \_marginStart ="16dp" android:layout \_marginTop ="40dp" android:layout \_marginEnd ="16dp" android:hint ="输入金额" app:layout \_constraintEnd \_toEndOf ="parent" app:layout \_constraintStart \_toStartOf ="parent" app:layout \_constraintTop \_toBottomOf ="@id/tv\_one" /><Button android:id ="@+id/btn\_sum" android:layout \_width ="100dp" android:layout \_height ="60dp" android:layout \_marginTop ="16dp" android:background ="#4BC0FF" android:text ="添加" android:textColor ="#FFFFFF" app:layout \_constraintEnd \_toEndOf ="parent" app:layout \_constraintHorizontal \_bias ="0.5" app:layout \_constraintStart \_toStartOf ="parent" app:layout \_constraintTop \_toBottomOf ="@id/edit\_text" /><TextView android:id ="@+id/text\_num" android:layout \_width ="0dp" android:layout \_height ="wrap\_content" android:layout \_marginStart ="16dp" android:layout \_marginTop ="16dp" android:layout \_marginEnd ="16dp" android:text ="0" app:layout \_constraintEnd \_toEndOf ="parent" app:layout \_constraintStart \_toStartOf ="parent" app:layout \_constraintTop \_toBottomOf ="@id/btn\_sum" /><ScrollView android:layout \_width ="0dp" android:layout \_height ="0dp" app:layout \_constraintBottom \_toBottomOf ="parent" app:layout \_constraintEnd \_toEndOf ="parent" app:layout \_constraintStart \_toStartOf ="parent" app:layout \_constraintTop \_toBottomOf ="@id/text\_num" ><LinearLayout android:id ="@+id/main\_line" android:layout \_width ="match\_parent" android:layout \_height ="wrap\_content" android:layout \_marginTop ="16dp" android:orientation ="vertical" tools:layout \_editor \_absoluteX ="0dp" ><TextView android:layout \_width ="wrap\_content" android:layout \_height ="wrap\_content" android:text ="添加数据" /></LinearLayout > </ScrollView > </androidx.constraintlayout.widget.ConstraintLayout >
从这段代码中,可以看到我在父容器ConstraintLayout里又创建了一个LinearLayout,因为在我想的时候我发现xml本质上和HTML差不多,而我的预想是为了保持布局的设计,我需要多个BOX,每个Box显示不同的内容,所以就有个这个内容器。
然后这个容器外面有一个ScrollView,这个标签的作用是为了判断,如果容器内的组件占满后,会出现滚动条,用来往下滑动以持续显示数据。
就这样,完成了页面的构建,虽然简陋,但在目前而言,我的目的主要是为了高效的学习。
至于逻辑部分的代码,我是这样写的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 package com.example.financing;import android.os.Bundle;import android.util.Log;import android.view.View;import android.view.ViewGroup;import android.widget.Button;import android.widget.EditText;import android.widget.LinearLayout;import android.widget.TextView;import androidx.activity.EdgeToEdge;import androidx.appcompat.app.AppCompatActivity;import androidx.constraintlayout.widget.ConstraintLayout;public class MainActivity extends AppCompatActivity {@Override protected void onCreate (Bundle savedInstanceState) {super .onCreate(savedInstanceState);EdgeToEdge.enable(this ); setContentView(R.layout.activity\_main); Button btn\_sum = findViewById(R.id.btn\_sum); EditText edit\_text = findViewById(R.id.edit\_text); TextView text\_num = findViewById(R.id.text\_num); btn\_sum.setOnClickListener(new View .OnClickListener() { @Override public void onClick (View v) {String editTextContent = edit\_text.getText().toString();String textViewContent = text\_num.getText().toString();LinearLayout container = findViewById(R.id.main\_line);if (editTextContent.isEmpty()){Log.d("TAG" ,"报错:输入为空" ); }else { double editTextValue = 0 ;try {editTextValue = Double.parseDouble(editTextContent); } catch (NumberFormatException e) { Log.d("TAG" , "报错:输入不是有效的数字或小数" ); } double textViewValue = Double.parseDouble(textViewContent);double sum = editTextValue + textViewValue;text\_num.setText(String.valueOf(sum)); edit\_text.setText("" ); TextView textView = new TextView (MainActivity.this );textView.setText(editTextContent); textView.setTextSize(30 ); container.addView(textView); } } }); } }
大概就是获取这三个组件,然后依次做出操作,值得一讲的是,这个自动创建组件的功能,可以new出组件后,先对组件设置相关必要参数,然后添加到容器中,这个容器就是我创建LinearLayout的原因,如果直接将组件添加到父容器中,那么布局就会重叠变乱,而我设定好LinearLayout后,少了很多不必要的麻烦,容器会对里面添加的组件排版,然后每行显示一条数据。
美观的加载画面 今天在论坛中看到了一个他人推荐的github项目 Titanic for Android。
大概原理我推断,通过读取字体文件ttf后,然后使用着色器美化动态效果,然后调用组件。
官方文档:
How to use
Add a TitanicTextView
to your layout:
1 2 3 4 5 6 7 <com.romainpiel.titanic.TitanicTextView android:id ="@+id/titanic\_tv" android:text ="@string/loading" android:layout \_width ="wrap\_content" android:layout \_height ="wrap\_content" android:textColor ="#212121" android:textSize ="70sp" />
To start the animation:
1 2 titanic = new Titanic (); titanic.start(myTitanicTextView);
You may want to keep track of the titanic instance after the animation is started if you want to stop it.
To stop it:
将这个项目添加到自己的项目来实现这个功能。
数据的保存和转换 通过使用SharedPreferences保存数据然后使用org.apache.poi依赖将数据转换成excol。
org.apache.poi报错,当前版本无法适配,切换org.apache.poi的版本号后成功运行,或者修改minskd也可以,但这样会让一些手机无法卡退。
创建一个数据库用来存储 虽然使用上面的方法也能够存储数据,但是面对大量需要索引的数据时,就显得没有那么方便和迅速,对于这个对象只适合存放一些日常的数据,面对大量需要检索的数据时,则需要数据库。
首先需要设计几个表,这里比如我设计出了一个支出表,它拥有以下列:
id: 整型,主键,具有自动增量属性,用于唯一标识每个支出记录。
amount: 实数,用于存储支出金额。
category: 文本,用于存储支出的类别或类型。
date: 日期,用于存储支出发生的日期。
transaction_method: 文本,用于存储支付方式或交易方式。
account: 文本,用于存储支出所使用的账户信息。
payee: 文本,用于存储收款人或收款机构的信息。
location: 文本,用于存储支出发生的地点或位置信息。
attachment: 文本,用于存储任何附加文件或照片的路径或链接。
notes: 文本,用于存储关于支出的任何备注或说明。
然后根据设计好的表去创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 String sql = "CREATE TABLE expenditure (" +"id INTEGER PRIMARY KEY AUTOINCREMENT," +"amount REAL," +"category TEXT," +"date DATE," +"transaction\_method TEXT," +"account TEXT," +"payee TEXT," +"location TEXT," +"attachment TEXT," +"notes TEXT)" ;db.execSQL(sql); }