Android進(jìn)程間通信方式

目錄

一赞庶、使用 Intent

二翁脆、使用文件共享

三眷蚓、使用 Messenger

四、使用 AIDL

五反番、使用 ContentProvider

六沙热、使用 Socket



一叉钥、使用 Intent

Activity,Service篙贸,Receiver 都支持在 Intent 中傳遞 Bundle 數(shù)據(jù)投队,而 Bundle 實(shí)現(xiàn)了 Parcelable 接口,可以在不同的進(jìn)程間進(jìn)行傳輸爵川。

在一個(gè)進(jìn)程中啟動(dòng)了另一個(gè)進(jìn)程的 Activity敷鸦,Service 和 Receiver ,可以在 Bundle 中附加要傳遞的數(shù)據(jù)通過(guò) Intent 發(fā)送出去寝贡。


二扒披、使用文件共享

Windows 上,一個(gè)文件如果被加了排斥鎖會(huì)導(dǎo)致其他線程無(wú)法對(duì)其進(jìn)行訪問(wèn)圃泡,包括讀和寫碟案;而 Android 系統(tǒng)基于 Linux ,使得其并發(fā)讀取文件沒(méi)有限制地進(jìn)行洞焙,甚至允許兩個(gè)線程同時(shí)對(duì)一個(gè)文件進(jìn)行讀寫操作蟆淀,盡管這樣可能會(huì)出問(wèn)題。

可以在一個(gè)進(jìn)程中序列化一個(gè)對(duì)象到文件系統(tǒng)中澡匪,在另一個(gè)進(jìn)程中反序列化恢復(fù)這個(gè)對(duì)象(注意:并不是同一個(gè)對(duì)象熔任,只是內(nèi)容相同。)唁情。

SharedPreferences 是個(gè)特例疑苔,系統(tǒng)對(duì)它的讀 / 寫有一定的緩存策略,即內(nèi)存中會(huì)有一份 ShardPreferences 文件的緩存甸鸟,系統(tǒng)對(duì)他的讀 / 寫就變得不可靠惦费,當(dāng)面對(duì)高并發(fā)的讀寫訪問(wèn),SharedPreferences 有很多大的幾率丟失數(shù)據(jù)抢韭。因此薪贫,IPC 不建議采用 SharedPreferences。


三刻恭、使用 Messenger

Messenger 是一種輕量級(jí)的 IPC 方案瞧省,它的底層實(shí)現(xiàn)是 AIDL ,可以在不同進(jìn)程中傳遞 Message 對(duì)象鳍贾,它一次只處理一個(gè)請(qǐng)求鞍匾,在服務(wù)端不需要考慮線程同步的問(wèn)題,服務(wù)端不存在并發(fā)執(zhí)行的情形骑科。

服務(wù)端進(jìn)程:服務(wù)端創(chuàng)建一個(gè) Service 來(lái)處理客戶端請(qǐng)求橡淑,同時(shí)通過(guò)一個(gè) Handler 對(duì)象來(lái)實(shí)例化一個(gè) Messenger 對(duì)象,然后在 Service 的 onBind 中返回這個(gè) Messenger 對(duì)象底層的 Binder 即可咆爽。

publicclassMessengerServiceextendsService {privatestaticfinalStringTAG=MessengerService.class.getSimpleName();privateclassMessengerHandlerextendsHandler {/***@param msg*/@OverridepublicvoidhandleMessage(Messagemsg) {switch (msg.what) {caseConstants.MSG_FROM_CLIENT:Log.d(TAG,"receive msg from client: msg = ["+ msg.getData().getString(Constants.MSG_KEY)+"]");Toast.makeText(MessengerService.this,"receive msg from client: msg = ["+ msg.getData().getString(Constants.MSG_KEY)+"]",Toast.LENGTH_SHORT).show();Messenger client= msg.replyTo;Message replyMsg=Message.obtain(null,Constants.MSG_FROM_SERVICE);Bundle bundle=newBundle(); bundle.putString(Constants.MSG_KEY,"我已經(jīng)收到你的消息梁棠,稍后回復(fù)你置森!"); replyMsg.setData(bundle);try { client.send(replyMsg); }catch (RemoteException e) { e.printStackTrace(); }break;default:super.handleMessage(msg); } } }privateMessenger mMessenger=newMessenger(newMessengerHandler());@Nullable@OverridepublicIBinderonBind(Intentintent) {return mMessenger.getBinder();

? ? }

}

客戶端進(jìn)程:首先綁定服務(wù)端 Service ,綁定成功之后用服務(wù)端的 IBinder 對(duì)象創(chuàng)建一個(gè) Messenger 掰茶,通過(guò)這個(gè) Messenger 就可以向服務(wù)端發(fā)送消息了暇藏,消息類型是 Message 蜜笤。如果需要服務(wù)端響應(yīng)濒蒋,則需要?jiǎng)?chuàng)建一個(gè) Handler 并通過(guò)它來(lái)創(chuàng)建一個(gè) Messenger(和服務(wù)端一樣),并通過(guò) Message 的 replyTo 參數(shù)傳遞給服務(wù)端把兔。服務(wù)端通過(guò) Message 的 replyTo 參數(shù)就可以回應(yīng)客戶端了沪伙。

