Android 开发实战

2024-03-21 王汪旺
Android 移动开发 Java

Android 特征

  • 开放性

  • 挣脱束缚

  • 丰富的硬件平台

  • 不受限制

  • 使用 Google 资源

Android 平台架构

  • 系统应用层

  • 接口框架层

  • 系统运行库层

  • 硬件抽象层

  • Linux 内核层

项目结构介绍

.
├── .idea/              # 存放开发所需的相关配置文件,由系统自动生成
├── app/                # 存放项目源代码、资源以及其他相关文件
│   ├── build/
│   ├── libs/
│   └── src/
│       ├── AndroidTest/
│       └── main/
│           ├── java/
│           └── res/    # 存放页面相关的资源文件
│               ├── drawable/   # 存放图片
│               ├── layout/     # 存放布局文件
│               ├── mipmap/     # 存放各种分辨率的图标资源
│               └── values/     # 存放颜色、字符串和样式等资源文件
└── gradle/             # 存放 gradle 配置文件

LogCat 运行测试

log 测试类衍生出 6 个日志等级和 5 个静态方法

// Verbose
Log.v(TAG, "message");

// Debug
Log.d(TAG, "message");

// Info
Log.i(TAG, "message");

// Warning
Log.w(TAG, "message");

// Error
Log.e(TAG, "message");

// Assert
// ...

控件部分

EditText

常用属性和方法

XML 属性:

android:hint="显示的提示文本信息"
android:lines="设置固定行数"
android:inputType="指定输入类型"  <!-- textPassword/numberPassword/number/phone/datetime -->
android:textSize="20sp"  <!-- 推荐单位 sp -->

常用方法:

getText()
setText()
setTextSize()
setTextColor()

Button

  • 点击事件

DatePicker

XML 属性:

android:calendarViewShown="true/false"  <!-- 是否显示日历 -->
android:startYear="2020"  <!-- 设置开始年份范围(可选) -->
android:endYear="2025"    <!-- 设置截止年份(可选) -->
android:maxDate="..."     <!-- 设置最大日期(可选) -->
android:minDate="..."     <!-- 设置最小日期(可选) -->

常用方法:

getYear()
getMonth() + 1  // 月方法从 0 月起始,需要+1
getDayOfMonth()  // 获取所选择的日

意图 (Intent)

意图(Intent)是一种用于在应用组件(如活动、服务和广播接收器)之间传递信息的机制。意图可以是显式的,也可以是隐式的,作用是启动组件并传递相关的数据。

显式意图

创建与跳转:

// 1. 创建意图
Intent intent = new Intent(MainActivity.this, NextActivity.class);
// 2. 指定动作行为
intent.setAction();
// 3. 启动活动
startActivity(intent);

数据传递:

// 向下传递数据
intent.putExtra("key", "value");  // 存放数据

// 在目标意图中获取数据
String value = getIntent().getStringExtra("key");
int value = getIntent().getIntExtra("key", 0);  // 默认值为 0
boolean value = getIntent().getBooleanExtra("key", false);

// 向上返回数据
// 1. 启动时使用
startActivityForResult(intent, REQUEST_CODE);

// 2. 重写回调方法
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
        String result = data.getStringExtra("key");
        // 使用返回的数据
    }
}

// 3. 在目标活动中返回数据
Intent resultIntent = new Intent();
resultIntent.putExtra("key", "value");  // 返回的数据
setResult(RESULT_OK, resultIntent);     // 设置结果
finish();                               // 结束当前 Activity

隐式意图

// 创建和跳转
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.baidu.com"));
startActivity(intent);

布局

LinearLayout

默认控件位置在布局的左上角

常用属性:

<!-- 指定控件排列方向 -->
android:orientation="vertical|horizontal"

<!-- 控件在布局中的对齐方式 -->
android:layout_gravity="top|center_vertical|bottom|left|center_horizontal|right"

<!-- 允许控件使用比例方式控制大小 -->
android:layout_weight="1"

<!-- 外边距 -->
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_margin="10dp"

<!-- 内边距,参考外边距 -->
android:padding="10dp"

RelativeLayout

默认控件位置在布局的左上角

常用属性:

android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_centerInParent="true"
android:layout_above="@id/other_view"
android:layout_below="@id/other_view"
android:layout_toLeftOf="@id/other_view"
android:layout_toRightOf="@id/other_view"
android:layout_alignTop="@id/other_view"
android:layout_alignBottom="@id/other_view"
android:layout_alignLeft="@id/other_view"
android:layout_alignRight="@id/other_view"

FrameLayout

FrameLayout 是一个简单的布局,它将其中的组件放置在自己的 "左上角" 位置,默认情况下,所有子视图都会叠加在一起。

Android 样式设计

  1. stroke:定义边框
  2. solid:定义填充
  3. corners:定义圆角半径

