前言
最近计划做一个安卓项目,决定系统学习一下安卓,于是跟着b站一个视频学习,把整理出来的笔记分享一下。
视频连接:https://www.bilibili.com/video/BV19U4y1R7zV?p=1&vd_source=edd880713648cfdba73e0de269c4035d
1.安装Andriod Studio和SDK
Andriod Studio:Android Studio 是谷歌推出的一个Android集成开发工具,基于IntelliJ IDEA. 类似 Eclipse ADT,Android Studio 提供了集成的 Android 开发工具用于开发和调试。
SDK:全程Software Development Kit,意即软件开发工具包,可以将App源码编译为可执行应用。
2.Hello World!
1.创建工程与模拟器
创建一个新项目,选择Minimum SDK(最低兼容版本),如果选择5.0,则5.0以上的版本都可以兼容。
![](https://i-blog.csdnimg.cn/blog_migrate/0244820a3f5f665172222c819ab13da7.png)
创建后自动打开一个xml和java文件
![](https://i-blog.csdnimg.cn/blog_migrate/3a526cefa6c6a40bca5720ce7f3e4286.png)
Create device可以创建安卓虚拟机,让应用运行在安卓设备上。
![](https://i-blog.csdnimg.cn/blog_migrate/99b01d48de80c639f09d4a365f44fee1.png)
点击"run"即可在安卓虚拟上安装并运行你的APP
![](https://i-blog.csdnimg.cn/blog_migrate/4b87da998e3d8c5682b90e1c8b8c888a.png)
2.运行日志、运行环境
![](https://i-blog.csdnimg.cn/blog_migrate/83dbfd2b290507b5a0ec672504b3dd80.png)
App可以在模拟器上运行,也可以在真机上运行
真机运行需要用数据线将手机连接在电脑,打开开发者模式
3.工程结构
App工程分为两个层次,第一个层次是项目(Project),另一个层次是模块(Module)
模块依赖于项目,每个项目至少拥有一个模块,也能拥有多个模块。
一般编译运行app指的是运行某个模块,而非运行某个项目,因为模块才对应实际的app。
![](https://i-blog.csdnimg.cn/blog_migrate/f85da41c4b35839f80881ac12e678e0c.png)
从上图看到,该项目下面有两个分类:一个是app(代表app模块);另一个是Gradle。其 中,app下的src有3个子目录,其功能说明如下:
main中的java存放源码,res存放资源,xml是app的运行配置文件。
androidTest和test是测试用的java代码
Grade是工程的编译配置文件
app文件夹
![](https://i-blog.csdnimg.cn/blog_migrate/4db9509459f7c4673b1a87bfb990224f.png)
res文件夹下有多个文件夹
![](https://i-blog.csdnimg.cn/blog_migrate/02a5592e2f7a378781dc4ec6d4047b35.png)
drawable目录存放图形描述文件与图片文件。
layout目录存放App页面的布局文件。
mipmap目录存放App的启动图标。
values目录存放一些常量定义文件,例如字符串常量strings.xml、像素常量dimens.xml、颜色常 量colors.xml、样式风格定义styles.xml等。
![](https://i-blog.csdnimg.cn/blog_migrate/c2d904412a4753bed12a9bde5e9a42ee.png)
清单文件
![](https://i-blog.csdnimg.cn/blog_migrate/cc49f1bfdba259aa644d256e8bc522a8.png)
![](https://i-blog.csdnimg.cn/blog_migrate/962ab89b3bd0fe070b67f06f5f0a08cd.png)
activity是一个应用程序组件,提供一个屏幕,用户可以用来完成交互
![](https://i-blog.csdnimg.cn/blog_migrate/84d0e45c257397427e3690fd52121f3d.png)
Gradle文件夹
Gradle下面主要是工程的编译配置文件,主要有:
(1)build.gradle,该文件分为项目级与模块级两种,用于描述App工程的编译规则。
(2)proguard-rules.pro,该文件用于描述Java代码的混淆规则。
(3)gradle.properties,该文件用于配置编译工程的命令行参数,一般无须改动。
(4)settings.gradle,该文件配置了需要编译哪些模块。初始内容为include ':app',表示只编译app模 块。
(5)local.properties,项目的本地配置文件,它在工程编译时自动生成,用于描述开发者电脑的环境 配置,包括SDK的本地路径、NDK的本地路径等。
项目级别的build.gradle
![](https://i-blog.csdnimg.cn/blog_migrate/c1e528a011f9062f46ee6edacee595ef.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2fe13c97c97be4c0390aacc38309237f.png)
4.设计规范
用XML标记描绘应用界面,Java代码书写程序逻辑。好处:提升代码复用性。
5.Activity的创建与跳转
![](https://i-blog.csdnimg.cn/blog_migrate/406492fafbbdb20c05f36ef222ec3cc9.png)
1.创建xml
![](https://i-blog.csdnimg.cn/blog_migrate/1cc03655bf8e1822a5c4a57155bf4fe4.png)
2.创建java代码
![](https://i-blog.csdnimg.cn/blog_migrate/9e2f9f7231c5a8869823058f05bd569b.png)
继承类,重写OnCreate,指定布局
![](https://i-blog.csdnimg.cn/blog_migrate/28dc3865682febb4f11ab216460afc25.png)
3.在清单文件中注册
![](https://i-blog.csdnimg.cn/blog_migrate/7ae769bda94b76cd94f3421a5b479c43.png)
4.布局中添加一个按钮
![](https://i-blog.csdnimg.cn/blog_migrate/1cc3d317cf9ed393eb992d013f871e70.png)
5.给按钮点击事件
匿名内部类
idea如何实现 未实现的方法快捷键,鼠标放在类的名称上,按住Alt+Enter键
![](https://i-blog.csdnimg.cn/blog_migrate/d1bf2bb5b5acdb5a05e0f8d54eed4ee6.png)
6创建Activity的简单方式
直接在java文件夹下创建New-Activity-Empty Activity
![](https://i-blog.csdnimg.cn/blog_migrate/c5871581c483c6eecdf662a7d005956c.png)
命名
![](https://i-blog.csdnimg.cn/blog_migrate/ba47428659f931db1dc7b76ecdd89261.png)
会自动创建java文件和xml
![](https://i-blog.csdnimg.cn/blog_migrate/edb9f8b3cbd487b02e14c3d6e2035d32.png)
7.上面遇到的bug
![](https://i-blog.csdnimg.cn/blog_migrate/3a285bfde83aa55026c967244fc313c9.png)
如果没有将某activity设定为启动activity而直接run,会报错
![](https://i-blog.csdnimg.cn/blog_migrate/77958e7bfd4fac5a9f6517c5707470fa.png)
解决:可在AndroidManifest.xml中Activity配置上设置 android:exported="true",或者设置intent-filter
如下:
<activity android:name=".activity.LoginActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
3.简单控件
1.文本显示
设置文本内容
1.XML文件中通过属性android:text设置文本
2.在Java代码中调用文本视图对象的setText方法设置文本
string中能够有文本
设置文本大小
1.在Java代码中调用setTextSize方法
2.在XML文件中则通过属性android:textSize指定文本大小
需要了解单位
![](https://i-blog.csdnimg.cn/blog_migrate/b830dd50987ca6ebcfed6b2f7b23f922.png)
设置文本颜色
1.在Java代码中调用setTextColor方法设置文本颜色,具体色值可以从Color类获取
也可以用8位或者6位16进制数表示,8位前两位表示透明度,ff为完全不透明,00位完全透明,后六位的每两位代表RGB的色值,6位表示的透明度默认为00,即是透明的
2.XML文件textColor
xml中的6位颜色默认是不透明的
3.颜色可以引用在res中定义的颜色,如在colors中定义一个绿色
代码
public class TextViewActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_text);
TextView tv_hello=findViewById(R.id.tv_hello);
TextView tv_background=findViewById(R.id.tv_background);
tv_hello.setText(R.string.hello);
tv_hello.setTextSize(50);
tv_hello.setTextColor(Color.GREEN); //tv_hello.setTextColor(0xff00ff00);
tv_background.setBackgroundColor(Color.BLUE);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_hello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello"
android:textSize="30dp"
android:textColor="#00ff00"/>
<TextView
android:id="@+id/tv_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello"
android:textSize="30dp"
android:textColor="@color/green"/>
</LinearLayout>
2.视图基础
设置视图宽高
➢1.视图宽度通过属性android:layout _width表达,视图高度通过属性android:layout height表达,宽高的取值主要有下列三种:
●match_ parent: 表示与上级视图保持一致。
●wrap_ content: 表示与内容自适应。
●以dp为单位的具体尺寸。
➢2.首先确保XML中的宽高属性值为wrap_ content, 接着打开该页面对应的Java代码,依序执行以下三个步骤:
●调用控件对象的getLayoutParams方法,获取该控件的布局参数。
●布局参数的width属性表示宽度,height属性表示高度,修改这两个属性值。
●调用控件对象的setLayoutParams方法,填入修改后的布局参数使之生效。
package com.example.helloworld;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.TextView;
import com.example.helloworld.util.Utils;
public class MainActivity_border extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_border);
TextView tv_code=findViewById(R.id.tv_code);
//获取tv_code的布局参数
ViewGroup.LayoutParams params=tv_code.getLayoutParams();
params.width= Utils.dip2x(this,300);//设置tv_code的宽
tv_code.setLayoutParams(params);
}
}
视图间距
➢设置视图的间距有两种方式:
●采用layout_ margin属性,它指定了当前视图与周围平级视图之间的距离。包括layout_ margin、layout_ marginLeft、 layout marginTop、layout. marginRight、layout marginBottom
●采用padding属性,它指定了当前视图与内部下级视图之间的距离。包括padding、 paddingLef采用填充属性,它指定了当前视图与内部下级视图之间的距离.包括填充、填充Left、paddingTop、 paddingRight、 paddingBottom
![](https://i-blog.csdnimg.cn/blog_migrate/4f883545d7fbfd7d93da0a63fa128a9a.png)
对齐方式
![](https://i-blog.csdnimg.cn/blog_migrate/179cc023960b2bc251bb3b67da45cd89.png)
3.常用布局
线性布局LinearLayout
线性布局内部的各视图有两种排列方式
orientation属性值为horizontal时,内部视图在水平方向从左往右排列
orientation属性值为vertical时,内部视图在垂直方向从上往下排列
不指定属性时默认水平
线性布局的权重
指的是线性布局的下级视图各自拥有多大比例的宽高
layout_width填0dp时,layout_weight表示水平方向的宽度比例
layout_height同理
相对布局RelativeLayout
相对布局的下级视图位置由其他视图决定。用于确定下级视图位置的参照物分两种:
与该视图平级的视图
该视图的上级视图
如果不设置下级视图的参照物,那么下级视图默认显示在RelativeLayout内部的左上角。
![](https://i-blog.csdnimg.cn/blog_migrate/d9c3d557216e9a1614ebebedc600d746.png)
GirdLayout
![](https://i-blog.csdnimg.cn/blog_migrate/f7af0dd29cceec56a283b878b9ddc632.png)
滚动视图ScrollView
![](https://i-blog.csdnimg.cn/blog_migrate/4068d523056dbc63fcceb176d76bbf9b.png)
按钮Button
![](https://i-blog.csdnimg.cn/blog_migrate/c04ef6e5fbd65ee6b7f4e3ffc40a31f5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/04440079cdfe1980f7a1f9e358bdca3c.png)
4.按钮触控
![](https://i-blog.csdnimg.cn/blog_migrate/66d41d2730aa8f45fda4c397c630ba2c.png)
1.硬编码,在xml中直接指定点击事件
缺点:高耦合
2.在java代码中实现
a.可以新建一个类来实现接口
b.也可以让当前activity直接implements View.OnClickListener
c.lambda表达式实现匿名内部类.(jdk8以上可以)
以下将这四种方法都实现了
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="在xml中设置槽">
</Button>
<TextView
android:id="@+id/tv_button_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击上面的按钮查看结果"></TextView>
<Button
android:id="@+id/btn_click_single"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="指定单独的点击监听器"></Button>
<TextView
android:id="@+id/tv_click_single_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击上面的按钮查看结果"></TextView>
<Button
android:id="@+id/btn_click_public"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="指定公共的点击监听器"></Button>
<TextView
android:id="@+id/tv_click_public_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击上面的按钮查看结果"></TextView>
<Button
android:id="@+id/btn_click_lambda"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="指定匿名内部内的长按点击监听器"></Button>
<TextView
android:id="@+id/tv_click_lambda_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击上面的按钮查看结果"></TextView>
</LinearLayout>
package com.example.helloworld;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.example.helloworld.util.DateUtil;
public class MainActivity_Button extends AppCompatActivity implements View.OnClickListener {
private TextView tv_button_result;
private TextView tv_click_single_result;
private TextView tv_click_public_result;
private TextView tv_click_lambda_result;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_button);
tv_button_result = findViewById(R.id.tv_button_result);
tv_click_single_result = findViewById(R.id.tv_click_single_result);
Button btn_click_single = findViewById(R.id.btn_click_single);
btn_click_single.setOnClickListener(new MyOnClickListener(tv_click_single_result)); //需要一个监听接口,点击后实例化一个对象,执行onClick
//MyOnClickListener是一个静态内部类,而tv_click_single_result不是静态,因此要传值
tv_click_public_result = findViewById(R.id.tv_click_public_result);
Button btn_click_public = findViewById(R.id.btn_click_public);
btn_click_public.setOnClickListener(this); //this是当前activity的实例 ,使当前activity实例implements View.OnClickListener,实现接口
tv_click_lambda_result = findViewById(R.id.tv_click_lambda_result);
Button btn_click_lambda = findViewById(R.id.btn_click_lambda);
btn_click_lambda.setOnLongClickListener(view -> {
String desc = String.format("%s 您点击了按钮:%s", DateUtil.getNowTime(), ((Button) view).getText());
tv_click_lambda_result.setText(desc);
return true;
});
}
public void doClick(View view) {
String desc = String.format("%s 您点击了按钮:%s", DateUtil.getNowTime(), ((Button) view).getText());
tv_button_result.setText(desc);
}
@Override
public void onClick(View view) {
//如果有多个按钮都执行这个方法,为了区分不同按钮,要用if语句判断
if (view.getId() == R.id.btn_click_public) {
String desc = String.format("%s 您点击了按钮:%s", DateUtil.getNowTime(), ((Button) view).getText());
tv_click_public_result.setText(desc);
}
}
//创建一个类实现接口,实例化类
//设置为静态类,防止内存泄漏
static class MyOnClickListener implements View.OnClickListener {
private final TextView tv_click_single_result;
//构造方法
public MyOnClickListener(TextView tv_click_single_result) {
this.tv_click_single_result = tv_click_single_result;
}
@Override
public void onClick(View view) {
String desc = String.format("%s 您点击了按钮:%s", DateUtil.getNowTime(), ((Button) view).getText());
tv_click_single_result.setText(desc);
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/57e7accf0898b3b0f9c91e456756a9f4.png)
按钮的禁用与恢复
![](https://i-blog.csdnimg.cn/blog_migrate/83d45889a92c6ee7990d0ebab41678f0.png)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_enable"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="启用测试按钮"
android:textSize="17sp"/>
<Button
android:id="@+id/btn_disable"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="禁用测试按钮"
android:textSize="17sp"/>
</LinearLayout>
<Button
android:id="@+id/btn_test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试按钮"
android:textColor="#888888"
android:textSize="17sp"
android:enabled="false"/>
<TextView
android:id="@+id/tv_result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="查看点击结果"
android:textColor="#000000"
android:textSize="17sp"/>
</LinearLayout>
package com.example.helloworld;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.example.helloworld.util.DateUtil;
public class MainActivity_button_enable extends AppCompatActivity implements View.OnClickListener{
private Button btn_test;
private Button btn_disable;
private TextView tv_result;
private Button btn_enable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_button_enable);
btn_enable=findViewById(R.id.btn_enable);
btn_disable = findViewById(R.id.btn_disable);
btn_test= findViewById(R.id.btn_test);
tv_result= findViewById(R.id.tv_result);
btn_enable.setOnClickListener(this);
btn_disable.setOnClickListener(this);
btn_test.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch(view.getId()){
case R.id.btn_enable:
btn_test.setEnabled(true);
btn_test.setTextColor(Color.BLACK);
break;
case R.id.btn_disable:
btn_test.setEnabled(false);
btn_test.setTextColor(Color.GRAY);
break;
case R.id.btn_test:
String desc = String.format("%s 您点击了按钮:%s", DateUtil.getNowTime(), ((Button) view).getText());
tv_result.setText(desc);
break;
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/4e74fa96e7c84e701ee9d05dbe3ec58f.png)
5.图像显示
![](https://i-blog.csdnimg.cn/blog_migrate/b55d4acf2caea117434ba426493872d7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ecdd1843f188417b82a0512b0c69c57c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/cdb058dc2fe90e878fec8e4b6233d0f6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/035476fbe4f6a3e5db652d48f5826738.png)