Android內(nèi)的IPC其他方法

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)程可以接收到通知

  1. 創(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);
}
  1. 添加兩個(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);
}
  1. 客戶端進(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)題:

  1. context對(duì)象,一般從oncreate中使用getContext方法獲取,組件創(chuàng)建的時(shí)候,生成相應(yīng)的上下文環(huán)境(可以看作組件對(duì)象)
  2. 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);
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容