首页 > 其他分享 >安卓学习

安卓学习

时间:2024-09-01 14:37:23浏览次数:10  
标签:onCreate 安卓 学习 override Activity fun 权限 super

项目结构

MyAndroidProject/
├── build.gradle 
├── settings.gradle
├── gradle/
├── app/
│   ├── build.gradle
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/  存放 Java 或 Kotlin 源代码,按包名结构组织。
│   │   │   ├── res/   存放资源文件
│   │   │   ├── AndroidManifest.xml 应用的清单文件,声明应用的组件和权限。
│   │   ├── test/
│   │   └── androidTest/  存放 Android 仿真器和设备上运行的测试代码。
└── gradle/wrapper/
  • build.gradle:项目级的 Gradle 构建文件,用于配置整个项目的构建设置。
  • settings.gradle:用于包含多个模块的设置。
  • gradle:存放 Gradle Wrapper 的脚本和配置文件。

简单使用

这里直接通过分析示例代码来讲述如何简单编写一个安卓程序。

class MainActivity : ComponentActivity() {  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        enableEdgeToEdge()  
        setContent {  
            HelloWorldTheme {  
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->  
                    Greeting(  
                        name = "Android",  
                        modifier = Modifier.padding(innerPadding)  
                    )  
                }  
            }        }    }  
}  
  

onCreate() 函数是此应用的入口点,可以简单理解为C语言的main函数。其中的setContent() 函数用于通过可组合函数定义布局。任何标有 @Composable 注解的函数都可通过 setContent() 函数或其他可组合函数进行调用。

注意:

  • @Composable 函数名称采用首字母大写形式。
  • 需在该函数前面添加 @Composable 注解。
  • @Composable 函数无法返回任何内容。
@Composable  
fun Greeting(name: String, modifier: Modifier = Modifier) {  
    Text(  
        text = "Hello $name!",  
        modifier = modifier  
    )  
}  
  
@Preview(showBackground = true)  
@Composable  
fun GreetingPreview() {  
    HelloWorldTheme {  
        Greeting("Android")
    }  
}

日志使用

为什么使用日志

很多人会非常喜欢使用System.out.println()方法来打印日志,在Kotlin中使用与之对应的是println()方法,在真正的项目开发中,是极度不建议使用System.out.println()或println()方法的,如果你在公司的项目中经常使用这两个方法来打印日志的话,就很有可能要挨骂了。那缺点在哪儿了呢?这个就太多了,比如日志开关不可控制、不能添加日志标签、日志没有级别区分等。

简单使用

Android中的日志工具类是Log(android.util.Log),这个类中提供了如下5个方法来供我们打印日志:

  • Log.v()。用于打印那些最为琐碎的、意义最小的日志信息。对应级别verbose,是Android日志里面级别最低的一种。
  • Log.d()。用于打印一些调试信息,这些信息对你调试程序和分析问题应该是有帮助的。对应级别debug,比verbose高一级。Log.i()。用于打印一些比较重要的数据,这些数据应该是你非常想看到的、可以帮你分析用户行为的数据。对应级别info,比debug高一级。
  • Log.w()。用于打印一些警告信息,提示程序在这个地方可能会有潜在的风险,最好去修复一下这些出现警告的地方。对应级别warn,比info高一级。
  • Log.e()。用于打印程序中的错误信息,比如程序进入了catch语句中。当有错误信息打印出来的时候,一般代表你的程序出现严重问题了,必须尽快修复。对应级别error,比warn高一级。

四大核心组件

在 Android 应用开发中,有四大核心组件,它们分别是:

  • Activity:
    代表用户界面的单一屏幕,负责与用户交互。
    可以启动其他 Activity 以创建多屏幕应用。
  • Service:
    在后台运行的组件,不提供用户界面。
    用于执行长时间运行的操作或处理后台任务,例如播放音乐或下载文件。
  • Broadcast Receiver:
    用于接收和处理广播消息(如系统或应用程序的事件)。
    允许应用在特定事件发生时响应,例如网络状态变化或电池电量变化。
  • Content Provider:
    提供应用间的数据共享机制。
    允许一个应用访问另一个应用的数据(如联系人、媒体等),并管理对这些数据的访问。

