1.所有以drawable开头的文件夹都是用来放图片的,所有以mipmap开头的文件夹都是用来放应用图标的,所有以values开头的文件夹都是用来放字符串、样式、颜色等配置的,layout文件夹是用来放布局文件的
2.但是我们应该自己创建drawable-hdpi、drawable-xhdpi、drawable-xxhdpi等文件夹。在制作程序的时候最好能够给同一张图片提供几个不同分辨率的版本,分别放在这些文件夹下,然后当程序运行的时候,会自动根据当前运行设备分辨率的高低选择加载哪个文件夹下的图片。当然这只是理想情况,更多的时候美工只会提供给我们一份图片,这时你就把所有图片都放在drawable-xxhdpi文件夹下就好了
3.gradle
Gradle是一种构建工具,它可以帮你管理项目中的差异,依赖,编译,打包,部署......,你可以定义满足自己需要的构建逻辑,写入到build.gradle中供日后复用.
Gradle不是一种编程语言,它不能帮你实现软件中的任何实际功能
4.根项目build.gradle
两处repositories的闭包中都声明了jcenter()这行配置,那么这个jcenter是什么意思呢?其实它是一个代码托管仓库,很多Android开源项目都会选择将代码托管到jcenter上,声明了这行配置之后,我们就可以在项目中轻松引用任何jcenter上的开源项目了。
接下来,dependencies闭包中使用classpath声明了一个Gradle插件。为什么要声明这个插件呢?因为Gradle并不是专门为构建Android项目而开发的,Java、C++等很多种项目都可以使用Gradle来构建。因此如果我们要想使用它来构建Android项目,则需要声明com.android.tool […]
这样我们就将最外层目录下的build.gradle文件分析完了,通常情况下你并不需要修改这个文件中的内容,除非你想添加一些全局的项目构建配置
5.app moudle的build.gradle
1.com.android.application表示这是一个应用程序模块,com.android.library表示这是一个库模块。应用程序模块和库模块的最大区别在于,一个是可以直接运行的,一个只能作为代码库依附于别的应用程序模块来运行
6.如果你需要在XML中引用一个id,就使用@id/id_name这种语法,而如果你需要在XML中定义一个id,则要使用@+id/id_name这种语法
7.项目中添加的任何资源都会在R文件中生成一个相应的资源id
8.在<activity>标签中我们使用了android:name来指定具体注册哪一个活动,那么这里填入的.FirstActivity是什么意思呢?其实这不过就是com.example.activitytest.FirstActivity的缩写而已。由于在最外层的<manifest>标签中已经通过package属性指定了程序的包名是com.example.activitytest,因此在注册活动时这一部分就可以省略了,直接使用.FirstActivity就足够了
9.给主活动指定的label不仅会成为标题栏中的内容,还会成为启动器(Launcher)中应用程序显示的名称
10.Activity类提供了一个finish()方法,我们在活动中调用一下这个方法就可以销毁当前活动了
11.Android应用程序资源可以分为两大类,分别是assets和res,详细看https://www.jianshu.com/p/87930a20a4a8
12.Intent大致可以分为两种:显式Intent和隐式Intent,我们先来看一下显式Intent如何使用。
1.Intent有多个构造函数的重载,其中一个是Intent(Context packageContext, Class<?> cls)。这个构造函数接收两个参数,第一个参数Context要求提供一个启动活动的上下文,第二个参数Class则是指定想要启动的目标活动,通过这个构造函数就可以构建出Intent的“意图”。然后我们应该怎么使用这个Intent呢?Activity类中提供了一个startActivity()方法,这个方法是专门用于启动活动的,它接收一个Intent参数,这里我们将构建好的Intent传入startActivity()方法就可以启动目标活动了button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
}});
2.比于显式Intent,隐式Intent则含蓄了许多,它并不明确指出我们想要启动哪一个活动,而是指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并帮我们找出合适的活动去启动
3.每个Intent中只能指定一个action,但却能指定多个category。目前我们的Intent中只有一个默认的category,调用Intent中的addCategory()方法来添加一个category;android.intent.category.DEFAULT是一种默认的category,在调用startActivity()方法的时候会自动将这个category添加到Intent中;
4.使用隐式Intent,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能。比如说你的应用程序中需要展示一个网页,这时你没有必要自己去实现一个浏览器(事实上也不太可能),而是只需要调用系统的浏览器来打开这个网页就行了
5.Intent中提供了一系列putExtra()方法的重载,可以把我们想要传递的数据暂存在Intent中,启动了另一个活动后,只需要把这些数据再从Intent中取出就可以了
13.返回数据给上一个活动,A->B
1.A使用startActivityForResult,startActivityForResult()方法也是用于启动活动的,但这个方法期望在活动销毁的时候能够返回一个结果给上一个活动
2.B放回时,调用了setResult()方法。这个方法非常重要,是专门用于向上一个活动返回数据的。setResult()方法接收两个参数,第一个参数用于向上一个活动返回处理结果,一般只使用RESULT_OK或RESULT_CANCELED这两个值,第二个参数则把带有数据的Intent传递回去。
3.在SecondActivity被销毁之后会回调上一个活动的onActivityResult()方法,因此我们需要在A中重写这个方法来得到返回的数据
4.用户在B中并不是通过点击按钮,而是通过按下Back键回到FirstActivity,这样数据不就没法返回了吗?没错,不过这种情况还是很好处理的,我们可以通过在SecondActivity中重写onBackPressed()方法来解决这个问题
14.其实Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈(Back Stack)。栈是一种后进先出的数据结构,在默认情况下,每当我们启动了一个新的活动,它会在返回栈中入栈,并处于栈顶的位置。而每当我们按下Back键或调用finish()方法去销毁一个活动时,处于栈顶的活动会出栈,这时前一个入栈的活动就会重新处于栈顶的位置。系统总是会显示处于栈顶的活动给用户
15.活动状态
每个活动在其生命周期中最多可能会有4种状态。
1.运行状态
当一个活动位于返回栈的栈顶时,这时活动就处于运行状态。系统最不愿意回收的就是处于运行状态的活动,因为这会带来非常差的用户体验。
2.暂停状态
当一个活动不再处于栈顶位置,但仍然可见时,这时活动就进入了暂停状态。你可能会觉得既然活动已经不在栈顶了,还怎么会可见呢?这是因为并不是每一个活动都会占满整个屏幕的,比如对话框形式的活动只会占用屏幕中间的部分区域,你很快就会在后面看到这种活动。处于暂停状态的活动仍然是完全存活着的,系统也不愿意去回收这种活动(因为它还是可见的,回收可见的东西都会在用户体验方面有不好的影响),只有在内存极低统才会去考虑回收这种活动。
3.停止状态
当一个活动不再处于栈顶位置,并且完全不可见的时候,就进入了停止状态。系统仍然会为这种活动保存相应的状态和成员变量,但是这并不是完全可靠的,当其他地方需要内存时,处于停止状态的活动有可能会被系统回收。
4.销毁状态
当一个活动从返回栈中移除后就变成了销毁状态。系统会最倾向于回收处于这种状态的活动,从而保证手机的内存充足。
5. 活动的生存期
Activity类中定义了7个回调方法,覆盖了活动生命周期的每一个环节,下面就来一一介绍这7个方法。
••onCreate()。这个方法你已经看到过很多次了,每个活动中我们都重写了这个方法,它会在活动第一次被创建的时候调用。你应该在这个方法中完成活动的初始化操作,比如说加载布局、绑定事件等。
•onStart()。这个方法在活动由不可见变为可见的时候调用。
•onResume()。这个方法在活动准备好和用户进行交互的时候调用。此时的活动一定位于返回栈的栈顶,并且处于运行状态。
•onPause()。这个方法在系统准备去启动或者恢复另一个活动的时候调用。我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动的使用。
•onStop()。这个方法在活动完全不可见的时候调用。它和onPause()方法的主要区别在于,如果启动的新活动是一个对话框式的活动,那么onPause()方法会得到执行,而onStop()方法并不会执行。
•onDestroy()。这个方法在活动被销毁之前调用,之后活动的状态将变为销毁状态。
•onRestart()。这个方法在活动由停止状态变为运行状态之前调用,也就是活动被重新启动了。
以上7个方法中除了onRestart()方法,其他都是两两相对的,从而又可以将活动分为3种生存期。
16.onSaveInstanceState()回调方法,这个方法可以保证在活动被回收之前一定会被调用,因此我们可以通过这个方法来解决活动被回收时临时数据得不到保存的问题。
当一个活动进入到了停止状态,是有可能被系统回收的。那么想象以下场景:应用中有一个活动A,用户在活动A的基础上启动了活动B,活动A就进入了停止状态,这个时候由于系统内存不足,将活动A回收掉了,然后用户按下Back键返回活动A,会出现什么情况呢?其实还是会正常显示活动A的,只不过这时并不会执行onRestart()方法,而是会执行活动A的onCreate()方法,因为活动A在这种情况下会被重新创建一次。这样看上去好像一切正常,可是别忽略了一个重要问题,活动A中是可能存在临时数据和状态的。
注意
1、如果是用户自动按下返回键,或程序调用finish()退出程序,是不会触发onSaveInstanceState()和onRestoreInstanceState()的。
2、每次用户旋转屏幕时,您的Activity将被破坏并重新创建。当屏幕改变方向时,系统会破坏并重新创建前台Activity,因为屏幕配置已更改,您的Activity可能需要加载替代资源(例如布局)。即会执行onSaveInstanceState()和onRestoreInstanceState()的。
17.我们在使用Intent传递数据时也是用的类似的方法。这里跟你提醒一点,Intent还可以结合Bundle一起用于传递数据,首先可以把需要传递的数据都保存在Bundle对象中,然后再将Bundle对象存放在Intent里。到了目标活动之后先从Intent中取出Bundle,再从Bundle中一一取出数据
18.活动的启动模式;
在实际项目中我们应该根据特定的需求为每个活动指定恰当的启动模式。启动模式一共有4种,分别是standard、singleTop、singleTask和singleInstance,可以在AndroidManifest.xml中通过给<activity>标签指定android:launchMode属性来选择启动模式
1.standard是活动默认的启动模式,在不进行显式指定的情况下,所有活动都会自动使用这种启动模式,对于使用standard模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。
2.singleTop模式。当活动的启动模式指定为singleTop,在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例。不过当Activity并未处于栈顶位置时,这时再启动Activity,还是会创建新的实例的
3.singleTask,每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例
4.singleInstance模式的活动会启用一个新的返回栈来管理这个活动(其实如果singleTask模式指定了不同的taskAffinity,也会启动一个新的返回栈。
那么这样做有什么意义呢?想象以下场景,假设我们的程序中有一个活动是允许其他程序调用的,如果我们想实现其他程序和我们的程序可以共享这个活动的实例,应该如何实现呢?使用前面3种启动模式肯定是做不到的,因为每个应用程序都会有自己的返回栈,同一个活动在不同的返回栈中入栈时必然是创建了新的实例。而使用singleInstance模式就可以解决这个问题,在这种模式下会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活动,都共用的同一个返回栈,也就解决了共享活动实例的问题
使用getTaskId()可以获取到Activity所在的task的id。
19.getClass().getSimpleName()获取当前Activity的类名,知晓当前是在哪一个活动。
20.退出程序,android.os.Process.killProcess(android.os.Process.myPid());
21.启动活动的最佳写法
我们在Activity中添加了一个actionStart()方法,在这个方法中完成了Intent的构建,另外所有Activity中需要的数据都是通过actionStart()方法的参数传递过来的,然后把它们存储到Intent中,最后调用startActivity()方法启动Activity。例如下面:
public class SecondActivity extends BaseActivity {
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);
}
}
这样写的好处在哪里呢?最重要的一点就是一目了然,SecondActivity所需要的数据在方法参数中全部体现出来了,这样即使不用阅读SecondActivity中的代码,不去询问负责编写SecondActivity的同事,你也可以非常清晰地知道启动SecondActivity需要传递哪些数据。另外,这样写还简化了启动活动的代码,现在只需要一行代码就可以启动SecondActivity
22.