publicclassMainActivityextendsAppCompatActivity {privatestaticfinalStringTAG=MainActivity.class.getSimpleName();privateMessenger mGetReplyMessenger=newMessenger(newMessageHandler());privateMessenger mService;privateclassMessageHandlerextendsHandler {@OverridepublicvoidhandleMessage(Messagemsg) {switch (msg.what) {caseConstants.MSG_FROM_SERVICE:Log.d(TAG,"received msg form service: msg = ["+ msg.getData().getString(Constants.MSG_KEY)+"]");Toast.makeText(MainActivity.this,"received msg form service: msg = ["+ msg.getData().getString(Constants.MSG_KEY)+"]",Toast.LENGTH_SHORT).show();break;default:super.handleMessage(msg);? ? ? ? ? ? }? ? ? ? }? ? }@OverrideprotectedvoidonCreate(BundlesavedInstanceState) {super.onCreate(savedInstanceState);? ? ? ? setContentView(R.layout.activity_main);? ? }publicvoidbindService(Viewv) {Intent mIntent=newIntent(this,MessengerService.class);? ? ? ? bindService(mIntent, mServiceConnection,Context.BIND_AUTO_CREATE);? ? }publicvoidsendMessage(Viewv) {Message msg=Message.obtain(null,Constants.MSG_FROM_CLIENT);Bundle data=newBundle();? ? ? ? data.putString(Constants.MSG_KEY,"Hello! This is client.");? ? ? ? msg.setData(data);? ? ? ? msg.replyTo= mGetReplyMessenger;try {? ? ? ? ? ? mService.send(msg);? ? ? ? }catch (RemoteException e) {? ? ? ? ? ? e.printStackTrace();? ? ? ? }? ? }@OverrideprotectedvoidonDestroy() {? ? ? ? unbindService(mServiceConnection);super.onDestroy();? ? }privateServiceConnection mServiceConnection=newServiceConnection() {/***@param name*@param service*/@OverridepublicvoidonServiceConnected(ComponentNamename,IBinderservice) {? ? ? ? ? ? mService=newMessenger(service);Message msg=Message.obtain(null,Constants.MSG_FROM_CLIENT);Bundle data=newBundle();? ? ? ? ? ? data.putString(Constants.MSG_KEY,"Hello! This is client.");? ? ? ? ? ? msg.setData(data);//? ? ? ? ? ? msg.replyTo= mGetReplyMessenger;try {? ? ? ? ? ? ? ? mService.send(msg);? ? ? ? ? ? }catch (RemoteException e) {? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? }? ? ? ? }/***@param name*/@OverridepublicvoidonServiceDisconnected(ComponentNamename) {

? ? ? ? }

? ? };

}

**注意:**客戶端和服務(wù)端是通過(guò)拿到對(duì)方的 Messenger 來(lái)發(fā)送 Message 的。只不過(guò)客戶端通過(guò) bindService onServiceConnected 而服務(wù)端通過(guò) message.replyTo 來(lái)獲得對(duì)方的 Messenger 县好。Messenger 中有一個(gè) Hanlder 以串行的方式處理隊(duì)列中的消息围橡。不存在并發(fā)執(zhí)行,因此我們不用考慮線程同步的問(wèn)題缕贡。


四翁授、使用 AIDL

Messenger 是以串行的方式處理客戶端發(fā)來(lái)的消息,如果大量消息同時(shí)發(fā)送到服務(wù)端晾咪,服務(wù)端只能一個(gè)一個(gè)處理收擦,所以大量并發(fā)請(qǐng)求就不適合用 Messenger ,而且 Messenger 只適合傳遞消息谍倦,不能跨進(jìn)程調(diào)用服務(wù)端的方法塞赂。AIDL 可以解決并發(fā)和跨進(jìn)程調(diào)用方法的問(wèn)題,要知道 Messenger 本質(zhì)上也是 AIDL 昼蛀,只不過(guò)系統(tǒng)做了封裝方便上層的調(diào)用而已宴猾。

AIDL 文件支持的數(shù)據(jù)類型

基本數(shù)據(jù)類型

StringCharSequence

ArrayList叼旋,里面的元素必須能夠被 AIDL 支持仇哆;

HashMap,里面的元素必須能夠被 AIDL 支持夫植;

Parcelable讹剔,實(shí)現(xiàn) Parcelable 接口的對(duì)象;?注意:如果 AIDL 文件中用到了自定義的 Parcelable 對(duì)象偷崩,必須新建一個(gè)和它同名的 AIDL 文件辟拷。

AIDL,AIDL 接口本身也可以在 AIDL 文件中使用阐斜。

服務(wù)端

服務(wù)端創(chuàng)建一個(gè) Service 用來(lái)監(jiān)聽客戶端的連接請(qǐng)求衫冻,然后創(chuàng)建一個(gè) AIDL 文件,將暴露給客戶端的接口在這個(gè) AIDL 文件中聲明谒出,最后在 Service 中實(shí)現(xiàn)這個(gè) AIDL 接口即可隅俘。

客戶端

綁定服務(wù)端的 Service 邻奠,綁定成功后,將服務(wù)端返回的 Binder 對(duì)象轉(zhuǎn)成 AIDL 接口所屬的類型为居,然后就可以調(diào)用 AIDL 中的方法了碌宴。客戶端調(diào)用遠(yuǎn)程服務(wù)的方法蒙畴,被調(diào)用的方法運(yùn)行在服務(wù)端的 Binder 線程池中贰镣,同時(shí)客戶端的線程會(huì)被掛起,如果服務(wù)端方法執(zhí)行比較耗時(shí)膳凝,就會(huì)導(dǎo)致客戶端線程長(zhǎng)時(shí)間阻塞碑隆,導(dǎo)致 ANR 〉乓簦客戶端的 onServiceConnected 和 onServiceDisconnected 方法都在 UI 線程中上煤。

