笔记:Android 起步Activity

1. .gradle 和 .idea
这两个目录下放的是Android Studio 自动生成的一些文件
2. app
项目中的代码、资源等都放在这个文件夹
(1).build
和外层的build类似,主要包含在编译时自动生成的文件
(2).libs
项目中使用的第三方jar包,放在这个文件夹下的jar包都会自动添加到构建路径里去
(3).androidTest
此处是用来编写Android Test 测试用例的,可以对项目进行一些自动化测试
(4).java
放置编写的代码的地方
(5).res
项目中使用的所有图片、布局、字符串等资源都放在这个文件夹下,图片放在drawable目录下、布局放在layout目录下、字符串放在value目录下,所有mipmap开头的文件都是来放应用图标的(之所以有这么多mipmap文件是为了让程序兼容各种设备(分辨率不同))。
(6).AndroidManifest.xml
这是整个Android项目的配置文件,在程序中指定的所有四大组件都需要放在这个文件里注册,另外还可以在这个文件中给应用程序添加程序声明
(7).test
用于编写Unit Test 测试用例的,是对项目进行自动化测试的另一种方式
(8). .gitgnore
将app模块中指定的目录或文件夹排除在版本控制之外
(9).app.iml
IDEA 自动生成
(10).build.gradle
这是app模块的gradle构建脚本,这个文件中会指定很多项目构建相关的配置
(11).proguard-rules.pro
这个文件用于指定项目代码的混淆规则,当代码开发完成之后打成安装包文件,如果不希望代码被破解,通常会将代码进行混淆

3. build
包含一些编译时自动生成的文件
4. gradle
包含 gradle wrapper 的配置文件
5. .gitigonre
将指定的目录或文件排除在版本控制之外
6. build.gradle
项目全局的gradle构建脚本
7. gradle.properties
全局的 gradle 配置文件,在这里配置的属性将会影响到项目中的所有的gradle编译脚本
8. gradlew 和 gradlew.bat
这两个文件是用来在命令行界面中执行gradle命令的,其中gradlew 是在Linux 或 Mac系统中使用的,gradlew.bat 是在Windoes系统中使用的
9. local.properties
用于指定本机中的 Android SDK 路径,通常内容都是自动生成,除非本机中的Android SDK 位置发生了变化,否则不需要修改
10. setting.gradle
这个文件用于指定项目中所有引入的模块,因为新建的这个项目只有一个app模块,所以文件中只引入了app这一个模块,通常情况下模块引入是自动完成的。

		<activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

这是对 MainActivity 这个活动进行注册,没有注册的活动是不能进行使用的,intent-filter中的两行代码表示这个是主活动,在手机点击应用图标,首先启动的就是这个活动

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

MainActivity 继承于AppCompatActivity ,这是一种向下兼容的 Activity 最低兼容到Android2.1系统(AppCompatActivity 是 Activity 的子类),setContentView 方法给当前的活动引入了一个布局 activity_main

  • 在代码中通过 R.string.app_name 可以获得该字符串的引用
  • 在XML中通过 @String/app_name 可以获得该字符串的引用
    如果引用图片资源将string替换成 drawable 引用图标替换成 mipmap 引用布局替换成 layout,以此类推

build.gradle文件