Activity使用

Activity是一个单一的界面,用户可以在该界面与应用进行交互。每个Activity通常代表应用中的一个屏幕。
Activity有一组生命周期方法,帮助开发者管理其状态和行为。常见的生命周期方法包括:

  • onCreate(): 初始化Activity时调用,设置布局等。
  • onStart(): Activity即将变为可见时调用。
  • onResume(): Activity已可见并与用户交互时调用。
  • onPause(): Activity即将进入不可见状态时调用。
  • onStop(): Activity已不可见时调用。
  • onDestroy(): Activity即将被销毁时调用,清理资源

代码示例

  
class MainActivity : AppCompatActivity() {  
  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        setContentView(R.layout.first_layout)  
  
        // 初始化界面元素  
        val textView: TextView = findViewById(R.id.textView)  
        textView.text = "欢迎来到我的应用!"  
    }  
  
    override fun onStart() {  
        super.onStart()  
        // Activity即将可见  
    }  
  
    override fun onResume() {  
        super.onResume()  
        // Activity已可见并与用户交互  
    }  
  
    override fun onPause() {  
        super.onPause()  
        // Activity即将不可见  
    }  
  
    override fun onStop() {  
        super.onStop()  
        // Activity已不可见  
    }  
  
    override fun onDestroy() {  
        super.onDestroy()  
        // 清理资源  
    }  
}


<?xml version="1.0" encoding="utf-8"?>  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent">  
  
    <TextView        android:id="@+id/textView"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:textSize="24sp"  
        android:layout_centerInParent="true" />  
</RelativeLayout>

Service使用

Service是Android中实现程序后台运行的解决方案,它非常适合执行那些不需要和用户交互而
且还要求长期运行的任务,例如:

  • 下载文件

  • 上传数据

  • 播放音乐

  • 处理网络请求
    在Android的Service类中,有几个重要的方法用于管理服务的生命周期和行为:

  • onCreate():当服务第一次被创建时调用。可以在此方法中进行一次性初始化操作,如创建线程或初始化资源。

  • onStartCommand():每次调用startService()时都会调用此方法。可以在这里处理启动服务时传入的Intent,并执行实际的后台任务。

  • onBind():当其他组件通过bindService()方法绑定到服务时调用。如果服务不支持绑定,可以返回null。

  • onUnbind():当所有客户端都解除绑定时调用,可以在此方法中执行清理工作。

  • onRebind():当新的客户端绑定到已经解绑的服务时调用。

  • onDestroy():当服务被销毁时调用。可以在此方法中释放资源或停止后台任务。

代码示例

  
class MyService : Service() {  
  
    override fun onBind(intent: Intent): IBinder {  
        TODO("Return the communication channel to the service.")  
    }  
    override fun onCreate() {  
        super.onCreate()  
        Log.d("MyService", "onCreate executed")  
    }  
    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {  
        Log.d("MyService", "onStartCommand executed")  
        return super.onStartCommand(intent, flags, startId)  
    }  
    override fun onDestroy() {  
        super.onDestroy()  
        Log.d("MyService", "onDestroy executed")  
    }  
}


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent">  
    <Button        android:id="@+id/startServiceBtn"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="Start Service" />  
    <Button        android:id="@+id/stopServiceBtn"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="Stop Service" />  
</LinearLayout>


  
class MainActivity : AppCompatActivity() {  
    private lateinit var startServiceBtn: Button  
    private lateinit var stopServiceBtn: Button  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        setContentView(R.layout.activity_main)  
        startServiceBtn = findViewById(R.id.startServiceBtn)  
        stopServiceBtn = findViewById(R.id.stopServiceBtn)  
  
        startServiceBtn.setOnClickListener {  
            val intent = Intent(this, MyService::class.java)  
            startService(intent) // 启动Service  
        }  
        stopServiceBtn.setOnClickListener {  
            val intent = Intent(this, MyService::class.java)  
            stopService(intent) // 停止Service  
        }  
    }  
}

Broadcast Receiver使用