服務(wù)端訪問(wèn)權(quán)限管理

使用 Permission 驗(yàn)證,在 manifest 中聲明

服務(wù)端 onBinder 方法中

publicIBinder onBind(Intent intent) {//Permission 權(quán)限驗(yàn)證int check= checkCallingOrSelfPermission("com.jc.ipc.ACCESS_BOOK_SERVICE");if (check==PackageManager.PERMISSION_DENIED) {returnnull;? ? }return mBinder;

}

Pid Uid 驗(yàn)證

詳細(xì)代碼:

// Book.aidlpackagecom.jc.ipc.aidl;parcelableBook;

// IBookManager.aidlpackage com.jc.ipc.aidl;import com.jc.ipc.aidl.Book;import com.jc.ipc.aidl.INewBookArrivedListener;// AIDL 接口中只支持方法著淆,不支持靜態(tài)常量劫狠,區(qū)別于傳統(tǒng)的接口interfaceIBookManager {ListgetBookList();// AIDL 中除了基本數(shù)據(jù)類型,其他數(shù)據(jù)類型必須標(biāo)上方向,in,out 或者 inout// in 表示輸入型參數(shù)// out 表示輸出型參數(shù)// inout 表示輸入輸出型參數(shù)voidaddBook(inBookbook);voidregisterListener(INewBookArrivedListenerlistener);voidunregisterListener(INewBookArrivedListenerlistener);

}

// INewBookArrivedListener.aidlpackagecom.jc.ipc.aidl;importcom.jc.ipc.aidl.Book;// 提醒客戶端新書到來(lái)interfaceINewBookArrivedListener {voidonNewBookArrived(inBooknewBook);

}

publicclassBookManagerActivityextendsAppCompatActivity {privatestaticfinalStringTAG=BookManagerActivity.class.getSimpleName();privatestaticfinalintMSG_NEW_BOOK_ARRIVED=0x10;privateButton getBookListBtn,addBookBtn;privateTextView displayTextView;privateIBookManager bookManager;privateHandler mHandler=newHandler(){@OverridepublicvoidhandleMessage(Messagemsg) {switch (msg.what) {caseMSG_NEW_BOOK_ARRIVED:Log.d(TAG,"handleMessage: new book arrived"+ msg.obj);Toast.makeText(BookManagerActivity.this,"new book arrived"+ msg.obj,Toast.LENGTH_SHORT).show();break;default:super.handleMessage(msg);? ? ? ? ? ? }? ? ? ? }? ? };privateServiceConnection mServiceConn=newServiceConnection() {@OverridepublicvoidonServiceConnected(ComponentNamename,IBinderservice) {? ? ? ? ? ? bookManager=IBookManager.Stub.asInterface(service);try {? ? ? ? ? ? ? ? bookManager.registerListener(listener);? ? ? ? ? ? }catch (RemoteException e) {? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? }? ? ? ? }@OverridepublicvoidonServiceDisconnected(ComponentNamename) {? ? ? ? }? ? };privateINewBookArrivedListener listener=newINewBookArrivedListener.Stub() {@OverridepublicvoidonNewBookArrived(BooknewBook)throwsRemoteException {? ? ? ? ? ? mHandler.obtainMessage(MSG_NEW_BOOK_ARRIVED, newBook).sendToTarget();? ? ? ? }? ? };@OverrideprotectedvoidonCreate(@NullableBundlesavedInstanceState) {super.onCreate(savedInstanceState);? ? ? ? setContentView(R.layout.book_manager);? ? ? ? displayTextView= (TextView) findViewById(R.id.displayTextView);Intent intent=newIntent(this,BookManagerService.class);? ? ? ? bindService(intent, mServiceConn,BIND_AUTO_CREATE);? ? }publicvoidgetBookList(Viewview) {try {List list= bookManager.getBookList();Log.d(TAG,"getBookList:"+ list.toString());? ? ? ? ? ? displayTextView.setText(list.toString());? ? ? ? }catch (RemoteException e) {? ? ? ? ? ? e.printStackTrace();? ? ? ? }? ? }publicvoidaddBook(Viewview) {try {? ? ? ? ? ? bookManager.addBook(newBook(3,"天龍八部"));? ? ? ? }catch (RemoteException e) {? ? ? ? ? ? e.printStackTrace();? ? ? ? }? ? }@OverrideprotectedvoidonDestroy() {if (bookManager!=null&& bookManager.asBinder().isBinderAlive()) {Log.d(TAG,"unregister listener"+ listener);try {? ? ? ? ? ? ? ? bookManager.unregisterListener(listener);? ? ? ? ? ? }catch (RemoteException e) {? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? }? ? ? ? }? ? ? ? unbindService(mServiceConn);super.onDestroy();

? ? }

}

