Android基本知识(一)
- 四大组件
- Activity
- 生命周期
- 保存数据
- 启动模式
- 页面间数据传递
- 跳转
- 显式
- 隐式
- Service
- 启动方式
- 生命周期
- IntentService
- Broadcast
- 特点
- 注册
- 静态注册
- 动态注册
- 类型
- 无序广播
- 有序广播
- 异常
- ContentProvider
- 实现
- 对比Sql
- ContentProvider、ContentResolver、ContentObserver之间的关系
四大组件
Activity
Activity: 四大组件之一,一个用户交互界面对应一个 activity。
生命周期
Activity 从创建到销毁状态,包括:
onCreate —— 创建
onStart —— 开始可见
onResume —— 可编辑((即焦点)
onPause —— 遮挡(丢失焦点)
onStop —— 不可见
onDestroy —— 销毁
保存数据
Activity 调用onPause()和onStop()方法后,进入后台不可见状态,如果系统内存不足时, 可能会被系统摧毁,这个activity 重新回到前台, 之前所作的改变就会消失。为了避免该问题发生,可以覆写 onSaveInstanceState(Bundle bundle)方法。可以将状态数据存储到这个 Bundle 对象中, 即使 activity 被系统摧毁, 当用户重新启动这个 activity 而调用它的onCreate()方法时, 上述的Bundle 对象会作为实参传递给 onCreate()方法, 可以从 Bundle 对象中取出保存的数据, 然后利用这些数据将 activity 恢复到被摧毁之前的状态。
ps:onSaveInstanceState()方法如果调用将发生在 onPause()或 onStop()方法之前。
启动模式
standard —— 默认启动方式
singletop —— 栈顶复用方式
singletask —— 栈内复用方式
singleInstance —— 单独栈管理模式
页面间数据传递
Intent —— 默认
SharedPreferences —— 首选
广播
static 静态数据
Sqlite
等等
跳转
显式
指定包名,类名方式。
Intent intent = new Intent(MainActivity.this,xxx.class);
隐式
不需要指定具体的类名,而是通过 过滤器Intentfilter过滤的形式匹配对应的页面。
Intentfilter过滤的信息有action、category、data。如果Intent不能匹配目标Activity的IntentFilter,那么启动Activity就会失败。一个Activity的可以有多个IntentFilter,只要匹配任意一个IntentFilter就可以成功启动Activity。
<activity
android:name="com.gm.MainActivity" >
<intent-filter>
<action android:name="com.gm.main"/>
<action android:name="com.gm.launch"/>
<category android:name="android.intent.category.APP_BROWSER"/>
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="gm"
android:scheme="com.gm.main" />
<data android:mimeType="video/*"/>
</intent-filter>
</activity>
匹配原则
intent启动Activity的时候如果没有添加category会自动添加android.intent.category.DEFAULT,如果intent-filter中没有添加android.intent.category.DEFAULT则会匹配失败
Intent中匹配任意一个IntentFilter中的action(至少一个)、category(完全匹配)、data(至少一个)同时匹配成功,则可以启动Activity。
- action —— Intentfilter可以设置多个,隐式跳转的action只需要与其中一个完全相同(包括大小写)即可成功跳转。
startActivity(new Intent("com.gm.main"));
- category —— Intentfilter可以设置多个,隐式跳转的所有category都必须在intent-filter中找到一样的(包括大小写)才可以成功跳转。
Intent: Intent = Intent(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_APP_BROWSER)
startActivity(intent)
- data —— Intentfilter可以设置多个,隐式跳转的data只需要与其中一个完全相同(包括大小写)即可成功跳转。
// 拨打电话
Intent intent = new Intent();
intent.setAction(intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
// 选择相册照片
Intent intent1 = new Intent(Intent.ACTION_PICK);
intent1.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent1, 1);
data 是由mimeType和Uri组成,mimeType是指图像/jpeg、video/*等各种媒体格式。
Uri的数据格式比较复杂,组成:
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>
ps: 不能把 Intent 的 setType 和 setData 方法一起调用,它们两种方法都是把对方的值彼此置入空的,要两个方法 Uri 和 mime Type 一个必须是空的。
Service
一种长生命周期的,没有可视化界面,运行于后台的一种服务程序。
默认情况,Service 和 activity 是运行在当前 app 所在进程的 main thread(UI 主线程)里面。
里面不能执行耗时的操作(网络请求,拷贝数据库,大文件等 )
启动方式
1:startService方法启动 Service。
这种service 必须调用stopSelf()方法或者其他组件调用stopService()方法来停止它。
2:bindService(Intent service, ServiceConnection conn, int flags)跟 Service 进行绑定,当绑定成功的时候 Service 会将代理对象通过回调的形式传给 conn,获取 Service 服务代理对象。
通过unbindService()方法来关闭这种连接。一个service可以同时和多个客户绑定,当多个客户都解除绑定之后,系统会销毁service。
生命周期
ps:Service 实例只会有一个,如果要启动的 Service 已经存在,就不会再次创建该 Service 当然也不会调用 onCreate()方法。
一个 Service 可以被多个客户进行绑定,只有所有的绑定对象都执行了unBind()方法后Service 才会销毁。
IntentService
一种异步的处理多线程问题service,通过创建独立的 worker 线程来处理 onHandleIntent()方法实现的代码,所有请求处理完成后,IntentService 会自动停止,无需调用 stopSelf()方法。
public class MyIntentService extends IntentService {
// ......
@Override
protected void onHandleIntent(Intent intent) {
// 处理耗时操作
try {
Thread.sleep(1000);
} catch (Exception e){
e.printStackTrace();
}
}
}
Broadcast
组件之间传播数据的一种机制。由广播的发送者和接收者组成。两者不需要知道对方存在。它的底层采用了 Binder 机制来实现。
特点
- 广播接收者的生命周期非常短暂的, 在接收到广播的时候创建,onReceive()方法结束之后销毁;
- 广播接收者中不要做一些耗时的工作, 否则会弹出 Application No Response 错误对话框;
- 最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易被系统杀掉;
- 较长的耗时工作最好放在服务中完成。
注册
静态注册
在清单文件中注册广播接收者,只要 app 在系统中运行则一直可以接收到广播消息。
<receiver android:name=".BroadcastReceiver" >
<intent-filter>
<action android:name="android.intent.action.Test" />
</intent-filter>
</receiver>
动态注册
在代码中注册称为动态注册。注册广播接收器后才可以接收广播,注册的Activity 或者Service 销毁了就接收不到广播了。
BroadcastReceiver receiver = new BroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.Test");
context.registerReceiver(receiver, intentFilter);
类型
无序广播
完全异步,逻辑上可以被任何广播接收者接收到。
优点是效率较高。缺点是一个接收者不能将处理结果传递给下一个接收者,并无法终止广播。
有序广播
按照被接收者的优先级顺序,在被接收者中依次传播。也可以对广播数据进行修改传递。
ps:通过 Context.sendOrderedBroadcast(intent, receiverPermission,resultReceiver, scheduler, initialCode, initialData, initialExtras)指定 resultReceiver 广播接收者,这个接收者是最终接收者。通常比他优先级更高的接收者如果没有终止广播,那么他的 onReceive 会被执行两次,第一次是正常的按照优先级顺序执行,第二次是作为最终接收者接收。如果比他优先级高的接收者终止了广播,那么他依然能接收到广播。
异常
在8.0以上系统注册静态广播后发现接收不到广播,onRecive()得不到执行。
原因:Android8.0对静态广播做了限制,在开发文档中有如下内容:
Note: If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for implicit broadcasts (broadcasts that do not target your app specifically), except for a few implicit broadcasts that are exempted from that restriction.
如果您的应用程序针对26级或更高级别的API,则无法使用清单声明隐式广播的接收者(不针对本地广播),除了几个免除该限制的隐式广播。
ContentProvider
ContentProvider: 应用程序之间共享数据的接口。为应用间的数据交互提供了一个简易,安全的方式,允许把自己的应用数据根据需求开放给 其他应用进行增删改查,而不用担心因为直接开放数据库权限而带来的安全问题。
实现
ContentProvider 是一个抽象类,如果需要自定义提供内容,继承 ContentProvider 类,然后覆写 query、insert、update、delete 等方法。因为其是四大组件之一,因此必须在 AndroidManifest 文件中进行注册。把自己的数据通过 uri 的形式共享出去(android 系统下 不同程序 数据默认是不能共享访问)。
publicclass PersonContentProvider extends ContentProvider{
public boolean onCreate(){
}
Cursor query(Uri, String[], String, String[], String)
void insert(Uri, ContentValues)
void update(Uri, ContentValues, String, String[])
void delete(Uri, String, String[])
}
<provider
android:exported="true"
android:name="com.gm.test.provider.PersonContentProvider
android:authorities="com.gm.person" />
// 获取短信内容
public void onquerySms(View view) {
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(Uri.parse("content://sms"), new String[]{"body", "address", "type", "date"}, null, null, null);
if (cursor == null){
return;
}
while (cursor.moveToNext()) {
String body = cursor.getString(cursor.getColumnIndex("body"));
String address = cursor.getString(cursor.getColumnIndex("address"));
String type = cursor.getString(cursor.getColumnIndex("type"));
String date = cursor.getString(cursor.getColumnIndex("date"));
Log.i(TAG, "短信body:" + body + " address:" + address + " type:" + type + " date:" + date);
}
cursor.close();
}
对比Sql
Sql 也有增删改查的方法, 但是 sql 只能查询本应用下的数据库。而
ContentProvider 还可以去增删改查本地文件. xml 文件的读取等。
ContentProvider、ContentResolver、ContentObserver之间的关系
ContentProvider :内容提供者,用于对外提供数据。
ContentResolver:内容解析者,用于操作内容提供者提供的数据
ContentObserver 内容监听器,可以监听数据的改变状态
// 注册uri的监听消息
ContentResolver.registerContentObserver(Uri uri, boolean notify,ContentObserver observer)
// 解除注册uri的监听
ContentResolver.unregisterContentObserver(ContentObserver observer)
// 通知监听器
ContentResolver.notifyChange(Uri uri, ContentObserver observer)