Android 系统架构
- linux内核层
- 系统运行库层
- 应用框架层
- 应用层
Android 的四大组件
- 活动(Activity)
- 服务(Service)、
- 广播接收器(Broadcast Receiver)
- 内容提供器(Content Provider)
手动创建一个活动
- 在Android Studio中创建一个Android程序选择 Add No Activity
-
在 app/src/main/java/默认包名 中 右键 New一个Empty Activity会弹出一个对话框 将活动命名为 FirstActivity 并且不勾选Generate Layout File 和 LauncherActivity这两个选项
勾选Generate Layout File会自动为FirstActicy生成一个对应的布局文件
勾选LauncherActivity会设置当前的活动为项目主活动。
勾选BackWards Compatibility表示会为项目启动向下兼容模式
任何活动都应该重写Activity的onCreate()方法 Android Studio已经帮我们做完了。
- 创建和加载布局 在app/src/main/res 目录 new 一个Directory创建一个名为layout的目录 然后右键 new 一个Layout resource file 在弹出窗口中命名为first_layout
- 回到FirstLayout中的onCreate()方法加入 setContentView(R.layout.first_layout);
-
在AndroidManifest文件中注册 在application标签中加入
标签并且指定action和category <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter>
Toast
Toast是一种提醒方式 使用方法是:
Toast.makeText(FirstActivity.this,"提醒文字",Toast.LENGTH_SHORT).show();
Toast通过其静态方法创建一个Toast对象,然后通过调用show()方法将Toast显示出来
在活动中使用Menu
- 在res目录下新建一个menu文件夹。然后在这个文件夹伤新建一个Menu resource file输入文件名mian点击ok
-
在文件main.xml中的menu标签中输入
<item android:id="@+id/add_item" android:title="添加"/> <item android:id="@+id/remove_item" android:title="删除"/>
这样就创建了两个菜单项
- 标签就是用来创建具体的某一个菜单项
-
回到FirstActivity中重写onCreateOptionsMenu()方法快捷键Ctrl+o具体如下
public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main,menu); return true; } 通过getMenuInflater()方法能够得到MenuInflater对象,再调用他的inflate()方法就可以给当前的活动创建菜单了 inflater()方法接受两个参数,第一个参数表示通过哪一个资源文件创建菜单,所以传入刚才创建的main.xml第二个参数用于指定我们的菜单项将添加到哪一个Menu对象当中去这里直接使用oncreateOptionsMenu()方法中传入的menu参数,然后给这个方法返回true 表示允许菜单显示出来, 如果返回了false创建的菜单将会无法显示。
-
创建菜单的响应事件 通过重写onOptionsItemSelected()方法
public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()){ case R.id.add_item: Toast.makeText(FirstActivity.this,"点击了菜单中的添加", Toast.LENGTH_SHORT).show(); break; case R.id.remove_item: Toast.makeText(FirstActivity.this, "点击了菜单中的删除", Toast.LENGTH_SHORT).show(); break; default: } return true; } 在onOptionsItemSelected()方法中通过调用item.getItemId()来判断我们点击的是哪一个菜单项
销毁一个活动
Activity中提供了一个finish()方法来销毁当前活动。
Intent
显式Intent
- 在创建一个 Activity 命名为SecondActivity 然后在FirstActivity中添加一个按钮
-
在FirstActivity中添加按钮监听事件后加入如下代码
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.first_layout); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(FirstActivity.this, SecondActivity.class); startActivity(intent); } }); } 我们首先构建出了一个Intent 传入FirstActivity.this作为上下文, 传入SecondActivity.class 作为活动目标,这表示在FirstActivity这个活动的基础上打开SecondActivity这个活动,然后通过startActivity方法来启动这个Intent
隐式Intent
隐式Intent相对于显式Intent制定了一些列更为抽象的action和category等信息,然后交由系统去分析这个Intent
在AndroidManifest.xml中,的activity标签下配置
SecondActivity的activity中添加相应
<intent-filter>
<action android:name="balabala.balabala.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
FirstActivity.java修改如下:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("balabala.balabala.ACTION_START");
//其中的action需要与AndroidManifest.xml中action标签中一致。
startActivity(intent);
}
});
在action标签中我们指明了当前活动可以响应balabala.balabala.ACTION_START这个action 而category标签则包含了一些附加信息,更精确的指明了当前的活动能响应的Intent中还可能带有category只有<action>和<category>中的内容同时能够匹配上Intent中指定的action和category时这个活动才能响应这个Intent
android.intent.category.DEFAULT是一种默认的category,在调用startActivity()方法的时候会自动将这个category添加到Intent中
每个Intent中只能指定一个action,但是却能指定多个category。
添加一个category:
在intent声明后添加
intent.addCategory("labalaba.labalaba.MY_CATEGORY");
调用了Intent类中的addCategory方法来添加一个category,我们制定了一个自定义的category 值为 labalaba.labalaba.MY_CATEGORY
然后在AndroidManifest.xml中,的activity标签下配置
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="balabala.balabala.ACTION_START" />
<!--android.intent.category.DEFAULT使一种默认的category在调用startActivity会自动将这个category添加到Intent中 所以必须要有这一句-->
<category android:name="android.intent.category.DEFAULT" />
<category android:name="labalaba.labalaba.MY_CATEGORY" />
</intent-filter>
</activity>
更多的Intent的用法
使用隐式Intent不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这样就可以使多个程序之间的功能共享成为一种可能。
修改FirstActivity中按钮点击事件的代码 如下:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.zbuter.cn"));
startActivity(intent);
}
});
这里制定了Intent的action是Intent.ACTION_VIEW 这是一个Android系统内置动作,其常量为android.intent.action.VIEW 然后通过Uri.parse()方法将一个网址字符串解析成一个Uri对象,在调用Intent的setData()方法将这个Uri对象传递进去
除了http协议外还可以指定很多其他协议,比如geo表示显式地理位置、tel表示拨打电话。。。
我们也可以在AndroidManifest.xml中注册对应action使我们自己的程序也响应这动作
向下一个活动传递数据
向下一个活动传递数据
intent.putExtra("key", "value");
可以向要启动的Activity中添加额外的数据
接受上一个活动传递来的数据
在启动的Activity中获取上个活动传递的数据要使用
Intent intent = getIntent();
String data = intent.getStringExtra("key");
将可以获得上一个活动传递来的key所对应的数据
如果key对应的是int类型就可以使用intent.getIntExtra()方法来或的int类型的返回值。
返回数据给上一个活动。
在启动Activity时使用
startActivityForResult(intent,1);
第二个参数是请求码
在SecondActivity中添加返回数据的逻辑
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra("data_return", "Hello FirstActivity");
setResult(RESULT_OK, intent);
finish(); //结束当前Activity
}
});
setResult接受两个参数,第一个参数用于向上一个活动的返回处理结果,一般只用RESULT_OK和RESULT_CANCELED这两个值,第二个参数则把带有数据的Intent传递过去。
由于我们使用的是startActivityForResult()方法来启动SecondActivity的在SecondActivity被销毁之后会调用上一个活动的onActivityResult()方法所以我们需要在FirstActivity中重写这个方法来得到返回的数据。
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
switch(requestCode){
case 1:
if(resultCode == RESULT_OK){
String returnData = data.getStringExtra("data_return");
Log.i(TAG, "onActivityResult: "+returnData);
}
}
}
Activity的生命周期
活动的状态
- 运行状态
- 暂停状态
- 停止状态
- 销毁状态
Activity的生存期:
Activity类中定义了7个回调方法, 覆盖了活动生命周期的每一个环节,
onCreate() 他会在活动第一次被创建的时候调用,一般在这个方法中完成对Activity的初始化操作,比如加载布局、绑定事件等。
onStart() 这个方法在活动由不可见变为可见时调用。
onResume() 这个方法在活动准备好了和用户进行交互的时候调用。此时的活动一定位于返回栈的栈顶。并且处于运行状态。
onPause() 这个方法在系统准备去启动或恢复另一个活动的时候调用。我们通常会在这个方法中将一些小号CPU资源释放掉,以及保存一些相关的数据,但是这个方法一定要执行的速度快,不然会影响到新的栈顶活动的使用
onStop() 这个方法在活动完全不可见的时候调用,和onPuase()方法的区别是,如果启动的活动是一个对话框活动,那么onPause()方法会得到执行,而onStop()不会
onDestory()这个方法在活动被销毁之前调用,之后的状态将变为销毁状态。
onRestart()这个方法在活动由停止状态变为运行状态之前调用,也就是活动被重新启动了。
以上7个方法除了onRestart()方法,其他都是两两对应的,可以分为三种生存周期。
完整生存期
活动在 onCreate() 和onDestroy()方法之间所经历的,程序会在onCreate()中初始化各种操作,在onDestroy()释放各种资源
可见生存期
活动在 onStart() 和onStop()方法之间所经历的
前台生存期
活动在 onResume() 和onPause()方法之间经历的
活动的启动模式
活动的启动模式一共由4种
-
standard
standard是活动默认的启动模式,在不进行显式指定的情况下所有的活动都会自动使用这种启动模式在standard模式下系统不会在乎这个活动是否已经存在返回栈中, 每次启动都会创建该活动的一个新的实例对象。
-
singleTop
当活动启动模式指定为singleTop时 在启动时如果发现返回栈的栈顶已经是该活动,则直接使用这个活动不会创建新的实例。,
-
singleTask
当活动启动模式指定为singTask时,在启动时候系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用这个实例,并把这个活动之上的所有活动统统出栈,如果*没有这个活动则会创建一个新的活动实例
- singleInstance
可以使在AndroidManifest.xml中通过
标签指定android:launchMode属性类选择启动模式
Tips:
-
知晓当前是在哪一个活动
新建一个JAVA类起名为BaseActivity类让BaseActivity继承AppCompatActivity并重写onCreate()方法 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("BaseActivity", getClass().getSimpleName()); }
然后让其他Activity继承BaseActivity, 就可以在logcat中观看是当前活动的是哪一个进程了。
-
随时随地退出程序
当程序由多层活动时退出程序需要按好多下back键才可以退出。Home只是将程序挂起。
所以应该新建一个ActivityCollector类作为活动管理器如下: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中的onCreate()方法中插入一句
ActivityCollector.addActivity(this);
在onDestroy()方法中插入一句
ActivityCollector.removeActivity(this);这样不管在什么地方想要退出程序 只需要调用ActivityCollector.finishAll()方法就可以了