publicclassBookManagerServiceextendsService {privatestaticfinalStringTAG=BookManagerService.class.getSimpleName();// CopyOnWriteArrayList 支持并發(fā)讀寫永部,實(shí)現(xiàn)自動(dòng)線程同步独泞,他不是繼承自 ArrayListprivateCopyOnWriteArrayList mBookList=newCopyOnWriteArrayList();//對(duì)象是不能跨進(jìn)程傳輸?shù)模瑢?duì)象的跨進(jìn)程傳輸本質(zhì)都是反序列化的過(guò)程扬舒,Binder 會(huì)把客戶端傳遞過(guò)來(lái)的對(duì)象重新轉(zhuǎn)化生成一個(gè)新的對(duì)象//RemoteCallbackList 是系統(tǒng)專門提供的用于刪除系統(tǒng)跨進(jìn)程 listener 的接口阐肤,利用底層的 Binder 對(duì)象是同一個(gè)//RemoteCallbackList 會(huì)在客戶端進(jìn)程終止后,自動(dòng)溢出客戶端注冊(cè)的 listener 讲坎,內(nèi)部自動(dòng)實(shí)現(xiàn)了線程同步功能孕惜。privateRemoteCallbackList mListeners=newRemoteCallbackList<>();privateAtomicBoolean isServiceDestroied=newAtomicBoolean(false);privateBinder mBinder=newIBookManager.Stub() {@OverridepublicListgetBookList()throwsRemoteException {return mBookList;? ? ? ? }@OverridepublicvoidaddBook(Bookbook)throwsRemoteException {Log.d(TAG,"addBook:"+ book.toString());? ? ? ? ? ? mBookList.add(book);? ? ? ? }@OverridepublicvoidregisterListener(INewBookArrivedListenerlistener)throwsRemoteException {? ? ? ? ? ? mListeners.register(listener);? ? ? ? }@OverridepublicvoidunregisterListener(INewBookArrivedListenerlistener)throwsRemoteException {? ? ? ? ? ? mListeners.unregister(listener);? ? ? ? }? ? };@OverridepublicvoidonCreate() {super.onCreate();? ? ? ? mBookList.add(newBook(1,"老人與海"));? ? ? ? mBookList.add(newBook(2,"哈姆雷特"));newThread(newServiceWorker()).start();? ? }privatevoidonNewBookArrived(Bookbook)throwsRemoteException {? ? ? ? mBookList.add(book);int count= mListeners.beginBroadcast();for (int i=0; i< count; i++) {INewBookArrivedListener listener= mListeners.getBroadcastItem(i);if (listener!=null) {? ? ? ? ? ? ? ? listener.onNewBookArrived(book);? ? ? ? ? ? }? ? ? ? }? ? ? ? mListeners.finishBroadcast();? ? }privateclassServiceWorkerimplementsRunnable {@Overridepublicvoidrun() {while (!isServiceDestroied.get()) {try {Thread.sleep(5000);? ? ? ? ? ? ? ? }catch (InterruptedException e) {? ? ? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? ? ? }int bookId= mBookList.size()+1;Book newBook=newBook(bookId,"new book #"+ bookId);try {? ? ? ? ? ? ? ? ? ? onNewBookArrived(newBook);? ? ? ? ? ? ? ? }catch (RemoteException e) {? ? ? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }? ? }@Nullable@OverridepublicIBinderonBind(Intentintent) {//Permission 權(quán)限驗(yàn)證int check= checkCallingOrSelfPermission("com.jc.ipc.ACCESS_BOOK_SERVICE");if (check==PackageManager.PERMISSION_DENIED) {returnnull;? ? ? ? }return mBinder;? ? }@OverridepublicvoidonDestroy() {? ? ? ? isServiceDestroied.set(true);super.onDestroy();? ? }}

五、使用 ContentProvider

用于不同應(yīng)用間數(shù)據(jù)共享晨炕,和 Messenger 底層實(shí)現(xiàn)同樣是 Binder 和 AIDL衫画,系統(tǒng)做了封裝,使用簡(jiǎn)單瓮栗。 系統(tǒng)預(yù)置了許多 ContentProvider 削罩,如通訊錄、日程表费奸,需要跨進(jìn)程訪問(wèn)弥激。 使用方法:繼承 ContentProvider 類實(shí)現(xiàn) 6 個(gè)抽象方法,這六個(gè)方法均運(yùn)行在 ContentProvider 進(jìn)程中愿阐,除 onCreate 運(yùn)行在主線程里微服,其他五個(gè)方法均由外界回調(diào)運(yùn)行在 Binder 線程池中。

ContentProvider 的底層數(shù)據(jù)缨历,可以是 SQLite 數(shù)據(jù)庫(kù)以蕴,可以是文件糙麦,也可以是內(nèi)存中的數(shù)據(jù)。

詳見代碼:

publicclassBookProviderextends ContentProvider {

? ? privatestaticfinalString TAG = "BookProvider";

? ? publicstaticfinalString AUTHORITY = "com.jc.ipc.Book.Provider";

? ? publicstaticfinalUri BOOK_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/book");

? ? publicstaticfinalUri USER_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/user");

? ? publicstaticfinalintBOOK_URI_CODE = 0;

? ? publicstaticfinalintUSER_URI_CODE = 1;

? ? privatestaticfinalUriMatcher sUriMatcher =new UriMatcher(UriMatcher.NO_MATCH);

? ? static {

? ? ? ? sUriMatcher.addURI(AUTHORITY, "book", BOOK_URI_CODE);

? ? ? ? sUriMatcher.addURI(AUTHORITY, "user", USER_URI_CODE);

? ? }

? ? private Context mContext;

? ? private SQLiteDatabase mDB;

? ? @Override

? ? publicboolean onCreate() {

? ? ? ? mContext = getContext();

? ? ? ? initProviderData();

? ? ? ? returntrue;

? ? }

? ? privatevoid initProviderData() {

? ? ? ? //不建議在 UI 線程中執(zhí)行耗時(shí)操作mDB =new DBOpenHelper(mContext).getWritableDatabase();

? ? ? ? mDB.execSQL("delete from " + DBOpenHelper.BOOK_TABLE_NAME);

? ? ? ? mDB.execSQL("delete from " + DBOpenHelper.USER_TABLE_NAME);

? ? ? ? mDB.execSQL("insert into book values(3,'Android');");

? ? ? ? mDB.execSQL("insert into book values(4,'iOS');");

? ? ? ? mDB.execSQL("insert into book values(5,'Html5');");

? ? ? ? mDB.execSQL("insert into user values(1,'haohao',1);");

? ? ? ? mDB.execSQL("insert into user values(2,'nannan',0);");

? ? }

? ? @Nullable

? ? @Override

? ? public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {

? ? ? ? Log.d(TAG, "query, current thread"+ Thread.currentThread());

? ? ? ? String table = getTableName(uri);

? ? ? ? if(table ==null) {

? ? ? ? ? ? thrownewIllegalArgumentException("Unsupported URI" + uri);

? ? ? ? }

? ? ? ? returnmDB.query(table, projection, selection, selectionArgs,null,null, sortOrder,null);

? ? }

? ? @Nullable

? ? @Override

? ? public String getType(Uri uri) {

? ? ? ? Log.d(TAG, "getType");

? ? ? ? returnnull;

? ? }

? ? @Nullable

? ? @Override

? ? public Uri insert(Uri uri, ContentValues values) {

? ? ? ? Log.d(TAG, "insert");

? ? ? ? String table = getTableName(uri);

? ? ? ? if(table ==null) {

? ? ? ? ? ? thrownewIllegalArgumentException("Unsupported URI" + uri);

? ? ? ? }

? ? ? ? mDB.insert(table, null, values);

? ? ? ? // 通知外界 ContentProvider 中的數(shù)據(jù)發(fā)生變化mContext.getContentResolver().notifyChange(uri,null);

? ? ? ? return uri;

? ? }

? ? @Override

? ? publicint delete(Uri uri, String selection, String[] selectionArgs) {

? ? ? ? Log.d(TAG, "delete");

? ? ? ? String table = getTableName(uri);

? ? ? ? if(table ==null) {

? ? ? ? ? ? thrownewIllegalArgumentException("Unsupported URI" + uri);

? ? ? ? }

? ? ? ? intcount = mDB.delete(table, selection, selectionArgs);

? ? ? ? if(count > 0) {

? ? ? ? ? ? mContext.getContentResolver().notifyChange(uri, null);

? ? ? ? }

? ? ? ? return count;

? ? }

? ? @Override

? ? publicint update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {

? ? ? ? Log.d(TAG, "update");

? ? ? ? String table = getTableName(uri);

? ? ? ? if(table ==null) {

? ? ? ? ? ? thrownewIllegalArgumentException("Unsupported URI" + uri);

? ? ? ? }

? ? ? ? introw = mDB.update(table, values, selection, selectionArgs);

? ? ? ? if(row > 0) {

? ? ? ? ? ? getContext().getContentResolver().notifyChange(uri, null);

? ? ? ? }

? ? ? ? return row;

? ? }

? ? private String getTableName(Uri uri) {

? ? ? ? String tableName =null;

? ? ? ? switch (sUriMatcher.match(uri)) {

? ? ? ? ? ? case BOOK_URI_CODE:

? ? ? ? ? ? ? ? tableName = DBOpenHelper.BOOK_TABLE_NAME;

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case USER_URI_CODE:

? ? ? ? ? ? ? ? tableName = DBOpenHelper.USER_TABLE_NAME;

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? default:

? ? ? ? ? ? ? ? break;

? ? ? ? }

? ? ? ? return tableName;

? ? }

}


publicclassDBOpenHelperextends SQLiteOpenHelper {

? ? privatestaticfinalString DB_NAME = "book_provider.db";

? ? publicstaticfinalString BOOK_TABLE_NAME = "book";

? ? publicstaticfinalString USER_TABLE_NAME = "user";

? ? privatestaticfinalintDB_VERSION = 1;

? ? privateString CREATE_BOOK_TABLE = "CREATE TABLE IF NOT EXISTS "? ? ? ? ? ? + BOOK_TABLE_NAME + "(_id INTEGER PRIMARY KEY," + "name TEXT)";

? ? privateString CREATE_USER_TABLE = "CREATE TABLE IF NOT EXISTS "? ? ? ? ? ? + USER_TABLE_NAME + "(_id INTEGER PRIMARY KEY," + "name TEXT,"? ? ? ? ? ? + "sex INT)";

? ? public DBOpenHelper(Context context) {

? ? ? ? super(context, DB_NAME,null, DB_VERSION);

? ? }

? ? @Override

? ? publicvoid onCreate(SQLiteDatabase db) {

? ? ? ? db.execSQL(CREATE_BOOK_TABLE);

? ? ? ? db.execSQL(CREATE_USER_TABLE);

? ? }

? ? @Override

? ? publicvoidonUpgrade(SQLiteDatabase db,intoldVersion,int newVersion) {

? ? }

}


publicclassProviderActivityextends AppCompatActivity {

? ? privatestaticfinalString TAG = ProviderActivity.class.getSimpleName();

? ? private TextView displayTextView;

? ? private Handler mHandler;

? ? @Override

? ? protectedvoid onCreate(@Nullable Bundle savedInstanceState) {

? ? ? ? super.onCreate(savedInstanceState);

? ? ? ? setContentView(R.layout.activity_provider);

? ? ? ? displayTextView = (TextView) findViewById(R.id.displayTextView);

? ? ? ? mHandler =new Handler();

? ? ? ? getContentResolver().registerContentObserver(BookProvider.BOOK_CONTENT_URI, true,new ContentObserver(mHandler) {

? ? ? ? ? ? @Override

? ? ? ? ? ? publicboolean deliverSelfNotifications() {

? ? ? ? ? ? ? ? returnsuper.deliverSelfNotifications();

? ? ? ? ? ? }

? ? ? ? ? ? @Override

? ? ? ? ? ? publicvoidonChange(boolean selfChange) {

? ? ? ? ? ? ? ? super.onChange(selfChange);

? ? ? ? ? ? }

? ? ? ? ? ? @Override

? ? ? ? ? ? publicvoidonChange(boolean selfChange, Uri uri) {

? ? ? ? ? ? ? ? Toast.makeText(ProviderActivity.this, uri.toString(), Toast.LENGTH_SHORT).show();

? ? ? ? ? ? ? ? super.onChange(selfChange, uri);

? ? ? ? ? ? }

? ? ? ? });

? ? }

? ? publicvoid insert(View v) {

? ? ? ? ContentValues values =new ContentValues();

? ? ? ? values.put("_id",1123);

? ? ? ? values.put("name", "三國(guó)演義");

? ? ? ? getContentResolver().insert(BookProvider.BOOK_CONTENT_URI, values);

? ? }

? ? publicvoid delete(View v) {

? ? ? ? getContentResolver().delete(BookProvider.BOOK_CONTENT_URI, "_id = 4",null);

? ? }

? ? publicvoid update(View v) {

? ? ? ? ContentValues values =new ContentValues();

? ? ? ? values.put("_id",1123);

? ? ? ? values.put("name", "三國(guó)演義新版");

? ? ? ? getContentResolver().update(BookProvider.BOOK_CONTENT_URI, values , "_id = 1123",null);

? ? }

? ? publicvoid query(View v) {

? ? ? ? Cursor bookCursor = getContentResolver().query(BookProvider.BOOK_CONTENT_URI,newString[]{"_id", "name"},null,null,null);

? ? ? ? StringBuilder sb =new StringBuilder();

? ? ? ? while (bookCursor.moveToNext()) {

? ? ? ? ? ? Book book =newBook(bookCursor.getInt(0),bookCursor.getString(1));

? ? ? ? ? ? sb.append(book.toString()).append("\n");

? ? ? ? }

? ? ? ? sb.append("--------------------------------").append("\n");

? ? ? ? bookCursor.close();

? ? ? ? Cursor userCursor = getContentResolver().query(BookProvider.USER_CONTENT_URI,newString[]{"_id", "name", "sex"},null,null,null);

? ? ? ? while (userCursor.moveToNext()) {

? ? ? ? ? ? sb.append(userCursor.getInt(0))

? ? ? ? ? ? ? ? ? ? .append(userCursor.getString(1)).append(" ,")

? ? ? ? ? ? ? ? ? ? .append(userCursor.getInt(2)).append(" ,")

? ? ? ? ? ? ? ? ? ? .append("\n");

? ? ? ? }

? ? ? ? sb.append("--------------------------------");

? ? ? ? userCursor.close();

? ? ? ? displayTextView.setText(sb.toString());

? ? }

}


六丛肮、使用 Socket

Socket起源于 Unix赡磅,而 Unix 基本哲學(xué)之一就是“一切皆文件”,都可以用“打開 open –讀寫 write/read –關(guān)閉 close ”模式來(lái)操作宝与。Socket 就是該模式的一個(gè)實(shí)現(xiàn)焚廊,網(wǎng)絡(luò)的 Socket 數(shù)據(jù)傳輸是一種特殊的 I/O,Socket 也是一種文件描述符伴鳖。Socket 也具有一個(gè)類似于打開文件的函數(shù)調(diào)用: Socket()节值,該函數(shù)返回一個(gè)整型的Socket 描述符,隨后的連接建立榜聂、數(shù)據(jù)傳輸?shù)炔僮鞫际峭ㄟ^(guò)該 Socket 實(shí)現(xiàn)的。

