Android 四大基础组件
Activity、Service、BroadCast Receiver、Content Provider
•介绍四大组件各自的作用
•探究activity的生命周期以及启动模式
•探究service的生命周期
•探究广播,service通过发送广播与activity通信(广播作为activity里面内部类)
•探究Content Provider
介绍四大组件各自的作用
Activity
Activity是用户操作的可视化界面,它为用户提供了一个完成操作指令的窗口。 需要在Activity创建时调用setContentView()来完成界面的显示,为用户提供交互的入口。
1、通常一个Activity就是一个屏幕
2、Activity之间通过Intent进行通信
3、安卓中每一个Activity都需要在AndroidMainFest.xml文件中声明
Service
Service(服务)是一个可以在后台执行长时间运行操作而没有用户界面的应用组件,即使当前应用被切换到后台,又或者用户打开了另一个App,服务仍然可以保持正常运行。
BroadCast Receiver
广播接收器是一个用于接收广播信息,并做出对应处理的组件。比如我们常见的系统广播:通知时区改变、电量低、用户改变了语言选项等。开发中我们可以通过继承BroadcastReceiver基类来自定义广播,接收某些我们感兴趣的广播来实现业务需求。
Content Provide
ContentProvider是不同应用程序之间进行数据交换的标准API,ContentProvide以Uri的形式对外提供数据,允许其他应用访问和修改数据;其他应用使用ContentResolve根据Uri进行访问操作指定的数据。
探究activity的生命周期以及启动模式
启动模式 :
1.Standard 标准模式: 每次启动一个Activity都会又一次创建一个新的实例入栈,无论这个实例是否存在。
2.SingleTop 栈顶复用模式 : 要创建的Activity已经处于栈顶时,此时会
直接复用栈顶的Activity。不会再创建新的Activity。
1.SingleTask 栈内复用模式,若须要创建的Activity已经处于栈中时,此时不会创建新的Activity,而是将存在栈中的Activity上面的其他Activity所有销毁,使它成为栈顶。
2.SingleInstance 单实例模式 : 具有此模式的Activity仅仅能单独位于一个任务栈中。
生命周期 :
Java
package com.example.testactivity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i("test","activity1 is created");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, MainActivity2.class);
startActivity(intent);
}
});
}
@Override
protected void onStart() {
Log.i("test","activity1 is started");
super.onStart();
}
@Override
protected void onResume() {
Log.i("test", "activity1 is resumeed");
super.onResume();
}
@Override
protected void onPause() {
Log.i("test", "activity1 is pauseed");
super.onPause();
}
@Override
protected void onStop() {
Log.i("test", "activity1 is stoped");
super.onStop();
}
@Override
protected void onDestroy() {
Log.i("test", "activity1 is destroyed");
super.onDestroy();
}
@Override
protected void onRestart() {
Log.i("test", "activity1 is Restarted");
super.onRestart();
}
}
TypeScript
package com.example.testactivity;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity2 extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i("test","activity2 is created");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
@Override
protected void onStart() {
Log.i("test","activity2 is started");
super.onStart();
}
@Override
protected void onResume() {
Log.i("test", "activity2 is resumeed");
super.onResume();
}
@Override
protected void onPause() {
Log.i("test", "activity2 is pauseed");
super.onPause();
}
@Override
protected void onStop() {
Log.i("test", "activity2 is stoped");
super.onStop();
}
@Override
protected void onDestroy() {
Log.i("test", "activity2 is destroyed");
super.onDestroy();
}
@Override
protected void onRestart() {
Log.i("test", "activity2 is Restarted");
super.onRestart();
}
}
单个activity :
启动activity: create start resume
点击返回建 : pause stop destory
点击桌面键: pause stop
多个activity :
启动第一个activity: create start resume
切换到另一个activity : 前一个activity : pause,后一个activity : create start resume ,前一个activity : stop
这个时候分两种情况:
1.点击返回键 : 后一个activity : pause , 前一个activity : restart start resume , 后一个activity : stop destory
2 .点击桌面键 : 后一个activity : pause stop
总结 : 点击返回建,栈顶activity出栈,点击桌面是跳转新的activity,是入栈。
onResume()里面调用finish方法会执行 pause stop destory 等方法。
特殊情况。栈顶是透明activity时,pause -> resume
探究service的生命周期
1.不与activity绑定(左边方式启动)
Java
package com.example.testservice;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Button btnStart;
private Button btnStop;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnStart = findViewById(R.id.btn_startService);
btnStop = findViewById(R.id.btn_stopService);
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startService(new Intent(MainActivity.this,MyService.class));
}
});
btnStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
stopService(new Intent(MainActivity.this,MyService.class));
}
});
}
}
Java
package com.example.testservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
public class MyService extends Service {
private final static String TAG = MyService.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate()...");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand()...");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()...");
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind()...");
return null;
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind()...");
return super.onUnbind(intent);
}
}
1.与activity绑定(右边方式启动)
Java
package com.example.testservice;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
public class MainActivity2 extends AppCompatActivity {
MyService2 myService2;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyService2.LocalBinder binder = (MyService2.LocalBinder) service;//获得自定义的LocalBinder对象
myService2 = binder.getService();//获得Service对象
}
@Override
public void onServiceDisconnected(ComponentName name) {
myService2 = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
bindService(new Intent(MainActivity2.this,MyService2.class),serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(serviceConnection);
super.onDestroy();
}
}
Java
package com.example.testservice;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
public class MyService2 extends Service {
private final IBinder binder = new LocalBinder();
private final static String TAG = MyService.class.getSimpleName();
public class LocalBinder extends Binder {
MyService2 getService(){
return MyService2.this;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind()......");
return binder;
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate()......");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand()......");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()......");
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind()......");
return super.onUnbind(intent);
}
}
手动调用方法 作用
startService() 启动服务
stopService() 关闭服务
bindService() 绑定服务
unbindService() 解绑服务
•startService()和stopService()只能开启和关闭Service,无法操作Service; bindService()和unbindService()可以操作Service
•startService()开启的Service,调用者退出后Service仍然存在; bindService()开启的Service,调用者退出后,Service随着调用者销毁。
•如果组件通过调用 startService() 启动服务(这会引起对 onStartCommand() 的调用),则服务会一直运行,直到其使用 stopself() 自行停止运行,或由其他组件通过调用 stopService() 将其停止为止。
•如果组件通过调用 bindService() 来创建服务,且未调用 onStartCommand() ,则服务只会在该组件与其绑定时运行。当该服务与其所有组件取消绑定后,系统便会将其销毁。
不与activity绑定
通过startService方式启动 : create startCommand ,后面再调用startService方法只有 startCommand
通过stopService方式停止 : destroy
与activity绑定
通过bindService方式启动 :create bind
activity销毁的时候里面调用unbindService解绑服务 : unbind destory
探究广播,service通过发送广播与activity通信
Java
package com.example.testbroadcast;
import androidx.appcompat.app.AppCompatActivity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
MyReceiver receiver ;
private static String ACTION = "123";
private Button btn;
class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(MainActivity.this,"我收到消息了!",Toast.LENGTH_LONG).show();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 开启 服务
startService(new Intent(MainActivity.this,MyService.class));
}
});
initReceiver();
}
// 注册 广播接收者
private void initReceiver() {
receiver = new MyReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION);
registerReceiver(receiver,intentFilter);
}
@Override
protected void onDestroy() {
// 关闭 服务
stopService(new Intent(MainActivity.this,MyService.class));
super.onDestroy();
}
}
TypeScript
package com.example.testbroadcast;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
private final static String TAG = MyService.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate()...");
}
// 发送 广播 延迟 三秒
private void sendBroad() {
try {
Thread.sleep(3000);
}catch (Exception e) {
e.printStackTrace();
}
Intent intent = new Intent();
intent.setAction("123");
sendBroadcast(intent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand()...");
// 发送 广播
sendBroad();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()...");
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind()...");
return null;
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind()...");
return super.onUnbind(intent);
}
}
总结 : activity 里面注册广播接收者,service里面发送广播,启动服务后,service发送广播,activity里面的广播接收者接收到后执行对应操作。
Content Provider
•概念(自己的理解)
•通过content provider 来获取联系人列表
•自定义content provider
概念 : 手机里面存取数据通过sqlite来进行,保存在当前程序目录下,content provider相当于是sqlite的外观,当sqlite里面数据改变的时候,content provider里面的notifychange()方法可以实现自动更新。同时content provider可以指定哪些可以被共享,哪些不可以,而sqlite只能全局读取数据。content provider保证了用户的安全与隐私。
通过content provider 来获取联系人列表
Java
package com.example.testcontentprovider;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private String[] columns = {
ContactsContract.Contacts._ID,// 获得ID值
ContactsContract.Contacts.DISPLAY_NAME,//获得姓名
ContactsContract.CommonDataKinds.Phone.NUMBER,//获得电话
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions((Activity) this, new String[]{Manifest.permission.READ_CONTACTS}, 100);
}
TextView tv = (TextView) findViewById(R.id.result); //获得布局文件中的标签
tv.setText(getQueryData());//为标签设置数据
}
private String getQueryData() {
StringBuilder sb =new StringBuilder();//用于保存字符串
ContentResolver resolver =getContentResolver();//获得ContentResolver对象
Cursor cursor =resolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);//查询记录
while(cursor.moveToNext()) {
int idIndex =cursor.getColumnIndex(columns[0]);//获得ID值的索引
int displayNameIndex =cursor.getColumnIndex(columns[1]); // 获得姓名索引
int id =cursor.getInt(idIndex);//获得id
String displayName =cursor.getString(displayNameIndex);//获得名称
Cursor phone =resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, columns[3]+"="+id,
null, null);
while(phone.moveToNext()) {
int phoneNumberIndex =phone.getColumnIndex(columns[2]); // 获得电话索引
String phoneNumber =phone.getString(phoneNumberIndex); //获得电话
sb.append(displayName +": "+phoneNumber +"\n");// 保存数据
}
}
cursor.close();//关闭Cursor
return sb.toString();
}
}
自定义content provider
Java
package com.example.testmycontentprovider;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private Button button1;
private Button button2;
private EditText editText1;
private EditText editText2;
private Uri uri = Uri.parse("content://com.example.testmycontentprovider/user");
private final String[] colmuns = {"_id", "name"};
private ListView listView;
private List<String> list = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = findViewById(R.id.btn1);
button2 = findViewById(R.id.btn2);
editText1 = findViewById(R.id.edit1);
editText2 = findViewById(R.id.edit2);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Integer id = Integer.parseInt(editText1.getText().toString());
String name = editText2.getText().toString();
if (id!=null && name!=null && !"".equals(name)){
ContentResolver contentResolver = getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put("_id",id);
contentValues.put("name",name);
contentResolver.insert(uri,contentValues);
}else {
Toast.makeText(MainActivity.this,"不能为空",Toast.LENGTH_LONG).show();
}
}
});
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(uri, colmuns, null, null, null, null);
while (cursor.moveToNext()) {
int idIndex = cursor.getColumnIndex(colmuns[0]);
int nameIndex = cursor.getColumnIndex(colmuns[1]);
String id = String.valueOf(cursor.getString(idIndex));
String name = cursor.getString(nameIndex);
list.add(id + " : " + name);
}
cursor.close();
listView = findViewById(R.id.listview);
listView.setAdapter(new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_dropdown_item_1line, list));
}
});
}
}
TypeScript
package com.example.testmycontentprovider;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class MyContentProvider extends ContentProvider
{
private SQLiteOpenHelper dataBaseHelper;
private SQLiteDatabase db;
public static final String AUTHORITY = "com.example.mycontentprovider";
// 设置ContentProvider的唯一标识
public static final int User_Code = 1;
// UriMatcher类使用:在ContentProvider 中注册URI
private static final UriMatcher uriMatcher;
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 初始化
uriMatcher.addURI(AUTHORITY,"user", User_Code);
}
@Override
public boolean onCreate() {
dataBaseHelper = MySqLiteHelper.getmInstance(getContext());
db = dataBaseHelper.getWritableDatabase();
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
return db.query("user",projection,selection,selectionArgs,null,null,sortOrder,null);
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
db.insert("user",null,values);
return uri;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
}
Java
package com.example.testmycontentprovider;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
public class MySqLiteHelper extends SQLiteOpenHelper {
private static String USER_TABLE = "user";
private static SQLiteOpenHelper mInstance;
public static synchronized SQLiteOpenHelper getmInstance(Context context){
if (mInstance == null){
mInstance = new MySqLiteHelper(context,"my.db",null,1);
}
return mInstance;
}
public MySqLiteHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
// 数据库初始化的时候调用 创建表 只调用一次
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "create table user(_id integer primary key autoincrement,name text)";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
横竖屏切换生命周期
加载竖屏:
I/test: activity1 is created
I/test: activity1 is started
I/test: activity1 is resumeed
竖屏切换到横屏:
I/test: activity1 is pauseed
I/test: activity1 is stoped
I/test: activity1 is destroyed
I/test: activity1 is created
I/test: activity1 is started
I/test: activity1 is resumeed
在AndroidManifest.xml中设置
竖屏切换到横屏就不会再走生命周期,而是执行onConfigurationChanged方法,仍然会进行横竖屏切换。但是不会设置横屏的布局。仍然是竖屏布局,仅仅只是横屏显示 。
TypeScript
//屏幕方向发生改变的回调方法
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
text_screen.append("\n 当前屏幕为横屏");
} else {
text_screen.append("\n 当前屏幕为竖屏");
}
super.onConfigurationChanged(newConfig);
Log.e("TAG", "onConfigurationChanged");
// setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //设置横屏
}
(一)设置屏幕横屏代码
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
这个在Activity下可以直接使用
(二)设置屏幕竖屏的代码
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
(三)判断屏幕是横屏还是竖屏的状态
/**
*系统中定义: int ORIENTATION_PORTRAIT = 1; 竖屏
*系统中定义: int ORIENTATION_LANDSCAPE = 2; 横屏
*/
//获取屏幕的方向 ,数值1表示竖屏,数值2表示横屏
int screenNum = getResources().getConfiguration().orientation;
layout-land文件夹下面是加载横屏布局模式