文章结构
-
Activity
- 正常情况下生命周期
- 异常情况下生命周期
- 四种模式
- 启动方式
-
Service
- Service
- IntentService
- StartService
- BindService
-
BroadcastReceiver
- 有序广播
- 无序广播
- 本地广播
- 动态广播
- 静态广播
-
ContentProvider
- URI
- 自定义ContentProvider
- 系统ContentProvider
Activity
生命周期
onCreate() → onStart() → onResume() → onPause() → onStop() → onDestroy()
-
OneActivity启动TwoActivity然后back的生命周期
onCreate()
→onStart()
→onResume()
→onPause()
→ onCreate() → onStart() → onResume() →onStop()
→ onPause() →onRestart()
→onStart()
→onResume()
→ onStop() → onDestroy()注:红色为OneActivity的生命周期,黑体为TwoActivity的生命周期
锁屏 home 或者应用退出到主屏(oppo R9s plus)
onPause()
→onStop()
→onRestart()
→onStart()
→onResume()
异常情况下的生命周期
当内存不足或者系统资源配置发生改变都会使Activity杀死,此时系统会调用onSaveInstance
来保存当前Activity的状态,当Activity重新创建后,系统会调用onRestoreInstanceState
并将Bundle对象传递给onCreate方法。
Activity的启动模式
- standard模式:默认模式 新Activity会进入启动他的Activity所在的栈中。
- singleTop模式:栈顶复用,若当前Activity在栈顶,则无需创建,否则会创建此Activity。
- singleTask模式:栈内复用,首先系统会扫描栈中有没有我要启动的Activity,如果有,那么就会将他移到栈顶(他以上的Activity会出栈),没有就会创建一个。
- singleInstance模式:一个任务栈中只有一个Activity
Activity启动方式
- 显示启动(适用于应用内部)
startActivity(new Intent(this,xxx.class));
当然xxx.class需要注册 - 隐式启动(适用于应用外部)
定义一个Activity
启动Activity
Intent intent = new Intent("com.example.one.ACTION_START");
//android.intent.category.DEFAULT是一种默认的category,在startActivity时自动添加
intent.addCategory("com.example.one.ACTION_START");
startActivity(intent);
Service
- Service
主要用来执行一些不与用户交互的long-run的操作。注意Service如非特意指定,它仅是运行于该进程的一部分代码而已,另外Service并不是运行在单独线程中,而是主线程中。所以尽量要避免一些ANR的操作。
注:服务一旦创建就不会再次创建了,他会调用
onSstartCommand
方法,同一个服务可以多个Activity调用
- IntentService
当你的应用需要下载一个文件或者播放音乐等长期处于后台工作而有没有UI界面的时候,你肯定要用到Service+Thread来实现。因此你需要自己在Service服务里面实现一个Thread工作线程来下载文件或者播放音乐。然而你每次都需要自己去写一个Service+Thread来处理长期处于后台而没有UI界面的任务,这样显得很麻烦,没必要每次都去构建一个Service+Thread框架处理长期处于后台的任务。Google工程师给我们构建了一个方便开发者使用的这么一个框架--IntentService。 - startService
下面通过代码说明服务的过程
首先创建一个service。
public class MyService extends Service {
private static final String TAG = "MyService";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate: ");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand: ");
new Thread(){
@Override
public void run() {
int i = 10;
while(i-->0)
Log.i(TAG, "run: "+i);
}
}.start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy: ");
}
}
当然别忘了注册。
好了,我们就可以在Activity中启动和停止服务了。
startService(new Intent(this,MyService.class));
stopService(new Intent(this,MyService.class));
有的时候我们可能因为大意忘了关掉服务怎么办,可以用bindService。
- bindService
创建一个服务
public class MyService2 extends Service {
public MyService2() {
}
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
class MyBinder extends Binder{
public void showToast(){
Log.i("MyService2", "showToast");
}
public void showList(){
Log.i("MyService2", "showList");
}
}
}
这里只做两个事,显示Toast和显示列表(别忘了注册),接下来是绑定服务和解除绑定服务。
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//拿到后台服务代理对象
MyService2.MyBinder myBinder = (MyService2.MyBinder) service;
//调用方法
myBinder.showToast();
myBinder.showList();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
//绑定服务启动
bindService(new Intent(this,MyService2.class),conn,BIND_AUTO_CREATE);
//解除绑定
unbindService(conn);
- 前台服务
public class MyService3 extends Service {
public MyService3() {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
showNotification();
}
private void showNotification() {
//创建通知详细信息
Notification.Builder builder = new Notification.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("2019年3月31日")
.setContentText("今天天气晴,0到14度");
//创建点击跳转Intent
Intent intent = new Intent(this,ZeroActivity.class);
//创建人物栈Builder
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(ZeroActivity.class);
stackBuilder.addNextIntent(intent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
//设置跳转Intent到通知中
builder.setContentIntent(pendingIntent);
//获取通知服务
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//构建通知
Notification notification = builder.build();
//显示通知
notificationManager.notify(0,notification);
//启动为前台服务
startForeground(0,notification);
}
启动服务
startService(new Intent(this,MyService3.class));
- 系统服务
- 判断wifi是否开启
WifiManager wm = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
boolean enabled = wm.isWifiEnabled();
- 获取系统最大音量
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
int max = am.getStreamMaxVolume(AudioManager.STREAM_SYSTEM);
- 获取当前音量
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
int current = am.getStreamMaxVolume(AudioManager.STREAM_RING);
- 判断网络是否有连接
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
boolean isAvailable = info.isAvailable();
广播
- 广播可以是有序的,接收的时候按照优先级排序,高优先级广播接收者可以拦截广播。
- 无序广播效率高,但不可拦截,谁都能收到。
- 本地广播指只在本应用内部广播,外部无法接收到(必须是动态的)。
- 广播的生命周期很短,执行完onReceive就结束了,所在不能再广播里做耗时操作,否则会引起ANR。
示例
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("BroadcastReceiver", "广播收到了");
// abortBroadcast(); 这个函数的功能是清除广播,在有序时调用
}
}
注册广播
发送广播
//无序广播
sendBroadcast(Intent intent);
//有序广播
sendOrderedBroadcast(Intent intent,String receiverPermission);
广播也可以动态注册,下面用本地广播做个例子。
public class MyLocalBroadcaseReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("local", "本地广播收到了");
}
}
Activity中可以这样用
IntentFilter intentFilter = new IntentFilter("test");
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
//注册广播
manager.registerReceiver(myLocalBroadcaseReceiver,intentFilter);
//发送广播
manager.sendBroadcast(new Intent("test"));
//最后别忘了解除广播(在Activity关闭或广播结束时调用)
manager.unregisterReceiver(myLocalBroadcaseReceiver);
内容提供者
ContentProvider主要用于不同的应用之间实现数据共享。
- Uri(通用资源标志符)
Uri代表要操作的数据,Android上可用的每种资源 - 图像、视频片段等都可以用Uri来表示。
URI主要分三个部分:scheme, authority and path。其中authority又分为host和port。
格式如下:
scheme://host:port/path
例如:
所有联系人的Uri:content://contacts/people
某个联系人的Uri: content://contacts/people/1
所有图片Uri: content://media/external
某个图片的Uri:content://media/external/images/media/1 - 自定义内容提供者
首先新建一个提供者类
public class TelContentProvider extends ContentProvider {
private DBHelper helper = null;
private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);// 默认的规则是不匹配的
static{
URI_MATCHER.addURI("com.example.tel","tel",2);
URI_MATCHER.addURI("com.example.tel","tel/#",1);
}
@Override
public boolean onCreate() {
helper = new DBHelper(getContext(),"tel.db",null,1);
return true;
}
@Override
public String getType(Uri uri) {
int flag = URI_MATCHER.match(uri);
switch (flag){
case 1:
return "vnd.android.cursor.item/tel";
case 2:
return "vnd.android.cursor.dir/tels";
}
return null;
}
@Override
public Cursor query(Uri uri, String[] projection,String selection, String[] selectionArgs,String sortOrder) {
Cursor cursor = null;
int flag = URI_MATCHER.match(uri);
SQLiteDatabase database = helper.getWritableDatabase();
switch (flag){
case 1:
long id = ContentUris.parseId(uri);
cursor = database.query(true,"tel",null,"id = ?",new String[]{String.valueOf(id)},null,null,null,null);
break;
case 2:
cursor = database.query(true,"tel",null,selection,selectionArgs,null,null,null,null);
break;
}
return cursor;
}
@Override
public Uri insert( Uri uri,ContentValues values) {
Uri resultUri = null;
int flag =URI_MATCHER.match(uri);
switch (flag){
case 2:
resultUri = ContentUris.withAppendedId(uri,insertTels(values));
break;
}
return resultUri;
}
private long insertTels(ContentValues values) {
long id = -1;
SQLiteDatabase database = helper.getWritableDatabase();
id = database.insert("tel",null,values);
return id;
}
@Override
public int delete(Uri uri,String selection, String[] selectionArgs) {
int count = -1;
SQLiteDatabase database = helper.getWritableDatabase();
int flag = URI_MATCHER.match(uri);
switch (flag){
case 1:
long id = ContentUris.parseId(uri);
count = database.delete("tel","id = ?",new String[]{String.valueOf(id)});
break;
case 2:
count = database.delete("tel",selection,selectionArgs);
break;
}
return count;
}
@Override
public int update(Uri uri,ContentValues values, String selection,String[] selectionArgs) {
int count = -1;
int flag = URI_MATCHER.match(uri);
SQLiteDatabase database = helper.getWritableDatabase();
switch (flag){
case 1:
long id = ContentUris.parseId(uri);
count =database.update("tel",values,"id = ?",new String[]{String.valueOf(id)});
break;
case 2:
count = database.update("tel",values,selection,selectionArgs);
break;
}
return count;
}
}
其中DBHelper类用于初始化数据库
public class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context ,String name,SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
// id 姓名 电话
String sql = "create table tel(id integer primary key autoincrement," +
"name varchar(20)," +
"tel varchar(20))";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//暂时不考虑
}
}
别忘了注册
下面是测试代码
ContentResolver contentResolver = getContentResolver();
Uri uri = Uri.parse("content://com.example.tel/tel");
//insert
ContentValues insertValues = new ContentValues();
insertValues.put("name","张三");
insertValues.put("tel","13211111111");
contentResolver.insert(uri,insertValues);
//query all
Cursor cursor = contentResolver.query(uri,null,null,null,null);
while(cursor.moveToNext()){
Log.i("query", "name = "+cursor.getString(cursor.getColumnIndex("name")));
}
//update by id
uri = Uri.parse("content://com.example.tel/tel/1");
ContentValues updateValues = new ContentValues();
updateValues.put("name","李四");
updateValues.put("tel","12345678911");
contentResolver.update(uri,updateValues,null,null);
//update by name
uri = Uri.parse("content://com.example.tel/tel");
ContentValues updateValues2 = new ContentValues();
updateValues2.put("name","李四");
updateValues2.put("tel","98765432111");
contentResolver.update(uri,updateValues2,"name = ?",new String[]{"李四"});
//delete all
contentResolver.delete(uri,null,null);
//delete by id
uri = Uri.parse("content://com.example.tel/tel/1");
contentResolver.delete(uri,null,null);
//delete by name
uri = Uri.parse("content://com.example.tel/tel");
contentResolver.delete(uri,"name = ?",new String[]{"张三"});
- 系统提供的内容提供者
本文只介绍一个(短信),其他都是类似的。
Uri uri = Uri.parse("content://sms");
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(uri,null,null,null,null);
while (cursor.moveToNext()){
Log.i("test", "body"+cursor.getString(cursor.getColumnIndex("body")));
}
注意:需要权限