主题和样式发生冲突时优先样式

组件

Toast

// 创建
Toast.makeText(context, "提示信息", Toast.LENGTH_SHORT).show();

// 设置位置
toast.setGravity(Gravity.CENTER, 0, 0);  // 让提示居中,偏移为0

// 设置边距
toast.setMargin(float x, float y);  // 提示的x和水平轴的边距

Dialog

// 构造器
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);

// 常见方法
builder.setIcon(R.drawable.icon)
       .setTitle("标题")
       .setMessage("设置 dialog 的内容")
       .setPositiveButton("确定", new DialogInterface.OnClickListener() {
           @Override
           public void onClick(DialogInterface dialog, int which) {
               // 处理确定按钮点击
           }
       })
       .setNegativeButton("取消", listener)
       .setNeutralButton("忽略", listener)
       .setSingleChoiceItems(列表, 默认选项下标, 监听器回调函数)
       .setMultiChoiceItems(列表, 默认选项下标, 监听器回调函数);

// 创建并显示
builder.create().show();
// 创建并显示
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // 加载菜单布局
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

// 添加响应事件
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // 处理菜单项点击
    return super.onOptionsItemSelected(item);
}

Spinner

初识适配器

常用适配器: 1. ArrayAdapter:数组适配器(由 map 封装) 2. SimpleAdapter:简单适配器 3. SimpleCursorAdapter:简单游标适配器

// 填充数据方法
spinner.setAdapter(adapter);

// 选择监听
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        // Spinner 选项被选中时执行
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {
        // Spinner 下拉选项未被选中的处理
    }
});

数据适配器 RecyclerView.Adapter

布局管理器

// 1. 线性布局
LinearLayoutManager layoutManager = new LinearLayoutManager(this);

// 2. 网格布局
GridLayoutManager layoutManager = new GridLayoutManager(this, 2);  // 2列

// 3. 瀑布流布局
StaggeredGridLayoutManager layoutManager = 
    new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);

重写方法

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    // 创建 ViewHolder
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    // 绑定数据
}

@Override
public int getItemCount() {
    return dataList.size();  // 通过 size() 方法获得数据源的长度
}

布局管理器绑定

LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);

媒体播放器

音乐

MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.reset();
mediaPlayer.setDataSource(FilePath);
mediaPlayer.prepare();
mediaPlayer.start();

视频

// 初始化控制柄
private MediaController mediaController;
mediaController = new MediaController(this);

// 绑定控制柄和控件
VideoView myVideoView = findViewById(R.id.my_videoview);
myVideoView.setMediaController(mediaController);

数据存储

SharedPreferences

// 创建 Editor
SharedPreferences.Editor editor = getSharedPreferences("myinfo", 0).edit();

// 存放数据
editor.putString("name", "Tom");
editor.putBoolean("married", false);
editor.putFloat("weight", 78.8f);
editor.putLong("birthday", 15467204391L);

// 获取数据
String name = getSharedPreferences("myinfo", 0).getString("name", null);

// 删除数据
editor.remove("name");      // 删除单个数据
editor.clear();            // 删除所有数据

// 提交/保存数据
editor.commit();

文件存储

// 数据写入文件
FileOutputStream out = openFileOutput("FileName", 0);
out.write(text.toString().getBytes());
out.close();

// 读取文件
FileInputStream in = openFileInput("FileName");
byte[] arr = new byte[in.available()];
in.read(arr);
in.close();

外部存储

// 判断外部设备是否可用
Environment.getExternalStorageState();

// 获取 SD 卡目录
Environment.getExternalStorageDirectory();

SQLite

SQLiteOpenHelper 类

// 创建数据库
@Override
public void onCreate(SQLiteDatabase db) {
    // 创建表等操作
}

// 更新数据库
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    // 更新数据库结构
}

// 获取数据库对象
SQLiteDatabase db = helper.getWritableDatabase();  // 读写操作
SQLiteDatabase db = helper.getReadableDatabase();  // 只读操作

数据表操作

// 初始化
private MyDBOpenHelper myhelper;
private SQLiteDatabase db;
db = myhelper.getWritableDatabase();

// 插入
ContentValues row = new ContentValues();
row.put("sno", "学号");
row.put("sname", "TOM");
row.put("sex", "man");
db.insert("tableName", null, row);

// 查询
Cursor cursor = db.rawQuery("SELECT * FROM tablename WHERE no = ?", 
    new String[]{"学号"});
while(cursor.moveToNext()) {
    String sname = cursor.getString(cursor.getColumnIndex("no"));
    // ...
}

// 更新
ContentValues row = new ContentValues();
row.put("sno", "学号");
row.put("sname", "姓名");
db.update("表名", row, "sno=?", new String[]{"学号"});

网络请求

【---】