Bundle
實(shí)現(xiàn)了parcelable序列化的類,可以跨進(jìn)成通信
例如在activity和service中跨進(jìn)程通信
Bundle bundle = new Bundle();
bundle.putString("a","a");
intent.putExtras(bundle);
// bindService(intent, myserviceconnection, BIND_AUTO_CREATE);如果不需要調(diào)用binder獲取服務(wù)就不用使用bindService方法
startService(intent);
service端
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Bundle bundle = intent.getExtras();
Log.e("xxxxx", "bundle傳遞的值:"+(String) bundle.get("a"));
return super.onStartCommand(intent, flags, startId);
}
文件共享
可以將數(shù)據(jù)、對(duì)象寫入一個(gè)共享文件(外部存儲(chǔ)位置即可)中,多個(gè)進(jìn)程就可以同時(shí)讀寫這個(gè)文件,windows上如果文件加了排斥鎖,就會(huì)導(dǎo)致外部線程不能讀寫,但是linux沒(méi)有這種限制。但是同時(shí)多謝可能會(huì)產(chǎn)生一些問(wèn)題,還是需要注意的。
盡量避免并發(fā)讀寫
還有另一種輕量級(jí)的文件SharedPreferences文件,當(dāng)他設(shè)置為全局模式,也是一種共享文件
創(chuàng)建SharedPreferences文件
SharedPreferences sharedPreferences = getSharedPreferences("a.xml",Context.MODE_WORLD_WRITEABLE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("a","a");
editor.commit();
另外一個(gè)進(jìn)程判斷文件是否可讀
File file = new File("/data/data/com.app.typicallifecycle/shared_prefs/a.xml.xml");
Log.e("xxxxx","is this file readable? "+ String.valueOf(file.canRead()));
結(jié)果返回:E/xxxxx: is this file readable? true
Messager(信使)
這個(gè)Messenger類是通過(guò)message來(lái)傳遞消息數(shù)據(jù),可以從源碼中看出。所以它是不能并發(fā)來(lái)進(jìn)程通信的
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
并且它的底層也是通過(guò)AIDL實(shí)現(xiàn)的???code>Messenger.java代碼,從Stub.asInterface就已經(jīng)很熟悉了對(duì)吧,然后我們?cè)倏纯?code>IMessenger這個(gè)android/platform/frameworks/base/android-9.0.0_r21/./core/java/android/os/IMessenger.aidl文件就可以完全確定了
....
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
在傳遞數(shù)據(jù)方面,有arg1,arg2,obj,Bundle,replyTo。obj可以傳遞由aidl生成的自定義的數(shù)據(jù)對(duì)象,Bundle也可以并且基礎(chǔ)類型也比obj稍微多一些。下面是一個(gè)使用Bundle傳遞數(shù)據(jù)的實(shí)現(xiàn)
簡(jiǎn)單實(shí)例:跨進(jìn)成發(fā)消息
客戶端(這里的客戶端、服務(wù)端就是兩個(gè)進(jìn)程):發(fā)起綁定請(qǐng)求,成功連接上就通過(guò)信使Messenger對(duì)象傳遞字符數(shù)據(jù)
private ServiceConnection myserviceconnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//連接上服務(wù)的回調(diào)函數(shù)
Log.e("xxxxx", name.getClassName());
//從傳過(guò)來(lái)的ibinder對(duì)象中獲取一個(gè)信使messenger對(duì)象
Messenger messenger001 = new Messenger(service);
Message message = new Message();
Bundle bundle = new Bundle();
bundle.putString("a","i am client!");
message.what=0;
message.setData(bundle);
try {
messenger001.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
try {
service.linkToDeath(deathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
服務(wù)端接收數(shù)據(jù)
public class AIDLService extends Service {
private Messenger messenger = new Messenger(new messageHanler());
@Nullable
@Override
public IBinder onBind(Intent intent) {
//getBinder返回一個(gè)messenger和其handler通信的binder
return messenger.getBinder();
}
class messageHanler extends Handler{
@Override
public void handleMessage(Message msg) {
if(msg.what==0){
String u1 = msg.getData().getString("a");
Log.e("xxxxx", "Receive from client:" + u1);
}
}
}
}
進(jìn)程雙方互相可以通信
客戶端,相比較上面的代碼做了一些修改,主要是引入了replyTo回復(fù)信使這個(gè)方法,客戶端來(lái)創(chuàng)建這個(gè)回復(fù)Messenger,并把它通過(guò)message傳遞到服務(wù)端,服務(wù)端接收此messenger,通過(guò)它回復(fù)客戶端的消息
private Messenger messenger = new Messenger(new clientHandler());
private class clientHandler extends Handler{
@Override
public void handleMessage(Message msg) {
if(msg.what==0){
String u1 = msg.getData().getString("a");
Log.e("xxxxx","receive from server:"+u1);
}
}
}
private ServiceConnection myserviceconnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//連接上服務(wù)的回調(diào)函數(shù)
Log.e("xxxxx", name.getClassName());
//從傳過(guò)來(lái)的ibinder對(duì)象獲取一個(gè)信使messenger對(duì)象
Messenger messenger001 = new Messenger(service);
Message message = Message.obtain(null, 0);
Bundle bundle = new Bundle();
bundle.putString("a","i am client!");
message.setData(bundle);
//設(shè)置客戶端的handler
message.replyTo = messenger;
try {
messenger001.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
try {
service.linkToDeath(deathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
服務(wù)端
class messageHanler extends Handler{
@Override
public void handleMessage(Message msg) {
if(msg.what==0){
//客戶端的信使Messenger,通過(guò)客戶端傳過(guò)來(lái)的信使來(lái)發(fā)送消息
Messenger client = msg.replyTo;
String u1 = msg.getData().getString("a");
Log.e("xxxxx", "Receive from client:" + u1);
//從全局池中獲取一個(gè)message對(duì)象,來(lái)防止重復(fù)創(chuàng)建,消耗內(nèi)存
Message message = Message.obtain(null, 0);
Bundle bundle = new Bundle();
bundle.putString("a","i am server and i will reply you after a few minutes");
message.setData(bundle);
try {
client.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
AIDL
在上一篇已經(jīng)說(shuō)過(guò),binder是在線程池中來(lái)處理多個(gè)進(jìn)程的并發(fā)請(qǐng)求,所以在AIDL接口方法中考慮處理線程并發(fā)的情況,這樣就引入了CopyOnWriteArrayList
CopyOnWriteArrayList
官方解釋:是ArrayList的安全線程的變體,支持多線程并發(fā)讀寫操作(是由底層數(shù)組副本來(lái)實(shí)現(xiàn)的),最終返回的是ArrayList對(duì)象
- A thread-safe variant of {@link java.util.ArrayList} in which all mutative
- operations ({@code add}, {@code set}, and so on) are implemented by
- making a fresh copy of the underlying array.
服務(wù)端(只需要把數(shù)據(jù))
private CopyOnWriteArrayList<Book> books = new CopyOnWriteArrayList<Book>();
private final BookManager.Stub bookManager = new BookManager.Stub() {
@Override
public void addBooks(Book book) throws RemoteException {
books.add(book);
}
@Override
public List<Book> getBook() throws RemoteException {
return books;
}
};
@Override
public void onCreate() {
Log.e("xxxxx", "服務(wù)創(chuàng)建了");
books.add(new Book(1,"第一本書"));
books.add(new Book(2,"第二本書"));
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
//getBinder返回一個(gè)messenger和其handler通信的binder
return bookManager;
}
客戶端(連接到服務(wù)端進(jìn)程上時(shí)):請(qǐng)求返回books(在服務(wù)端時(shí),是CopyOnWriteArrayList類型)對(duì)象的類型,返回結(jié)果好是ArrayList
private ServiceConnection myserviceconnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//連接上服務(wù)的回調(diào)函數(shù)
Log.e("xxxxx", name.getClassName());
bookManager = BookManager.Stub.asInterface(service);
try {
List<Book> books = (List<Book>) bookManager.getBook();
Log.e("xxxxx","類名:" + books.getClass().getCanonicalName());
Log.e("xxxxx","書庫(kù)存書:" + books.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
try {
service.linkToDeath(deathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
新需求:需要滿足服務(wù)進(jìn)程新增書籍后,希望接收相關(guān)書籍的客戶進(jìn)程可以接收到通知
- 創(chuàng)建一個(gè)新書通知功能的接口,這個(gè)接口是供服務(wù)端進(jìn)程調(diào)用的
這個(gè)接口為什么使用aidl文件來(lái)創(chuàng)建:aidl接口只能使用aidl接口,不能使用普通接口
import com.app.typicallifecycle.Book;
interface IOnNewBookArrived {
void OnNewBookArrvied(in Book book);
}
- 添加兩個(gè)新功能給用戶端進(jìn)程調(diào)用,用來(lái)選擇是否啟用通知服務(wù)
為什么這里要將IOnNewBookArrived對(duì)象作為參數(shù):客戶端進(jìn)程需要和服務(wù)端進(jìn)程建立聯(lián)系,通過(guò)在OnNewBookArrvied方法內(nèi)部封裝發(fā)送message到固定handler的方法
interface BookManager {
void addBooks(in Book book);
List<Book> getBook();
void registerNewBookArrivedListener(IOnNewBookArrived listener);
void unreregisterNewBookArrivedListener(IOnNewBookArrived listener);
}
- 客戶端進(jìn)程內(nèi)實(shí)現(xiàn)這個(gè)OnNewBookArrvied方法的封裝,并作為參數(shù)傳給服務(wù)端進(jìn)程來(lái)讓服務(wù)端進(jìn)程發(fā)送message進(jìn)行提醒服務(wù)
public class MainActivity extends AppCompatActivity {
private static final String TAG = "xxxxx";
private static final int MESSAGE_NEWBOOK_ARRIVED = 1;
private EditText editText;
private Button button;
private Button button1;
private Context context =getGlobalContext.getContext();
private BookManager bookManager;
private Intent intent;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what==MESSAGE_NEWBOOK_ARRIVED){
Log.e(TAG, "客戶端收到新書新增通知!");
}
}
};
private ServiceConnection myserviceconnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//連接上服務(wù)的回調(diào)函數(shù)
Log.e("xxxxx", name.getClassName());
bookManager = BookManager.Stub.asInterface(service);
try {
List<Book> books = (List<Book>) bookManager.getBook();
Log.e("xxxxx","類名:" + books.getClass().getCanonicalName());
Log.e("xxxxx","書庫(kù)存書:" + books.toString());
//注冊(cè)新書新增通知
bookManager.registerNewBookArrivedListener(iOnNewBookArrived);
} catch (RemoteException e) {
e.printStackTrace();
}
try {
service.linkToDeath(deathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
/*
實(shí)例化一個(gè)IOnNewBookArrived接口對(duì)象,作為參數(shù)返回到遠(yuǎn)程進(jìn)程中,一旦遠(yuǎn)端進(jìn)程有新的書籍對(duì)象新增,就會(huì)調(diào)用
這個(gè)對(duì)象的方法,發(fā)送message消息,這邊接收到就會(huì)彈出提示
*/
private IOnNewBookArrived iOnNewBookArrived = new IOnNewBookArrived.Stub() {
@Override
public void OnNewBookArrvied(Book book) throws RemoteException {
//發(fā)送消息到由getTarget方法指定的handler
handler.obtainMessage(MESSAGE_NEWBOOK_ARRIVED, book).sendToTarget();
}
};
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.e("xxxxx", "onCreate: 活動(dòng)創(chuàng)建");
super.onCreate(savedInstanceState);
editText = findViewById(R.id.editText);
setContentView(R.layout.activity_main);
button = findViewById(R.id.button);
button1 = findViewById(R.id.removeservice);
intent = new Intent("AIDLservice");
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
bindService(intent, myserviceconnection, BIND_AUTO_CREATE);
}
});
服務(wù)端進(jìn)程,模擬每5秒增加一本書,來(lái)提醒所有開啟提醒服務(wù)的客戶進(jìn)程
public class AIDLService extends Service {
private String TAG = "xxxxx";
private CopyOnWriteArrayList<Book> books = new CopyOnWriteArrayList<Book>();
private CopyOnWriteArrayList<IOnNewBookArrived> listeners = new CopyOnWriteArrayList<IOnNewBookArrived>();
private Messenger messenger = new Messenger(new messageHanler());
private final BookManager.Stub bookManager = new BookManager.Stub() {
@Override
public void addBooks(Book book) throws RemoteException {
books.add(book);
}
@Override
public List<Book> getBook() throws RemoteException {
return books;
}
@Override
public void registerNewBookArrivedListener(IOnNewBookArrived listener) throws RemoteException {
if(listeners.contains(listener)){
Log.e(TAG, "已經(jīng)注冊(cè)過(guò)提醒服務(wù)了");
}else{
listeners.add(listener);
}
}
@Override
public void unreregisterNewBookArrivedListener(IOnNewBookArrived listener) throws RemoteException {
if(listeners.contains(listener)){
listeners.remove(listener);
Log.e(TAG, "注銷提醒服務(wù)成功!");
}else {
Log.e(TAG, "未找到需要注銷的提醒服務(wù)");
}
}
};
@Override
public void onCreate() {
try {
Log.e("xxxxx", "服務(wù)創(chuàng)建了");
books.add(new Book(1,"第一本書"));
books.add(new Book(2,"第二本書"));
delayAddBook();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
//getBinder返回一個(gè)messenger和其handler通信的binder
return bookManager;
}
private void delayAddBook() throws InterruptedException, RemoteException {
new Thread(new Runnable() {
@Override
public void run() {
for (int i=books.size(); i<20; i++){
try {
Thread.sleep(5000);
Book book = new Book(i, String.valueOf(i)+"號(hào)新書");
books.add(book);
newBookArrived(book);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}).start();
}
//添加新書,發(fā)起通知
private void newBookArrived(Book book) throws RemoteException {
if (listeners.size() != 0){
for (int i=0; i<listeners.size(); i++){
listeners.get(i).OnNewBookArrvied(book);
}
}
}
出現(xiàn)新問(wèn)題:點(diǎn)擊返回鍵,出現(xiàn)異常,找不到該binder連接Unbind failed: could not find connection for android.os.BinderProxy@4a822e38
原因:客戶進(jìn)程傳過(guò)去的對(duì)象iOnNewBookArrived不是同一個(gè)對(duì)象
@Override
protected void onDestroy() {
Log.e("xxxxx", "onDestroy:銷毀activity");
try {
bookManager.unreregisterNewBookArrivedListener(iOnNewBookArrived);
} catch (RemoteException e) {
e.printStackTrace();
}
super.onDestroy();
}
}
解決:使用RemoteCallbackList,專門負(fù)責(zé)清理跨進(jìn)成回調(diào)接口對(duì)象,雖然跨進(jìn)程傳遞對(duì)象,會(huì)生成兩個(gè)不同的對(duì)象,但是他們是使用同一個(gè)Binder進(jìn)行通信的,所以根據(jù)這個(gè)特點(diǎn),注冊(cè)的時(shí)候使用map的類型保存binder對(duì)象,和listener這個(gè)回調(diào)方法對(duì)象,注銷的時(shí)候,根據(jù)binder對(duì)象,注銷器所有的listener回調(diào)方法對(duì)象。當(dāng)然如果存在回調(diào)的方法不止一個(gè)這種情況,他們將是不同的兩個(gè)RemoteCallbackList對(duì)象
替換的代碼有,這些接口對(duì)象都需要替換:
private CopyOnWriteArrayList<IOnNewBookArrived> listeners = new CopyOnWriteArrayList<IOnNewBookArrived>();
替換成:
private RemoteCallbackList<IOnNewBookArrived> listeners = new RemoteCallbackList<IOnNewBookArrived>();
都已經(jīng)封裝成方法,直接調(diào)用
@Override
public void registerNewBookArrivedListener(IOnNewBookArrived listener) throws RemoteException {
if(listeners.contains(listener)){
Log.e(TAG, "已經(jīng)注冊(cè)過(guò)提醒服務(wù)了");
}else{
listeners.add(listener);
}
}
@Override
public void unreregisterNewBookArrivedListener(IOnNewBookArrived listener) throws RemoteException {
if(listeners.contains(listener)){
listeners.remove(listener);
Log.e(TAG, "注銷提醒服務(wù)成功!");
}else {
Log.e(TAG, "未找到需要注銷的提醒服務(wù)");
}
}
};
替換成:
@Override
public void registerNewBookArrivedListener(IOnNewBookArrived listener) throws RemoteException {
listeners.register(listener);
}
@Override
public void unreregisterNewBookArrivedListener(IOnNewBookArrived listener) throws RemoteException {
listeners.unregister(listener);
}
//添加新書,發(fā)起通知
private void newBookArrived(Book book) throws RemoteException {
if (listeners.size() != 0){
for (int i=0; i<listeners.size(); i++){
listeners.get(i).OnNewBookArrvied(book);
}
}
}
替換成:
//添加新書,發(fā)起通知
private void newBookArrived(Book book) throws RemoteException {
int listenerNumber = listeners.beginBroadcast();
for(int i=0; i<listenerNumber; i++){
listeners.getBroadcastItem(i).OnNewBookArrvied(book);
}
}
RemoteCallbackList工作原理
根據(jù)android藝術(shù)編程上的講解,使用binder來(lái)查詢回調(diào)方法對(duì)象,這里有一個(gè)問(wèn)題,同一個(gè)binder對(duì)應(yīng)多個(gè)回調(diào),即同一個(gè)binder多個(gè)RemoteCallbackList對(duì)象,應(yīng)該還有別的參數(shù)來(lái)幫助找到同一個(gè)binder下的不同對(duì)象
ContentProvider
注意幾個(gè)點(diǎn):
1.如果是在同一個(gè)應(yīng)用上開啟另一個(gè)進(jìn)程的情況,是不用考慮這些屬性的設(shè)置的,都可以訪問(wèn)
2.外部應(yīng)用調(diào)用contentprovider,需要android:exported="true"、不要設(shè)權(quán)限,只要滿足這兩點(diǎn),就可以跨進(jìn)程調(diào)用contentprovider(經(jīng)過(guò)測(cè)試:android5.0夜神模擬器)
現(xiàn)在寫代碼:一個(gè)接入SQLlit數(shù)據(jù)庫(kù)的ContentProvider組件
1.首先要用到一個(gè)SQLiteOpenHelper類,官網(wǎng)介紹說(shuō)這是一個(gè)幫助類,幫助數(shù)據(jù)庫(kù)的創(chuàng)建和版本更新,所以說(shuō)這個(gè)類是給應(yīng)用自己用的,不是給用戶提供訪問(wèn)接口的,畢竟用戶需要的只需要增刪該查接口,不是這些復(fù)雜的功能。
public class mSqlLiteHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "book_provider.db";
private static final int DATABASE_VERSION = 1;
private static final String table_name_book = "book";
private static final String table_name_user = "user";
private String create_table_book = "CREATE TABLE IF NOT EXISTS "
+table_name_book+ "_id INTEGER PRIMARY KEY, book_name TEXT)";
private String create_table_user = "CREATE TABLE IF NOT EXISTS "
+table_name_user+ "_id INTEGER PRIMARY KEY, username TEXT, sex INT";
//實(shí)例化數(shù)據(jù)庫(kù)對(duì)象的時(shí)候,傳入名稱、版本號(hào)
public mSqlLiteHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, DATABASE_NAME, factory, DATABASE_VERSION);
}
//數(shù)據(jù)庫(kù)第一次創(chuàng)建時(shí)調(diào)用,創(chuàng)建表格等初始化操作
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(create_table_book);
db.execSQL(create_table_user);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
2.使用這個(gè)類創(chuàng)建好數(shù)據(jù)庫(kù)之后,就可以使用ContentProvider將需要對(duì)外提供的數(shù)據(jù)庫(kù),開放其接口,但是ContentProvider需要訪問(wèn)Uri地址,所以需要給數(shù)據(jù)庫(kù)生成一個(gè)Uri地址
注意幾個(gè)小問(wèn)題:
- context對(duì)象,一般從oncreate中使用
getContext方法獲取,組件創(chuàng)建的時(shí)候,生成相應(yīng)的上下文環(huán)境(可以看作組件對(duì)象) - SQL語(yǔ)句書寫是注意單詞之間留空格
mContentProvider.java:使用mSqlLiteHelper類,生成、訪問(wèn)、更改數(shù)據(jù)庫(kù),作為對(duì)外開放的接口
public class mContentProvider extends ContentProvider {
private static final String HOST = "com.app.typicallifecycle.provider";
private static final String TAG = "xxxxx";
private static final int uri_book_code = 0;
private static final int uri_user_code = 1;
private static Context mcontext;
private static SQLiteDatabase sqLiteDatabase = null;
String table_name = null;
private static mContentObserver contentObserver = new mContentObserver(handler);;
//生成兩個(gè)Uri
private static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
uriMatcher.addURI(HOST, "book", uri_book_code);
uriMatcher.addURI(HOST, "user", uri_user_code);
}
private static final Uri uri_book = Uri.parse("content://"+HOST+ "/book");
private static final Uri uri_user = Uri.parse("content://"+HOST+ "/user");
/**
* 根據(jù)傳入的Uri對(duì)象,獲取uri code,然后根據(jù)這個(gè)code,來(lái)匹配相應(yīng)的數(shù)據(jù)庫(kù)表
*
* @ param uriobject 傳入的uri對(duì)象
* @ return table name 數(shù)據(jù)庫(kù)表的名稱
*/
private String getTableName(Uri uri){
String table_name = null;
switch (uriMatcher.match(uri)){
case uri_book_code:
table_name = mSqlLiteHelper.table_name_book;
break;
case uri_user_code:
table_name = mSqlLiteHelper.table_name_user;
break;
default:break;
}
return table_name;
}
/**
* 數(shù)據(jù)庫(kù)的初始化操作.
* 創(chuàng)建數(shù)據(jù)庫(kù)、表。向表內(nèi)插入數(shù)據(jù)
*
* @return database object 一個(gè)數(shù)據(jù)庫(kù)對(duì)象
*/
private void init_database(){
sqLiteDatabase = new mSqlLiteHelper(mcontext).getWritableDatabase();
sqLiteDatabase.execSQL("delete from " + mSqlLiteHelper.table_name_book);
sqLiteDatabase.execSQL("delete from " + mSqlLiteHelper.table_name_user);
sqLiteDatabase.execSQL("insert into " + mSqlLiteHelper.table_name_book + " values(1, 'Android');");
sqLiteDatabase.execSQL("insert into " + mSqlLiteHelper.table_name_book + " values(2, 'IOS');");
sqLiteDatabase.execSQL("insert into " + mSqlLiteHelper.table_name_user + " values(1, '安卓', 1);");
sqLiteDatabase.execSQL("insert into " + mSqlLiteHelper.table_name_user + " values(2, '喬布斯', 1);");
}
@Override
public boolean onCreate() {
mcontext = getContext();
init_database();
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
Log.e(TAG, "Current Thread:"+Thread.currentThread().getName());
table_name = getTableName(uri);
if(table_name!=null)
return sqLiteDatabase.query(table_name, projection, selection, selectionArgs, null,
null, sortOrder, null);
else throw new IllegalArgumentException("Illegal Uri: "+uri);
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
table_name = getTableName(uri);
if (uri==null){
throw new Resources.NotFoundException("Not found this URI: "+uri);
}
Log.e(TAG, table_name);
sqLiteDatabase.insert(table_name, null, values);
Log.e(TAG, "OldURI:" + uri);
getContext().getContentResolver().notifyChange(uri, null);
Log.e(TAG, "New Uri: "+uri);
return uri;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
table_name = getTableName(uri);
if (uri==null){
throw new Resources.NotFoundException("Not found this URI: "+uri);
}
int deleted_number = sqLiteDatabase.delete(table_name, selection, selectionArgs);
Log.e(TAG, "刪除了:" + String.valueOf(deleted_number) + " 行數(shù)據(jù)");
//通知注冊(cè)了ContentObserver的對(duì)象,此URI發(fā)生了更改
getContext().getContentResolver().notifyChange(uri, null);
return deleted_number;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
table_name = getTableName(uri);
if (uri==null){
throw new Resources.NotFoundException("Not found this URI: "+uri);
}
int updata_number = sqLiteDatabase.update(table_name, values, selection, selectionArgs);
Log.e(TAG, "修改了" + String.valueOf(updata_number)+ "行數(shù)據(jù)");
return updata_number;
}
}
mContentObserver.java
package com.app.typicallifecycle;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class mContentObserver extends ContentObserver {
private static final String TAG = "xxxxx";
private static int URI_ONCHANGED = 0;
private static Handler mhandler;
/**
* Creates a content observer.
*
* @param handler The handler to run {@link #onChange} on, or null if none.
*/
public mContentObserver(Handler handler) {
super(handler);
mhandler = handler;
}
@Override
public void onChange(boolean selfChange) {
Log.e(TAG, "uri 發(fā)生了更改");
mhandler.obtainMessage(URI_ONCHANGED).sendToTarget();
super.onChange(selfChange);
}
}
MainActivity.java:跨進(jìn)成訪問(wèn)ContentProvider
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.e("xxxxx", "onCreate: 活動(dòng)創(chuàng)建");
super.onCreate(savedInstanceState);
editText = findViewById(R.id.editText);
setContentView(R.layout.activity_main);
button = findViewById(R.id.button);
button1 = findViewById(R.id.removeservice);
intent = new Intent("AIDLservice");
new String();
RemoteCallbackList<IUnregisterNotification> remoteCallbackList = new RemoteCallbackList<IUnregisterNotification>();
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Uri uri = Uri.parse("content://com.app.typicallifecycle.provider/book");
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
user u1 = new user();
while(cursor.moveToNext()){
u1.id = cursor.getInt(0);
u1.book_name = cursor.getString(1);
Log.e(TAG, "查詢編號(hào)為:"+String.valueOf(u1.getId()) + ",書籍名稱:"+u1.getBook_name());
}
registerObserver(uri);
ContentValues contentValues = new ContentValues();
contentValues.put("_id", 3);
contentValues.put("book_name", "第一行代碼");
getContentResolver().insert(uri, contentValues);
getContentResolver().delete(uri, "_id=?", new String[]{"3"});
ContentValues newcontentValues = new ContentValues();
newcontentValues.put("_id", 1);
newcontentValues.put("book_name", "第二行代碼");
getContentResolver().update(uri, newcontentValues, "_id=1", null);
}
});
private void registerObserver(Uri uri){
contentObserver = new mContentObserver(new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 0:
Log.e(TAG, "ContentObserver: 接受到了來(lái)自跨進(jìn)成的消息");
break;
default:break;
}
}
});
getContentResolver().registerContentObserver(uri, false, contentObserver);
}