为Android中的每个应用程序都可以对自己感兴趣的广播进行注册,这样该程序就只会收到自己所关心的广播内容,这些广播可能是来自于系统的,也可能是来自于其他应用程序的。

  • 隐式广播: 不指定发送广播的组件,只指定意图(Intent)中的动作。适用于大多数系统广播。系统或其他应用发出,接收者不明确指定。
  • 显式广播: 指定特定组件(如某个Activity或Service)来接收广播。程序发出,明确指定接收者。

代码示例

动态注册

动态注册是在代码中注册BroadcastReceiver,通常在Activity或Service的生命周期方法中进行。

class TimeChangeReceiver : BroadcastReceiver() {  
    override fun onReceive(context: Context?, intent: Intent?) {  
        val currentTime = SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(Date())  
        Toast.makeText(context, "Time has changed $currentTime", Toast.LENGTH_SHORT).show()  
    }  
}



import android.content.Intent  
import android.content.IntentFilter  
import android.os.Bundle  
import android.widget.Button  
import android.widget.TextView  
import androidx.appcompat.app.AppCompatActivity  
  
class MainActivity : AppCompatActivity() {  
    private lateinit var startServiceBtn: Button  
    private lateinit var stopServiceBtn: Button  
    private lateinit var timeChangeReceiver: TimeChangeReceiver  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        setContentView(R.layout.activity_main)  
        startServiceBtn = findViewById(R.id.startServiceBtn)  
        stopServiceBtn = findViewById(R.id.stopServiceBtn)  
  
        startServiceBtn.setOnClickListener {  
            val intent = Intent(this, MyService::class.java)  
            startService(intent) // 启动Service  
        }  
        stopServiceBtn.setOnClickListener {  
            val intent = Intent(this, MyService::class.java)  
            stopService(intent) // 停止Service  
        }  
  
        timeChangeReceiver = TimeChangeReceiver()  
    }  
    override fun onStart() {  
        super.onStart()  
        // 注册BroadcastReceiver  
        val filter = IntentFilter(Intent.ACTION_TIME_TICK)  
        registerReceiver(timeChangeReceiver, filter)  
    }  
  
    override fun onStop() {  
        super.onStop()  
        // 注销BroadcastReceiver  
        unregisterReceiver(timeChangeReceiver)  
    }  
}

动态注册的BroadcastReceiver可以自由地控制注册与注销,在灵活性方面有很大的优势。但
是它存在着一个缺点,即必须在程序启动之后才能接收广播,因为注册的逻辑是写在
onCreate()方法中的

静态注册

编写对应的一个逻辑:

class MyReceiver : BroadcastReceiver() {  
  
    override fun onReceive(context: Context, intent: Intent) {  
        Toast.makeText(context, "received in MyBroadcastReceiver",  
            Toast.LENGTH_SHORT).show()  
    }  
}

注意这里需要将其注册进行AndroidManifest.xml文件中

<receiver  
    android:name=".MyReceiver"  
    android:enabled="true"  
    android:exported="true">  
    <intent-filter>        <action android:name="com.example.broadcasttest.MY_BROADCAST"/>  
    </intent-filter></receiver>

这里的

"com.example.broadcasttest.MY_BROADCAST"

即表明他要接收的类型。

  
class MainActivity : AppCompatActivity() {  
    private lateinit var button: Button  
  
  
  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        setContentView(R.layout.activity_main)  
        button=findViewById(R.id.button)  
        button.setOnClickListener {  
            val intent = Intent("com.example.broadcasttest.MY_BROADCAST")  
            intent.setPackage(packageName)  
            sendBroadcast(intent)  
        }  
  
    }  
  
}

这样即可实现

ContentProvider使用

Content Provider是Android应用中的一种组件,用于管理和共享应用数据。它为其他应用提供了一种安全的、标准化的方式来访问数据。、

在业务中承担的角色:

  • 数据共享: 允许一个应用访问另一个应用的数据,这对于多应用之间的数据交互非常重要。
  • 抽象数据存储: 提供统一的接口来访问不同类型的数据源,如SQLite数据库、文件系统或网络。
  • 安全性: 通过权限控制,确保只有授权的应用才能访问特定的数据。