常用的 Socket 類型有兩種:流式 Socket(SOCK_STREAM)和數(shù)據(jù)報(bào)式 Socket(SOCK_DGRAM)嗓蘑。流式是一種面向連接的 Socket须肆,針對(duì)于面向連接的 TCP 服務(wù)應(yīng)用;數(shù)據(jù)報(bào)式 Socket 是一種無(wú)連接的 Socket 桩皿,對(duì)應(yīng)于無(wú)連接的 UDP 服務(wù)應(yīng)用豌汇。

Socket 本身可以傳輸任意字節(jié)流。

談到Socket泄隔,就必須要說(shuō)一說(shuō) TCP/IP 五層網(wǎng)絡(luò)模型:

應(yīng)用層:規(guī)定應(yīng)用程序的數(shù)據(jù)格式拒贱,主要的協(xié)議 HTTP,F(xiàn)TP佛嬉,WebSocket逻澳,POP3 等;

傳輸層:建立“端口到端口” 的通信暖呕,主要的協(xié)議:TCP斜做,UDP;

網(wǎng)絡(luò)層:建立”主機(jī)到主機(jī)”的通信湾揽,主要的協(xié)議:IP瓤逼,ARP ,IP 協(xié)議的主要作用:一個(gè)是為每一臺(tái)計(jì)算機(jī)分配 IP 地址库物,另一個(gè)是確定哪些地址在同一子網(wǎng)霸旗;