最外层的 build.gradle 文件是项目的全局构建配置

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        google()
//        jcenter()
        maven{ url'http://maven.aliyun.com/nexus/content/groups/public/' }
        maven{ url'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.0.0"
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
allprojects {
    repositories {
        google()
//        jcenter()
        maven{ url'http://maven.aliyun.com/nexus/content/groups/public/' }
        maven{ url'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

buildScript块 主要是为了Gradle脚本自身的执行,获取脚本依赖插件。
allprojects块 用于项目构建,为所有项目提供共同所需依赖。

两处 repositories 闭包都声明了jcenter(),jcenter()是一个代码托管仓库,由谷歌提供需要翻墙,这里可以配置成阿里云的镜像仓库
dependencies 闭包中使用 classpath 声明了一个Gradle插件,因为Gradle不是专门为Android项目开发的,Java、C++等很多项目都可以使用Gradle构建,如果想使用它来构建Androd项目,就要添加com.android.tools.build:gradle来兼容


apply plugin: 'com.android.application'

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.1"

    defaultConfig {
        applicationId "com.example.helloworld"
        minSdkVersion 16
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

}

apply plugin: 应用了一个插件,一般有两种值可选:com.android.application(表示这是一个应用程序模块)com.android.library(表示这是一个库模块),应用程序模块是可以直接执行的。库模块只能依附于应用程序模块来运行
android的闭包,在这个闭包中可以配置项目构建的各种属性
compileSdkVersion 表示项目编译的版本
buildToolsVersion 表示项目构建工具的版本
然后嵌套了一个defaultConfig 闭包,defaultConfig 闭包可以对项目中的更多细节进行配置
applicationId用于指定项目的包名
minSdkVersion 指定项目最低兼容的Android系统版本 15 表示最低兼容到Android4.0系统
targetSdkVersion 指定的值表示在该版本上已经做过了充分的测试,系统将会为应用程序启动一些新的功能和特性
versionCode 指定项目的版本号
versionName 指定项目版本名称
在下面有嵌套了一个buildTypes 闭包,buildTypes 闭包用于指定生成安装文件的配置,通常会有两个常见的子闭包,一个是debug一个是release, debug用于指定生成测试版安装文件的配置,release 用于指定生成正式版安装文件的配置
minifyEnabled 用于指定是否对项目的代码进行混淆
proguardFiles 用于指定混淆时使用的规则文件,proguard-android-optimize.txt是在Android SDK 目录下,里面是所有项目通用的混淆规则,proguard-rules.pro是在当前项目的目录下的,里面可以编写挡墙项目特有的混淆规则
最后dependencies 闭包是指定当前项目所有的依赖关系,一般有3中依赖方式:本地依赖、库依赖、远程依赖


Android 日志工具

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

  • Log.v():(verbose)用于打印最琐碎,意义最小的日志信息,是Android 日志里级别最低的一种
  • Log.d():(debug)用于打印调试信息,这些信息对调试程序和分析问题有帮助
  • Log.i():(info)打印一些比较重要的数据,这些数据可以帮你分析用户行为数据
  • Log.w():(warn)打印一些警告信息,提示程序有潜在的风险,需要去修复
  • Log.e():(error)打印程序中的错误信息,表示程序出现严重错误,尽快修复
    在这里插入图片描述

活动Activaty

可以使用android:label="This is MainActivity" 指定活动中标题栏的内容,注意指定活动的 label 不仅会成为标题栏的内容,还会成为启动器(Launcher)中应用程序显示的名称

Toast

Toast是android系统提供的一个提醒方式,通过 makeText() 创建出一个 Toast,然后调用 show() 将Toast 显示出来,makeText() 需要三个参数:Context、显示的文本内容,显示的时长(Toast.LENGTH_SHORT 和 Toast.LENGTH_LONG)

Toast.makeText(MainActivity.this, "你点击了按钮", Toast.LENGTH_SHORT).show();
Menu

在res目录下新建一个 menu 文件夹,在文件夹中新建 main 的菜单文件 New——Menu resource file

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/add_item"
        android:title="Add"/>
    <item
        android:id="@+id/remove_item"
        android:title="Remove"/>
</menu>

Ctrl+o重写 onCreateOptionsMenu 方法 getMenuInflater() 方法可以获得 MenuInflater 对象,再调用 inflate() 方法就可以创建当前活动的菜单,inflate() 接收两个参数,一个是菜单的资源文件,一个是将菜单添加到哪一个 Menu 对象,返回 true 表示允许菜单显示出来

 	@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

重写 onOptionsItemSelected() 方法定义菜单响应事件

@Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case R.id.add_item:
                Toast.makeText(MainActivity.this, "你点击了Add", Toast.LENGTH_SHORT).show();
                break;
            case R.id.remove_item:
                Toast.makeText(MainActivity.this, "你点击了Remove", Toast.LENGTH_SHORT).show();
                break;
            default:
                break;
        }
        return true;
    }
销毁一个活动

finish() 方法,和手机上按下 Back 键是一样的

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        finish();
    }
Intent

一般用于启动活动,启动服务以及发送广播,大致分为两种:隐式Intent显式Intent
显式Intent

button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "你点击了按钮", Toast.LENGTH_SHORT).show();
                Intent intent = new Intent(MainActivity.this, FristActivity.class);
                startActivity(intent);
            }
        });

隐式Intent
通过在标签下配置可以指定当前活动能够相应的 action 和 category

		<activity android:name=".FristActivity"
            android:label="This is FristActivity">
            <intent-filter>
                <action android:name="com.example.helloworld.fristactivity"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

指明了当前活动可以相应 则包含了一些附加信息,只有action 和 category同时满足,这个活动才能相应Intent
android.intent.category.DEFAULT 是一种默认的 category,在调用 startActivity() 时会自动将这个category添加到 Intent 中

	button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("com.example.helloworld.fristactivity");
                startActivity(intent);
            }
        });