ContentProvider的用法一般有两种:一种是使用现有的ContentProvider读取和操作相应程
序中的数据;另一种是创建自己的ContentProvider,给程序的数据提供外部访问接口。

权限处理

在我们读取其他数据之前,我们首先要处理的是权限的问题。比如我们读取照片和电话信息时,app都会跳出对应的弹窗要求我们授予对应的权限。

流程可以大概分为:

  • 在Manifest中声明权限。
  • 检查是否已获得权限。
  • 如果未获得权限,申请权限。
  • 处理用户的授权结果。

声明权限

我们首先要声明权限,即安装时就要求拥有的权限.

<uses-permission android:name="android.permission.READ_CONTACTS" />

检查权限

这里要使用的函数为checkSelfPermission函数

public static int checkSelfPermission(@NonNull Context context, @NonNull String permission)

参数

  • context: 当前的上下文,通常是 Activity 或 Application。
  • permission: 要检查的权限字符串,例如 Manifest.permission.CAMERA。

返回值

  • 返回 PackageManager.PERMISSION_GRANTED (值为 0) 表示权限已获得。
  • 返回 PackageManager.PERMISSION_DENIED (值为 -1) 表示权限未获得。

申请权限

public void requestPermissions(@NonNull String[] permissions, int requestCode)

参数

  • permissions: 一个字符串数组,包含要请求的权限。
  • requestCode: 一个整型值,用于标识这个请求,以便在回调中处理。

处理授权结果

当用户做出权限选择后,系统会调用这个方法。

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
  • requestCode: 之前传递的请求代码。
  • permissions: 请求的权限数组。
  • grantResults: 权限请求的结果数组,其中每个元素对应于 permissions 数组的元素,值为 PackageManager.PERMISSION_GRANTED 或 PackageManager.PERMISSION_DENIED。

完整代码示例

package com.example.permissionexample

import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat

class MainActivity : AppCompatActivity() {