數(shù)據(jù)鏈路層:確定電信號(hào)的分組方式,主要的協(xié)議:以太網(wǎng)協(xié)議戚揭;

物理層:負(fù)責(zé)電信號(hào)的傳輸诱告。

Socket 是連接應(yīng)用層與傳輸層之間接口(API)。


只實(shí)現(xiàn) TCP Socket 毫目。

Client 端代碼:

publicclassTCPClientActivityextendsAppCompatActivityimplements View.OnClickListener{

? ? privatestaticfinalString TAG = "TCPClientActivity";

? ? publicstaticfinalintMSG_RECEIVED = 0x10;

? ? publicstaticfinalintMSG_READY = 0x11;

? ? private EditText editText;

? ? private TextView textView;

? ? private PrintWriter mPrintWriter;

? ? private Socket mClientSocket;

? ? private Button sendBtn;

? ? private StringBuilder stringBuilder;

? ? privateHandler mHandler =new Handler(){

? ? ? ? @Override

? ? ? ? publicvoid handleMessage(Message msg) {

? ? ? ? ? ? switch (msg.what) {

? ? ? ? ? ? ? ? case MSG_READY:

? ? ? ? ? ? ? ? ? ? sendBtn.setEnabled(true);

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? case MSG_RECEIVED:

? ? ? ? ? ? ? ? ? ? stringBuilder.append(msg.obj).append("\n");

? ? ? ? ? ? ? ? ? ? textView.setText(stringBuilder.toString());

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? default:

? ? ? ? ? ? ? ? ? ? super.handleMessage(msg);

? ? ? ? ? ? }

? ? }

? ? };

? ? @Override

? ? protectedvoid onCreate(@Nullable Bundle savedInstanceState) {

? ? ? ? super.onCreate(savedInstanceState);

? ? ? ? setContentView(R.layout.tcp_client_activity);

? ? ? ? editText = (EditText) findViewById(R.id.editText);

? ? ? ? textView = (TextView) findViewById(R.id.displayTextView);

? ? ? ? sendBtn = (Button) findViewById(R.id.sendBtn);

? ? ? ? sendBtn.setOnClickListener(this);

? ? ? ? sendBtn.setEnabled(false);

? ? ? ? stringBuilder =new StringBuilder();

? ? ? ? Intent intent =newIntent(TCPClientActivity.this, TCPServerService.class);

? ? ? ? startService(intent);

? ? ? ? new Thread(){

? ? ? ? ? ? @Override

? ? ? ? ? ? publicvoid run() {

? ? ? ? ? ? ? ? connectTcpServer();

? ? ? ? ? ? }

? ? ? ? }.start();

? ? }

? ? privateString formatDateTime(long time) {

? ? ? ? returnnewSimpleDateFormat("(HH:mm:ss)").format(new Date(time));

? ? }

? ? privatevoid connectTcpServer() {

? ? ? ? Socket socket =null;

? ? ? ? while(socket ==null) {

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? socket =newSocket("localhost", 8888);

? ? ? ? ? ? ? ? mClientSocket = socket;

? ? ? ? ? ? ? ? mPrintWriter =newPrintWriter(new BufferedWriter(

? ? ? ? ? ? ? ? ? ? ? ? new OutputStreamWriter(socket.getOutputStream())

? ? ? ? ? ? ? ? ), true);

? ? ? ? ? ? ? ? mHandler.sendEmptyMessage(MSG_READY);

? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? // receive messageBufferedReader bufferedReader =null;

? ? ? ? try {

? ? ? ? ? ? bufferedReader =newBufferedReader(new InputStreamReader(socket.getInputStream()));

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? while(!isFinishing()) {

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? String msg = bufferedReader.readLine();

? ? ? ? ? ? ? ? if(msg !=null) {

? ? ? ? ? ? ? ? ? ? String time = formatDateTime(System.currentTimeMillis());

? ? ? ? ? ? ? ? ? ? String showedMsg = "server " + time + ":" + msg

? ? ? ? ? ? ? ? ? ? ? ? ? ? + "\n";

? ? ? ? ? ? ? ? ? ? mHandler.obtainMessage(MSG_RECEIVED, showedMsg).sendToTarget();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? }

? ? ? ? }

? ? }

? ? @Override

? ? publicvoid onClick(View v) {

? ? ? ? if(mPrintWriter !=null) {

? ? ? ? ? ? String msg = editText.getText().toString();

? ? ? ? ? ? mPrintWriter.println(msg);

? ? ? ? ? ? editText.setText("");

? ? ? ? ? ? String time = formatDateTime(System.currentTimeMillis());

? ? ? ? ? ? String showedMsg = "self " + time + ":" + msg + "\n";

? ? ? ? ? ? stringBuilder.append(showedMsg);

? ? ? ? }

? ? }

? ? @Override

? ? protectedvoid onDestroy() {

? ? ? ? if(mClientSocket !=null) {

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? mClientSocket.shutdownInput();

? ? ? ? ? ? ? ? mClientSocket.close();

? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? super.onDestroy();

? ? }

}

Server端代碼:

publicclassTCPServerServiceextends Service {

? ? privatestaticfinalString TAG = "TCPServerService";

? ? privatebooleanisServiceDestroyed =false;

? ? privateString[] mMessages =new String[]{

? ? ? ? ? ? "Hello! Body!",

? ? ? ? ? ? "用戶不在線蔬啡!請(qǐng)稍后再聯(lián)系诲侮!",

? ? ? ? ? ? "請(qǐng)問(wèn)你叫什么名字呀?",

? ? ? ? ? ? "厲害了箱蟆,我的哥沟绪!",

? ? ? ? ? ? "Google 不需要***是真的嗎?",

? ? ? ? ? ? "扎心了空猜,老鐵U来取!辈毯!"? ? };

? ? @Override

? ? publicvoid onCreate() {

? ? ? ? newThread(new TCPServer()).start();

? ? ? ? super.onCreate();

? ? }

? ? @Override

? ? publicvoid onDestroy() {

? ? ? ? isServiceDestroyed =true;

? ? ? ? super.onDestroy();

? ? }

? ? @Nullable

? ? @Override

? ? public IBinder onBind(Intent intent) {

? ? ? ? returnnull;

? ? }

? ? privateclassTCPServerimplements Runnable {

? ? ? ? @Override

? ? ? ? publicvoid run() {

? ? ? ? ? ? ServerSocket serverSocket =null;

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? serverSocket =newServerSocket(8888);

? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? ? ? return;

? ? ? ? ? ? }

? ? ? ? ? ? while(!isServiceDestroyed) {

? ? ? ? ? ? ? ? // receive request from clienttry {

? ? ? ? ? ? ? ? ? ? finalSocket client = serverSocket.accept();

? ? ? ? ? ? ? ? ? ? Log.d(TAG, "=============== accept ==================");

? ? ? ? ? ? ? ? ? ? new Thread(){

? ? ? ? ? ? ? ? ? ? ? ? @Override

? ? ? ? ? ? ? ? ? ? ? ? publicvoid run() {

? ? ? ? ? ? ? ? ? ? ? ? ? ? try {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? responseClient(client);

? ? ? ? ? ? ? ? ? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? }.start();

? ? ? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? }

? ? privatevoidresponseClient(Socket client)throws IOException {

? ? ? ? //receive messageBufferedReader in =new BufferedReader(

? ? ? ? ? ? ? ? new InputStreamReader(client.getInputStream()));

? ? ? ? //send messagePrintWriter out =new PrintWriter(

? ? ? ? ? ? ? ? new BufferedWriter(

? ? ? ? ? ? ? ? ? ? ? ? new OutputStreamWriter(

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? client.getOutputStream())),true);

? ? ? ? out.println("歡迎來(lái)到聊天室坝疼!");

? ? ? ? while(!isServiceDestroyed) {

? ? ? ? ? ? String str = in.readLine();

? ? ? ? ? ? Log.d(TAG, "message from client: " + str);

? ? ? ? ? ? if(str ==null) {

? ? ? ? ? ? ? ? return;

? ? ? ? ? ? }

? ? ? ? ? ? Random random =new Random();

? ? ? ? ? ? intindex = random.nextInt(mMessages.length);

? ? ? ? ? ? String msg = mMessages[index];

? ? ? ? ? ? out.println(msg);

? ? ? ? ? ? Log.d(TAG, "send Message: " + msg);

? ? ? ? }

? ? ? ? out.close();

? ? ? ? in.close();

? ? ? ? client.close();

? ? }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市谆沃,隨后出現(xiàn)的幾起案子孙援,更是在濱河造成了極大的恐慌,老刑警劉巖穆咐,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件遇伞,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡据沈,警方通過(guò)查閱死者的電腦和手機(jī)哟沫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)锌介,“玉大人嗜诀,你說(shuō)我怎么就攤上這事】谆觯” “怎么了隆敢?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)融击。 經(jīng)常有香客問(wèn)我筑公,道長(zhǎng),這世上最難降的妖魔是什么尊浪? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任匣屡,我火速辦了婚禮,結(jié)果婚禮上拇涤,老公的妹妹穿的比我還像新娘捣作。我一直安慰自己,他們只是感情好鹅士,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布券躁。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪也拜。 梳的紋絲不亂的頭發(fā)上以舒,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音慢哈,去河邊找鬼蔓钟。 笑死,一個(gè)胖子當(dāng)著我的面吹牛卵贱,可吹牛的內(nèi)容都是我干的滥沫。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼键俱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼兰绣!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起编振,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤缀辩,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后党觅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體雌澄,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年杯瞻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片炫掐。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡魁莉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出募胃,到底是詐尸還是另有隱情旗唁,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布痹束,位于F島的核電站检疫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏祷嘶。R本人自食惡果不足惜屎媳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望论巍。 院中可真熱鬧烛谊,春花似錦、人聲如沸嘉汰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至双泪,卻和暖如春持搜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背焙矛。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工葫盼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人薄扁。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓剪返,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親邓梅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子脱盲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344