每个 Intent 只能指定一个 action,但能指定多个 category ,通过下面代码添加

intent.addCategory("com.example.helloworld.mycategory");
// 同时在AndroidManifest.xml 中添加
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="com.example.helloworld.mycategory"/>

隐式的 Intent 还可以用来启动其他的应用程序的活动,比如打开一个网页

		button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "你点击了按钮", Toast.LENGTH_SHORT).show();
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setData(Uri.parse("http://www.baidu.com"));
                startActivity(intent);
            }
        });

Intent.ACTION_VIEW 是Android 系统内置的动作,常量为 android.intent.action.VIEW,然后通过 Uri.parse() 方法将一个网址字符串解析成一个Uri对象,再调用 setData() 方法将这个Uri 对象传递进去,对此还可以在标签中配置标签:

  • android:scheme:用于指定数据的协议部分,例如http
  • android:host:用于指定数据的主机名,例如www.baidu.com
  • android:port:用于指定数据的端口部分,一般紧跟主机之后
  • android:path:用于指定主机名和端口之后的部分
  • android:mimeType:用于指定可以处理数据的类型
    只有data的内容与指定的内容完全一致时,当前活动才能相应,例如上面的浏览器只需要指定 android:scheme=“http” 就能相应所有http协议的 Intent
    新建一个 Activity 更改 AndroidManifest.xml
    在这里插入图片描述
    报错:支持ACTION_VIEW的活动未设置为BROWSABLE 但是不影响项目的发布和运行,添加下面可消除错误
		<activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE"/>
                <data android:scheme="http"/>
            </intent-filter>
        </activity>

在这里插入图片描述
除了http协议外还有很多协议,例如geo表示显示地理位置、tel表示拨打电话
传递数据

	button1.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view) {
            Intent intent = new Intent("com.example.helloworld.fristactivity");
            intent.putExtra("zwt_data", "Hi,你好!");
            startActivity(intent);
        }
    });

接受数据

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activate_first);
        
        Intent intent = getIntent();
        String data = intent.getStringExtra("zwt_data");
        Toast.makeText(FristActivity.this, data, Toast.LENGTH_LONG).show();
    }

getIntent() 获得用于启动这个活动的 Intent,然后调用 getStringExtra 取出数据,由于传递的是字符串,如果传递的是整型就用 getIntExtra,布尔类型就用 getBooleanExtra,以此类推
返回数据
Activity 中有一个 startActivityForResult() 方法,这个方法也是用来启动活动,但这个方法在后动销毁的时候能够返回一个结果给上一个活动,有两个参数,一个是Intent、一个是请求码,请求码只要唯一就行

		@Override
        public void onClick(View view) {
            Intent intent = new Intent("com.example.helloworld.fristactivity");
            intent.putExtra("zwt_data", "Hi,你好!");
            startActivityForResult(intent,1);
        }

构建了一个 Intent ,只不过仅仅用来传递数据,调用 setResult() 方法向上一个活动传递数据,有两个参数,一个是返回处理结果的状态码,一个是带有数据的intent,最后调用finish销毁当前活动

			@Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.putExtra("data_return", "返回数据");
                setResult(RESULT_OK, intent);
                finish();
            }