    private val REQUEST_PHONE_PERMISSION = 1

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        checkAndRequestPhonePermission()
    }

    private fun checkAndRequestPhonePermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
            // 权限已获得
            Toast.makeText(this, "权限已获得", Toast.LENGTH_SHORT).show()
        } else {
            // 请求权限
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CALL_PHONE), REQUEST_PHONE_PERMISSION)
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        if (requestCode == REQUEST_PHONE_PERMISSION) {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 用户已同意权限
                Toast.makeText(this, "用户同意权限", Toast.LENGTH_SHORT).show()
            } else {
                // 用户拒绝权限
                Toast.makeText(this, "用户不同意权限", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

读取数据

基本方法

这里我们使用的ContentResolver,来进行对应的CRUD:

  • 查询数据: 使用 query() 方法从 ContentProvider 获取数据。
  • 插入数据: 使用 insert() 方法向 ContentProvider 添加新数据。
  • 更新数据: 使用 update() 方法修改 ContentProvider 中的现有数据。
  • 删除数据: 使用 delete() 方法从 ContentProvider 移除数据。
contentResolver.query(uri, null, null, null, null)

参数:

  • uri: 要查询的内容 URI。
  • projection: 要返回的列名数组(可为 null,表示返回所有列)。
  • selection: 选择条件(WHERE 子句,或 null)。
  • selectionArgs: 选择条件的参数数组(或 null)。
  • sortOrder: 排序顺序(或 null)。

对于结果的处理,我们这里使用Cursor,来实现结果的梳理:

  • 遍历结果: 使用 moveToNext() 方法移动到下一行。
  • 获取列值: 使用 getString()、getInt() 等方法获取特定列的数据。
  • 获取列索引: 使用 getColumnIndex() 方法根据列名获取列的索引。
  • 资源管理: 提供 close() 方法以释放相关资源。

代码示例

val contentResolver: ContentResolver = contentResolver   //创建ContentValues 实例 
val uri: Uri = ContactsContract.Contacts.CONTENT_URI  //
val cursor: Cursor? = contentResolver.query(uri, null, null, null, null)

cursor?.use {  
    val nameIndex = it.getColumnIndex(ContactsContract.Contacts.CONTACT_STATUS)  
    while (it.moveToNext()) {  //将光标移动到下一行。如果还有行可供访问,返回 true,否则返回 false。
        val name = it.getString(nameIndex)  
        // 显示联系人名称  
        Toast.makeText(this, "联系人: $name", Toast.LENGTH_SHORT).show()  
    }  
}

这里使用了getColumnIndex方法,使用列名ContactsContract.Contacts.CONTACT_STATUS来获取对应的一个索引。

参考链接

https://developer.android.com/codelabs/basic-android-kotlin-compose-first-app?continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fandroid-basics-compose-unit-1-pathway-2%23codelab-https%3A%2F%2Fdeveloper.android.com%2Fcodelabs%2Fbasic-android-kotlin-compose-first-app&%3Bhl=zh-cn&hl=zh-cn#4

标签:onCreate,安卓,学习,override,Activity,fun,权限,super
From: https://www.cnblogs.com/Ho1dF0rward/p/18391264

相关文章

  • 学习笔记 ---- 基环树
    目录算法解析基环树与基环森林模板例题[NOIP2018提高组]旅行[ZJOI2008]骑士[IOI2008]IslandLongWaytobeNon-decreasing算法解析基环树与基环森林基环树是指有且仅有一个环的树。基环森林是指若干棵基环树构成的森林。对于有向图,基环树可分为内向基环树和外向基环......
  • MVC与设计模式理解-lnmp学习之路
    一、MVC前言:        MVC是一种应用架构模式,也可以说是一种业务架构或是一种应用设计思想,用于组织业务逻辑并分离代码的。        MVC组成结构是Model-View-Controller,Model是管控数据层,View是管控视图层,Controller是管控业务逻辑层。举例:       ......
  • 深度学习_模型调用预测
    概要应用场景:用户流失本文将介绍模型调用预测的步骤,这里深度学习模型使用的是自定义的deepfm代码导包importpandasaspdimportnumpyasnpimportmatplotlib.pyplotaspltimportseabornassnsfromcollectionsimportdefaultdictfromscipyimportstat......
  • jsp艾宾浩斯遗忘曲线的单词学习系统xttc1
    jsp艾宾浩斯遗忘曲线的单词学习系统xttc1本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能用户,学习计划,课程类型,课程信息,学习进度,词汇,复习提醒开题报告内容一、项目背景与意义随着全球化的深......
  • spring学习日记-day5-代理模式
    一、学习目标        代理模式是一种常用的设计模式,它主要用于在不修改原有对象代码的情况下,通过引入一个代理对象来控制对原有对象的访问,从而增强原有对象的功能。代理模式主要分为两种:静态代理和动态代理。尽管Spring框架本身更多地利用了动态代理来实现其功能,但理......
  • 开学第一周9.1周日学习日记
    算法cf1989ABCDhttps://codeforces.com/contest/1989B最长公共子序列 //相当于枚举以b[i]为起点遍历a的最长公共子序列 //因为是子序列所以abacccab即使后面先取了第一个a也不影响最长长度#include<bits/stdc++.h>usingnamespacestd;voidsolve() { stringa......
  • 【GRNN-RBFNN-ILC算法】【轨迹跟踪】基于神经网络的迭代学习控制用于未知SISO非线性系
     ......
  • 【GRNN-RBFNN-ILC算法】【轨迹跟踪】基于神经网络的迭代学习控制用于未知SISO非线性系
     ......
  • SSM框架学习!~~~一篇文章就够了!
    详细解释SSM框架SSM框架是Spring、SpringMVC和MyBatis框架的整合,它遵循标准的MVC(Model-View-Controller)设计模式,旨在提高JavaWeb开发的效率和可维护性。下面将详细解释SSM框架的各个组成部分及其作用。Spring框架概述:Spring框架是一个开源的、全面的企业级应用开发框......
  • 数组更加深入的学习
    1.浅了解java数组原理可以形象的认为java中有“栈”和“堆”这两个东西,栈用于存放声明的数组,而堆则用于存放数组的赋值刚声明完的数组没有任何作用,必须要对其赋值才有意义2.数组的三种初始化静态初始化:将数组的值在声明时提前写好并且值固定不变动态初始化:声明并创建完数组......