Android的系统架构:Linux内核层、系统运行库层、应用框架层和应用层
1.Linux内核层
Android系统是基于Linux内核的,Linux内核层层为Android设备的各种硬件提供了底层的驱动,如显示驱动、音频驱动、照相机驱动、蓝牙驱动、Wi-Fi驱动、电源管理等
2.系统运行库层
系统运行库层通过一些C/C++库来为Android系统提供了主要的特性支持。如SQLite库提供了数据库的支持,OpenGL|ES库提供了3D绘图的支持,Webkit库提供了浏览器内核的支持等。
3.应用架构层
应用架构层主要提供了构建应用程序时可能用到的各种API,Android自带的一些核心应用就是使用这些API完成的,开发者也可以通过使用这些API来构建自己的应用程序。
4.应用层
所有安装在手机上的应用程序都是属于这一层的比如系统自带的联系人、短信等程序,或者是你从Google Play上下载的小游戏,当然还包括你自己开发的程序。
1.四大组件
Android系统四大组件活动(Activity)、服务(Service)、广播接收器(Broadcast Receiver)和内容提供器(Content Provider)
活动:所有Android应用程序的门面,凡是在应用程序中看得到的东西,都放在活动中。
服务:低调,看不到但会一直在后台默默运行,即使退出了应用,服务仍可以继续运行。
广播接收器:允许的应用接收来自各处的广播消息,比如电话、短信等,当然应用可以向外发出广播消息。
内容提供器:为应用程序之间共享数据提供了可能,比如想要读取系统电话簿中的联系人就需要通过内容提供器来实现。
2.丰富的系统控件
Android系统为开发者提供了丰富的系统控件,使我们可以轻松地编写出漂亮的界面。品位高也能定制自己的控件。
3.SQLite数据库
Android系统自带了这种轻量级、运算速度极快的嵌入式关系型数据库。它不仅支持标准的SQL语法,还可以通过Android封装好的API进行操作,让存储和读取数据变得非常方便。
4.强大的多媒体
Android系统提供了如音乐、视频、录音、拍照、闹铃等等多媒体服务,可以在程序中通过代码进行控制,让应用变得更丰富多彩。
5.地理位置定位
现在Android手机都内置GPS,发挥想象可以做出创意十足的应用。
res目录:drawable开头的文件夹用来放图片,mipmap开头的文件夹用来放应用图标,values用来放字符串、样式、颜色等配置,layout用来放布局文件
Log.v() 用于打印那些最为琐碎的、意义最小的日志信息。
Log.d() 用于打印一些调试信息。
Log.i() 用于打印一些比较重要的数据。
Log.w() 用于打印一些警告信息。
Log.e() 用于打印程序中的错误信息。
是一种可以包含用户界面的组件,主要用于和用户进行交互。
新建一个Android项目,选择Add No Activity
app/src/main/java/com.example.activitytest目录 右击com.example.activitytest包->New->Activity->Empty Activity弹出创建活动的对话框,不勾选Generate Layout File和LauncherActivity,勾选Backwards Compatibility
勾选Generate Layout File(产生布局文件)表示会自动为FirstActivity创建一个对应的布局文件,勾选LauncherActivity(发射器活动)表示会自动将FirstActivity设置为当前项目的主活动,勾选Backwards Compatibility表示为项目启用向下兼容的模式。
项目中的任何活动都应该重写Activity的onCreate()方法,目前FirstActivity已经重写了这个方法。onCreate()默认实现是调用父类的onCreate()方法。
布局:用来显示界面内容
右击app/src/main/res目录->New->Directory,弹出新建目录的窗口,创建一个名为layout的目录,对layout目录右键->New->Layout resource file,弹出新建布局资源文件的窗口,命名为first_layout
创建布局文件时选择了LinearLayout作为根元素,因此现在布局文件中已经出现有一个LinearLayout元素,现在对这个布局添加一个按钮
<?xml version="1.0" encoding="utf-8"?>
<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/button_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button 1"
/>
</LinearLayout>
添加了一个Button元素,并在Button元素的内部增加了几个属性。
android:id是给当前的元素定义一个唯一标识符,之后可以在代码中对这个元素进行操作。
android:layout_width制定了当前元素的宽度,这里使用match_parent表示让当前元素和父元素一样宽。
android:layout_height指定当前元素高度,这里使用wrap_content表示当前元素的高度只要刚好能包含里面的内容就行。
android:text指定了元素中显示的文字内容。
按钮已经成功显示出来,接下来在活动中加载布局。回到FirstActivity,在onCreat()方法中添加:
public class FirstActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
}
}
setContentView()中传入布局R.layout…用于给当前的活动加载布局,R.layout.first_layout就会得到first_layout.xml布局的id。可以通过工具栏Preview预览当前布局。
所有的Activity都要在AndroidManifest.xml中进行注册才能生效,FirstActivity已经在AndroidManifest.xml注册过了。
android:name指定具体注册哪个Activity,这里填入.FirstActivity是com.example.activitytest.FirstActivity的缩写,最外层标签中已经通过package属性指定了程序的包名是com.example.activitytest,因此在注册Activity时包名就可以省略,直接使用.FirstActivity就足够。
配置主Activity的方法就是在标签内部加入标签,并在这个标签里添加和 。
修改后的AndroidManifest.xml文件代码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication" >
<activity android:name=".FirstActivity"
android:label = "This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Toast时Android系统提供的一种提醒方式,在程序中可以使用它将一些短小的信息通知给用户,会在一段时间后自动消失,并且不会占用任何屏幕空间。
首先需要定义一个弹出Toast的触发点,在onCreate()方法中添加:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
Button button1 = (Button) findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(FirstActivity.this,"You clicked Button 1",
Toast.LENGTH_SHORT).show();
}
});
在rea目录下新建menu文件夹,右击res目录->New->Directory,输入文件夹名menu,接着在这个文件夹下新建名为main的菜单文件,右击New->Menu resource file,文件名输入main
在main.xml添加如下代码:
<?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>
我们创建了两个菜单项,标签是用来创建具体的某一个菜单项,然后通过android:id给菜单项指定一个唯一的标识符,通过android:title给这个菜单项指定一个名称。
接着在FirstActivity中重写onCreateOptionsMenu()方法:
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main,menu);
return true;
}
定义菜单响应事件,在FirstActivity中重写onOptionsItemSelected()方法:
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.add_item:
Toast.makeText(this, "You clcker Add", Toast.LENGTH_SHORT).show();
break;
case R.id.remove_item:
Toast.makeText(this, "You clicked Remove", Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}
修改按钮监听器中的代码:
button1.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
finish();
}
});
在ActivityTest项目中创建一个活动。Android Studio为我们自动生成SecondActivity.java和second_layout.xml这两个文件。
编写second_layout.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SecondActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button 2"
/>
</LinearLayout>
然后SecondActivity中代码已经自动生成了一部分,默认不变,任何一个活动都需要在AndroidManifest.xml中注册,不过Android Studio已经帮我们自动完成了
Intent是Android程序中各组件之间进行交互的一种重要方式,可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。Intent可被用于启动活动、启动服务以及发送广播等场景,我们先将目光锁定在启动活动上面。
Intent大致可以分为两种:显示Intent和隐式Intent。
Intent有多个构造函数的重载,其中一个是Intent(Context packageContext,Class<?>cls)。这个构造函数接受两个参数,第一个参数Context要求提供一个启动活动的上下文,第二个参数Class指定想要启动的目标活动,这个构造函数就可以构建出Intent的“意图”。Activity类中提供了一个startActivity()方法接受一个Intent参数,专门用于启动活动。这里我们将构建好的Intent传入startActivity()方法就可以启动目标活动。
修改FirstActivity中的按钮的点击事件,代码如下:
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivity(intent);
}
});
我们首先构建出了一个Intent,传入FirstActivity.this作为上下文,传入Second-Activity.class作为目标活动,这样我们的“意图”就非常明显了,即在FirstActivity这个活动的基础上打开SecondActivity这个活动。然后通过startActivity()方法来执行这个Intent。按Back键可以销毁当前活动回到上一个活动。使用这种方式来启动活动,Intent的“意图”非常明显,因此我们称之为显示Intent。
通过在标签下配置的内容,可以指定当前活动能够响应的action和category,打开AndroidManifest.fest添加如下代码:
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
在标签中我们指明当前活动可以响应com.example.activitytest.ACTION_START这个action,标签则包含一些附加信息,更精确指明当前的活动能够响应的Intent中还可能带有category。只有和中的内容同时匹配上Intent中指定的action和category时,这个活动才能响应该Intent。
修改FirstActivity中按钮的点击事件,代码如下所示:
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.activitytest.ACTION_START");
startActivity(intent);
}
});
每个Intent只能指定一个action,却能指定多个category。
比如:FirstActivity中有一个字符串,传递到SecondActivity中:
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String data = "Hello SecondActivity";
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
//putExtra()方法重载,把要传递的数据暂存在Intent中。第一个参数是键,第二个参数是要传递的数据。
intent.putExtra("extra_data",data);
startActivity(intent);
}
});
在 SecondActivity中将传递的数据取出,并打印出来:
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
//getIntent()方法获取到启动SecondActivity的Intent,
Intent intent = getIntent();
//调用启动SecondActivity的Intent的getStringExtra()方法,传入相应的键值获取到相应的数据。
//不同类型换中间的字母即可。getIntExtra()、getBooleanExtra().
String data = ((Intent) intent).getStringExtra("extra_data");
Log.d("SecondActivity",data);
}
}
Activity中有一个startActivityForResult()方法用于启动活动,用startActivityForResult()启动的活动期望在销毁时返回一个结果给上一个Activity。startActivityForResult()接受两个参数,第一个参数是Intent,第二个是请求码(是个唯一值就行),用于在之后的回调中判断数据的来源。
修改FirstActivity中按钮的点击事件:
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivityForResult(intent,1);
}
});
这里使用startActivityForResult()方法来启动SecondActivity,请求码传入1。
接下来在SecondActivity中给按钮注册点击事件,并在点击事件中添加返回数据的逻辑
Button button2=(Button) findViewById(R.id.button_2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//先构建一个没有指定意图的Intent
Intent intent = new Intent();
//把要传递的数据存放在Intent中
intent.putExtra("data_return","Hello FirstActivity");
//Activity类的setResult()方法是专门用于向上一个Activity返回数据的。
//setResult()第一个参数用于向上一个活动返回处理结果,一般是RESULT_OK或RESULT_CANCELD
//setResult()第二个参数把带有数据的Intent传递回去
setResult(RESULT_OK,intent);
//调用finish()方法销毁活动。
finish();
}
});
在FirstActivity中写这个方法来得到返回的数据
//onActivityResult()方法带有三个参数,
//第一个参数requestCode为启动活动时传入的请求码,
//第二个参数resultCode我们返回数据时传入的处理结果,
//第三个参数data为携带返回数据的Intent。
@Override
protected void onActivityResult(int requestCode, int resultCode,Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 1:
if (resultCode == RESULT_OK) {
String returnedData = data.getStringExtra("data_return");
Log.d("FirstActivity", returnedData);
}
break;
default:
}
}
//如果不点击按钮直接按下Back键回到FirstActivity,数据就无法返回,
//我们通过在SecondActivity中重写onBackPressed()方法来解决。
public void onBackPressed() {
Intent intent = new Intent();
intent.putExtra("data_return","Hello FirstActivity");
setResult(RESULT_OK,intent);
finish();
}
Android使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称为返回栈(Back Stack),后进先出,系统总是会显示处于栈顶的活动给用户。
1.运行状态
位于返回栈栈顶的Activity处于运行状态。如果回收会带来非常差的用户体验。
2.暂停状态
不处于栈顶,但仍然可见的Activity。比如对话框形式的Activity只占用屏幕中间部分区域。暂停状态中的Activity仍完全存活着,系统也不愿意回收这种Activity(因为它仍可见,回收可见的任何东西都会带来不好的用户体验),除非在内存极低情况下才会考虑回收暂停状态的Activity。
3.停止状态
不处于返回栈栈顶,且完全不可见的Activity处于停止状态。系统仍会为停止状态的Activity保存相应状态和成员变量,当其他地方需要内存时,处于停止状态的Activity可能会被回收。
4.销毁状态
从返回栈中移除后的活动处于销毁状态。系统最倾向于回收销毁状态的活动来保证手机内存充足。
Activity类中定义了7个回调方法,覆盖了活动生命周期的每一个环节。
onCreate()。每个活动都需要重写onCreate()方法,会在活动第一次被创建时调用,在onCreate()中完成活动初始化操作如加载布局、绑定事件。
onStart()。在Activity由不可见变可见时调用。
onResume ()。在Activity准备好和用户交互时调用。此时Activity位于栈顶并处于运行状态。
onPause()。在系统准备启动或恢复另一个活动时调用。通常在onPause()中把消耗CPU的资源释放掉,保留关键数据,这个方法要快才能不影响栈顶Activity的使用。
onStop()。在活动完全不可见时调用,如果启动的新Activity是一个对话框式的Activity,那么onPause()方法会得到执行,onStop()不会执行。
onDestory()。在Activity被销毁之前调用,之后的Activity变为销毁状态。
onRestart()。在Activity由停止状态变为运行状态之前调用,也就是Activity被重新启动了。
除了onRestart(),其他都是两两相对,从而又可以将活动分为3种生存期,可以将Activity分为以下3种生存期。
完整生存期。Activity在onCreate()和onDestory()之间经历的。一般Activity在onCreate()方法中完成各种初始化操作,onDestroy()方法中完成释放内存操作。
可见生存期。onStart()和onStop()之间经历。可见生存期内Activity对用户总是可见的,即便有可能无法和用户交互,我们可以在onStart()中对资源加载,在onStop()中对资源释放。保证处于停止状态Activity不会过多占用内存。
前台内存期。onResume()和onPause()之间经历。前台生存期内Activity总是处于运行状态,此时Activity可以和用户进行交互。
启动模式一共4种,分别是standard、singleTop、singleTask和singleInstance。
活动默认的启动模式,不进行显式指定的情况下,所有活动都会自动使用这种启动模式。
打开ActivityTest项目,修改FirstActivity中onCreate()方法的代码
Log.d("FirstActivity",this,toString);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, FirstActivity.class);
startActivity(intent);
}
});
在启动Activity时如果发现返回栈的栈顶已经是该Activity,则直接使用它,不会创建新Activity实例
<activity
android:name=".FirstActivity"
**android:launchMode="singleTop"**
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
整个应用程序上下文只存在一个实例,每次启动该Activity时系统会首先在返回栈中检查是否存在该Activity实例,如果发现已存在则直接使用该Activity,并把这个Activity之上的所有Activity统统出栈。
FirstActivity中
<activity
**android:name=".FirstActivity"**
android:launchMode="singleTask"
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
@Override
protected void onRestart() {
super.onRestart();
Log.d("FirstActivity","onRestart");
}
SecondActivity中
protected void onDestroy() {
super.onDestroy();
Log.d("SecondActivity","onDestory");
}
<activity
android:name=".SecondActivity"
**android:launchMode="singleInstance"**>
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.activittest.MY_CATEGORY" />
</intent-filter>
</activity>
在FirstActivity、SecondActivity和ThirdActivity的onCreate()方法中用getTaskId()分别打印返回栈id,