在销毁活动的时候会回调 onActivityResult() 方法来传递数据,要在之前的活动中重写这个方法,这个方法有三个参数,requestCode 就是唯一的请求码,resultCode 返回处理结果的状态码,data 带有数据的 Intent
注意,项目中可能会多次调用 startActivityForResult() 方法,每一个活动销毁时都会回调 onActivityResult() 方法,所以要通过请求吗判断数据来源

	@Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case 1:
                if (resultCode == RESULT_OK) {
                    String return_data = data.getStringExtra("data_return");
                    Toast.makeText(MainActivity.this, return_data, Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
    }

如果不是通过按钮销毁活动,而是通过Back键来销毁活动的话,就需要重写 onBackPressed() 方法,当按下Back键的时候就会调用 onBackPressed() 里面,就可以同样返回数据

	@Override
    public void onBackPressed() {
        Intent intent = new Intent();
        intent.putExtra("data_return", "返回数据");
        setResult(RESULT_OK, intent);
        finish();
    }
活动状态
  1. 运行状态:当一个活动位于返回栈顶时,这个活动处于运行状态,系统最不愿意回收这个状态的资源
  2. 暂停状态:当一个活动不再处于栈顶,但是仍然可见,这个活动就进入了暂停的状态,并不是每一个活动都会沾满整个屏幕,比如对话框形式的活动只会占用屏幕中间的区域,处于暂停状态的活动任然是完全存活的,系统也不会去回收这种活动,只有在内存极低的情况下才会考虑
  3. 停止状态:当一个活动不再处于栈顶,并且完全不可见,就进入了停止状态,系统仍会保存相应的状态和成员变量,但当其他地方需要内存时就可能会被系统回收
  4. 销毁状态:当一个活动从返回栈中移除就变成了销毁状态,系统会最先回收处于这种状态的活动资源
活动的生命周期
  • onCreate():活动第一次被创建的时候调用,可以在此完成初始化操作(加载布局、绑定事件)
  • onStart():在活动由不可见变为可见的时候调用
  • onResume():在活动准备好和用户进行交互的时候调用,此时活动一定处于活动栈顶,并处于运行状态
  • onPause():在系统准备去启动或者恢复另一个活动的时候调用,通常将一些消耗CPU的资源释放掉,以及保存一些关键数据
  • onStop():在活动完全不可见的时候调用,如果启动的新活动是一个对话框式的活动,会调用onPause()不会调用onStop()
  • onDestroy():在活动被销毁之前调用,之后活动变为相会状态
  • onRestart():在活动由停止状态变为运行状态之前调用,也就是被重新启动
    在这里插入图片描述
    完整生存期:活动在 onCreate() 和 onDestroy() 之间
    可见生存期:活动在 onStart() 和 onStop() 之间,在屏幕上是可见的,有的能进行交互,有的不能
    前台生存期:活动在 onResume() 和 onPause()之间,活动处于隐形状态,可以和用户交互
    活动的启动模式
    活动的启动模式有四种:standard、singleTop、singleTask、singleInstance,可以在AndroidManifest.xml 中通过标签指定 android:launchMode 属性选择启动模式

standard:默认启动模式,当启动一个新活动,就会在返回栈中入栈,并处于栈顶的位置,不会在乎该活动是否已经存在栈中,每次启动都会创建新实例

singleTop:在启动活动的时候如果该活动已经在返回栈的栈顶,则直接使用,不再创建,若不再栈顶,则会创建新的实例

singleTask:没次启动活动时,系统会在返回栈中检查是否存在该实例,如果有就直接使用,并把这个活动之上的所有活动出栈,如果没有就创建一个新的实例

singleInstance:指定 singleInstance 模式的活动会启动一个新的返回栈来管理这个活动(singleTask指定不同的 taskAffinity 也会启动一个新的返回栈)一个活动内可能保存着一些数据,每个程序都有自己的返回栈,同一个活动在不同的返回栈中会创建新的实例,这就达不到共享活动实例的需求,使用 singleInstance 会有一个单独的返回栈来管理这个活动,不管那个应用程序来访问,都共用这个单独的返回栈,就实现了活动的共享


经验

通常为了方便管理会创建一个 BaseActivity 类,让其他的 Activity 都继承于这个 BaseActivity ,由于 BaseActivity 没有界面,不需要启动,所以不需要在 AndroidManifest.xml 中注册

public class BaseActivity extends AppCompatActivity {
    
    private static final String TAG = "BaseActivity";
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, getClass().getSimpleName());
    }
}

创建Activity的管理类 addActivity() 向 List 中添加一个活动,removeActivity() 在 List 中移除这个活动,finishAll() 在 List 中的所有活动进行全部销毁

public class ActivityCollector {
    public static List<Activity> activities = new ArrayList<>();
    
    public static void addActivity(Activity activity){
        activities.add(activity);
    }
    
    public static void removeActivity(Activity activity){
        activities.remove(activity);
    }
    
    public static void finishAll(){
        for (Activity activity : activities){
            if(!activity.isFinishing()){
                activity.finish();
            }
        }
    }
}

然后修改 BaseActivity

public class BaseActivity extends AppCompatActivity {

    private static final String TAG = "BaseActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, getClass().getSimpleName());
        ActivityCollector.addActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }
}

还可以在调用 finishAll() 后杀掉当前进程,保证完全退出程序

android.os.Process.killProcess(android.os.Process.myPid())

数据传递:若 FristActivity 需要传递信息给 SecondActivity 最好的写法是
在 SecondActivity:

    public static void actionStart(Context context, String data1, String data2){
        Intent intent = new Intent(context, SecondActivity.class);
        intent.putExtra("param1", data1);
        intent.putExtra("param2", data2);
        context.startActivity(intent);

    }

在 FristActivity 调用上面的方法启动 SecondActivity

		button1.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                SecondActivity.actionStart(FristActivity.this, "data1", "data2")
            }
        });
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值