IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 安卓IPC机制(二) -> 正文阅读

[移动开发]安卓IPC机制(二)

?? 1.安卓中的IPC方式

1.1 Bundle

💡 bundle就不多写了,只需要注意,四大组件除ContentProvider之外,其它组件都支持bundle

1.2使用文件共享

💡 通过共享文件来进行进程间通信,不多说,需要注意,安卓提供的轻量级存储方案SharedPreferences,其也属于文件系统的一种,但由于其有一定的缓存策略,使得在内存里面有一份SharedPreferences的缓存,这会造成在多进程下使用SharedPreferences有一定的几率会丢失数据。

1.3使用Messenger

💡 可以通过Messenger实现进程间的通信,其底层实现是aidl,Messenger对aidl进行了封装,一次只可以处理一次请求,是一种轻量级的IPC方案,同时由于一次只处理一个请求,因此没有必要考虑同步问题,但是不适合在大量的并发请求里面使用。

3.3.1 实现方式

  • MyConstants
package com.example.artandroidlearn;

public class MyConstants {
    public static final int MSG_FROM_CLIENT = 0;
    public static final int MSG_FROM_SERVICE = 2;
}
  • 服务端代码示例:
package com.example.artandroidlearn.Service;

import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.example.artandroidlearn.MyConstants;

public class MessengerService extends Service {
    private static final String TAG = "MessengerService";

    private static class MessengerHandler extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case MyConstants.MSG_FROM_CLIENT:
										//获取客户端消息
                    Log.d(TAG, msg.getData().getString("msg"));
										//回复客户端消息,接收定义的messenger
                    Messenger messenger = msg.replyTo;
                    Message reply = Message.obtain(null, MyConstants.MSG_FROM_SERVICE);
                    Bundle bundle = new Bundle();
                    bundle.putString("reply", "service");
                    reply.setData(bundle);
                    try {
												//开始回复
                        messenger.send(reply);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
		
		//回复客户端消息,接收定义的messenger
    private final Messenger messenger = new Messenger(new MessengerHandler());

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }
}
  • 客户端实现代码示例
package com.example.artandroidlearn.activity;

import androidx.annotation.NonNull;
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.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

import com.example.artandroidlearn.Service.MessengerService;
import com.example.artandroidlearn.MyConstants;
import com.example.artandroidlearn.R;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private Messenger messenger;
    /**
    *
    ***这里有一个疑问需要备注一下,此处定义的ServiceConnection如何与Service建立连接呢?**
    *后续再看
		**/
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //给服务端发送消息
						messenger = new Messenger(service);
            Message message = Message.obtain(null, MyConstants.MSG_FROM_CLIENT);
            Bundle data = new Bundle();
            data.putString("msg", "hello,this is client");
            message.setData(data);
            //定义处理来自服务端消息的messenger
            message.replyTo = messenger1;
            try {
                messenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

		//定义处理服务端消息messenger
    private Messenger messenger1 = new Messenger(new MessengerHandler());
		

		//接收并处理来自服务端消息的类
    private static class MessengerHandler extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
								//处理来自服务端的消息
                case MyConstants.MSG_FROM_SERVICE:
                    Log.d(TAG, msg.getData().getString("reply"));
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this, MessengerService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
    }

    @Override
    public void addContentView(View view, ViewGroup.LayoutParams params) {
        super.addContentView(view, params);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(serviceConnection);
    }

1.3.2Messenger工作流程图

在这里插入图片描述

💡 Messenger进行消息传递,必须将数据放入Message里面,通过Messenger 来传递Message ,由于Message 支持的数据类型只有whatarg1arg2bundlereplyToobject ,但由于object 只能传输实现了Paracelable 接口的数据,因此实际上只有除object几个。

1.4AIDL

1.4.1 AIDL支持的数据类型

  1. 基本数据类型(int、long、char、boolean、double等);
  2. String和CharSequence;
  3. List,只支持ArrayList且里面的元素也要被AIDL支持;
  4. Map,只支持HashMap,且里面的元素也要被AIDL支持;
  5. 所有实现了Paracelable接口的对象;
  6. AIDL,AIDL接口本身可以在AIDL文件中使用。

💡 1.自定义的Paracelable对象和AIDL对象需要显示的import进AIDL文件,如果需要使用自定义的Paracelable对象,需要创建同名的AIDL文件;

2.在AIDL文件中引入Paracelable对象的对应AIDL文件时,需要使用paracelable进行修饰,除基本类型外,在AIDL文件中其它类型参数都要使用in、out、inout修饰符修饰,其中in代表输入型参数、out代表输出型参数、inout为前两者的结合;
3.需要根据实际情况去指定参数类型,不能一概使用out或inout,否则会带来开销;
4.AIDL接口只支持声明方法,不支持声明静态常量。

1.4.2 实现实例

  • AIDL文件实现
// IBookManager.aidl
package com.example.artandroidlearn;
import com.example.artandroidlearn.Book;
import com.example.artandroidlearn.IonNewBookArrivedListener;

// Declare any non-default types here with import statements

interface IBookManager {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
    List<Book> getBookList();
    void addBook(in Book book);
    void registerListener(IonNewBookArrivedListener listener);
    void unregisterListener(IonNewBookArrivedListener listener);
}

// IonNewBookArrivedListener.aidl
//回调监听接口,监听数据发生变化,通知观察者,典型的观察者模式
package com.example.artandroidlearn;
import com.example.artandroidlearn.Book;

interface IonNewBookArrivedListener{
    void onNewBookArrived(in Book newBook);
}

// Book.aidl
package com.example.artandroidlearn;

// Declare any non-default types here with import statements

parcelable Book;
  • dao类
package com.example.artandroidlearn;

import android.os.Parcel;
import android.os.Parcelable;

import androidx.annotation.NonNull;

public class Book implements Parcelable {

    public int bookId;
    public String bookName;

    public Book() {
    }

    public Book(int bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(bookId);
        dest.writeString(bookName);
    }

    public static final Creator<Book> CREATOR = new Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    protected Book(Parcel in) {
        bookId = in.readInt();
        bookName = in.readString();
    }

    @NonNull
    @Override
    public String toString() {
        return bookId + ":" + bookName;
    }
}
  • 远程服务端Service实现
package com.example.artandroidlearn.Service;

import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;

import androidx.annotation.Nullable;

import com.example.artandroidlearn.Book;
import com.example.artandroidlearn.IBookManager;
import com.example.artandroidlearn.IonNewBookArrivedListener;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;

public class BookManagerService extends Service {

    private static final String TAG = "BookManagerService";
    private AtomicBoolean mIsServiceDestroyed = new AtomicBoolean(false);

/**
*此处注释是原监听listener的实现
**/
//    private CopyOnWriteArrayList<IonNewBookArrivedListener> mOnNewBookArrivedListeners=new CopyOnWriteArrayList<>();

    private RemoteCallbackList<IonNewBookArrivedListener> mListenerRemoteCallbackList = new RemoteCallbackList<>();

    private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
    private Binder mBinder = new IBookManager.Stub() {

        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            /**
             * 权限判断 方法2
             * **/
            int check = checkCallingOrSelfPermission("com.example.artandroidlearn.ACCESS_BOOK");
            if (check == PackageManager.PERMISSION_DENIED) {
                return false;
            }
            String packageName = null;
            String[] packages = getPackageManager().getPackagesForUid(getCallingUid());
            if (packages != null && packages.length > 0) {
                packageName = packages[0];
            }
            if (!packageName.startsWith("com.example")) {
                return false;
            }
            return super.onTransact(code, data, reply, flags);
        }

        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public List<Book> getBookList() throws RemoteException {
            return mBookList;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            mBookList.add(book);
        }

        @Override
        public void registerListener(IonNewBookArrivedListener listener) throws RemoteException {

/**
*此处注释是原监听接口的实现
**/
//            if (!mOnNewBookArrivedListeners.contains(listener)) {
//                mOnNewBookArrivedListeners.add(listener);
//            } else {
//                Log.d(TAG, "Listener already exists");
//            }
//            Log.d(TAG, "registerListener ,current size:" + mOnNewBookArrivedListeners.size());

            mListenerRemoteCallbackList.register(listener);
        }

        @Override
        public void unregisterListener(IonNewBookArrivedListener listener) throws RemoteException {

/**
*注意,此处代码,是monNewBookArrivedListener的注销操作,但是呢由于binder是多进程,实际使用的
*INewBookArrivedListener对象并不是monNewBookArrivedListener对象,而是通过binder传递的新的对象
*,要想使用解注册功能,需要使用RemoteCallbackList,使用这个List后,它在里面以map的形式保存了对端
*对象,因此可以实现同时解注销的功能。
**/
/**
*此处注释是原监听接口的实现
**/
//            if (mOnNewBookArrivedListeners.contains(listener)) {
//                mOnNewBookArrivedListeners.remove(listener);
//                Log.d(TAG, "register listener succeed");
//            } else {
//                Log.d(TAG, "not found,can not unregister");
//            }
//            Log.d(TAG, "unregisterListener ,current size:" + mOnNewBookArrivedListeners.size());
            mListenerRemoteCallbackList.unregister(listener);
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        mBookList.add(new Book(1, "www"));
        mBookList.add(new Book(2, "kkk"));
        new Thread(new ServiceWork()).start();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        /**
         * 权限判断 方法1
         * **/
        int check = checkCallingOrSelfPermission("com.example.artandroidlearn.ACCESS_BOOK");
        if (check == PackageManager.PERMISSION_DENIED) {
            return null;
        }
        return mBinder;
    }

    @Override
    public void onDestroy() {
        mIsServiceDestroyed.set(true);
        super.onDestroy();
    }

    private void onNewBookArrived(Book book) throws RemoteException {
        mBookList.add(book);

/**
*此处注释是原监听接口的实现
**/
//        Log.d(TAG, "onNewBookArrived ,notify listeners:" + mOnNewBookArrivedListeners);
//        for (IonNewBookArrivedListener ionNewBookArrivedListener : mOnNewBookArrivedListeners) {
//            ionNewBookArrivedListener.onNewBookArrived(book);
//            Log.d(TAG, "onNewBookArrived ,notify listener:" + ionNewBookArrivedListener);
//        }

/**
*monNewBookArrivedListener的获取操作,必须使用mListenerRemoteCallbackList.beginBroadcast()
*才能获取到监听接口
**/
        final int n = mListenerRemoteCallbackList.beginBroadcast();
        for (int i = 0; i < n; i++) {
            IonNewBookArrivedListener newBookArrivedListener = mListenerRemoteCallbackList.getBroadcastItem(i);
            if (newBookArrivedListener != null) {
                try {
                    newBookArrivedListener.onNewBookArrived(book);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
/**
*结束相关操作
**/
        mListenerRemoteCallbackList.finishBroadcast();
    }

    private class ServiceWork implements Runnable {

        @Override
        public void run() {
            while (!mIsServiceDestroyed.get()) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                int bookId = mBookList.size() + 1;
                Book newBook = new Book(bookId, "new book#" + bookId);
                try {
                    onNewBookArrived(newBook);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

💡 这里面实现了Stub接口并将其作为binder返回,注意使用了CopyOnWriteArrayList ,由于AIDL方法是在binder线程池里面运行,所以需要使用它来来保证线程同步,这里备注一下,由于AIDL里面所支持的是抽象的List,虽然服务端使用的是CopyOnWriteArrayList ,但是在客户端还是返回的ArrayList

  • 客户端实现
package com.example.artandroidlearn.activity;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.example.artandroidlearn.Book;
import com.example.artandroidlearn.IonNewBookArrivedListener;
import com.example.artandroidlearn.Service.BookManagerService;
import com.example.artandroidlearn.IBookManager;
import com.example.artandroidlearn.R;

import java.util.List;

public class BookManagerActivity extends Activity {

    private static final String TAG = "BookManagerActivity";
    private static final int MESSAGE_NEW_BOOK_ARRIVED = 1;

    private IBookManager mRemoteBookManager;

    /**
     * 设置死亡代理
     **/
    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
/**
*binderDied运行在binder线程池里面,binder死亡可在此设置重新连接服务。
**/
        @Override
        public void binderDied() {
            if (mRemoteBookManager == null) {
                return;
            }
            mRemoteBookManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
            mRemoteBookManager = null;
        }
    };
		/**
		*处理新来的对象
		**/
    private static Handler mHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case MESSAGE_NEW_BOOK_ARRIVED:
                    Log.d(TAG, "receive new book:" + msg.obj);
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    };

    private ServiceConnection mConnection = new ServiceConnection() {
/**
*onServiceConnected运行在UI线程里面,binder死亡可在此设置重新连接服务。
**/
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IBookManager bookManager = IBookManager.Stub.asInterface(service);
            try {
                mRemoteBookManager = bookManager;
                /**
                 * 设置死亡代理
                 * **/
                mRemoteBookManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
                List<Book> bookList = bookManager.getBookList();
                Log.i(TAG, "query book list,list type:" + bookList.getClass().getCanonicalName());
                bookManager.addBook(new Book(3, "ks"));
                Log.i(TAG, "query book list:" + bookList.toString());
                bookManager.addBook(new Book(3, "ks"));
                bookList = bookManager.getBookList();
                Log.i(TAG, "query book list:" + bookList.toString());
								/**
								*注册监听接口
								***/
                bookManager.registerListener(monNewBookArrivedListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
		

/**
*原监听接口的实现
**/
    private IonNewBookArrivedListener monNewBookArrivedListener = new IonNewBookArrivedListener.Stub() {
        @Override
        public void onNewBookArrived(Book newBook) throws RemoteException {
            mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED, newBook).sendToTarget();
        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_book_manager);
        Intent intent = new Intent(this, BookManagerService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        if (mRemoteBookManager != null && mRemoteBookManager.asBinder().isBinderAlive()) {
            try {
                mRemoteBookManager.unregisterListener(monNewBookArrivedListener);
                Log.d(TAG, "unregisterListener:" + monNewBookArrivedListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        unbindService(mConnection);
        super.onDestroy();
    }
}

💡 注意:AIDL客户端调服务端,在服务端没有返回数据前,客户端会挂起,因此当服务端比较耗时,需要避免客户端的耗时操作,或将客户端的相应操作放在非UI线程中里面,同样道理,服务端调客户端方法,如此例调listener,若listener耗时,则会导致服务端耗时,因此需要将对应的运行listener操作放在子线程里面去。

1.5 ContentProvider

💡 注意:ContentProvider底层也是使用的binder进行数据通信。

3.5.1 使用示例(接上例)

  • 数据层
package com.example.artandroidlearn;

import androidx.annotation.NonNull;

public class User {
    public int userId;
    public String userName;
    public int sex;

    public User() {
    }

    @NonNull
    @Override
    public String toString() {
        return "name=" + this.userName + ",id=" + userId + "sex=" + this.sex;
    }
}
  • 数据库访问:定义数据表
package com.example.artandroidlearn.db;

import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class DbOpenHelper extends SQLiteOpenHelper {

    private static final String DB_NAME = "book_provider.db";
    public static final String BOOK_TABLE_NAME = "book";
    public static final String USER_TABLE_NAME = "user";

    private static final int DB_VERSION = 1;
    private String CREATE_BOOK_TABLE = "create table if not exists " + BOOK_TABLE_NAME +
            "(_id INTEGER PRIMARY KEY,name TEXT)";
    private String CREATE_USER_TABLE = "create table if not exists " + USER_TABLE_NAME +
            "(_id integer primary key,name text,sex text)";

    public DbOpenHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    public DbOpenHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    public DbOpenHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version, @Nullable DatabaseErrorHandler errorHandler) {
        super(context, name, factory, version, errorHandler);
    }

    public DbOpenHelper(@Nullable Context context, @Nullable String name, int version, @NonNull SQLiteDatabase.OpenParams openParams) {
        super(context, name, version, openParams);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK_TABLE);
        db.execSQL(CREATE_USER_TABLE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}
  • provider层
package com.example.artandroidlearn.provider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.example.artandroidlearn.db.DbOpenHelper;

import java.net.URI;

public class BookProvider extends ContentProvider {
    private static String TAG = "BookProvider";
    private static final String AUTHORITY = "com.example.artandroidlearn.provider.BookProvider";

    public static final Uri BOOK_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/book");
    public static final int BOOK_URI_CODE = 0;
    public static final int USER_URI_CODE = 1;
    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    private SQLiteDatabase mDb;
    private Context mContext;

    static {
        sUriMatcher.addURI(AUTHORITY, "book", BOOK_URI_CODE);
        sUriMatcher.addURI(AUTHORITY, "user", USER_URI_CODE);
    }
/**
*注意provider的onCreate运行在主线程里面,其它五个方法运行在其它线程
***/

    @Override
    public boolean onCreate() {
        Log.d(TAG, "onCreate,current thread:" + Thread.currentThread().getName());
        mContext = getContext();
        initProviderData();
        return false;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        Log.d(TAG, "query,current thread:" + Thread.currentThread().getName());
        String tableName = getTableName(uri);
        if (tableName == null) {
            throw new IllegalArgumentException("Unsupported Uri: " + uri);
        }
        return mDb.query(tableName, projection, selection, selectionArgs, null, null, sortOrder, null);
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        Log.d(TAG, "getType,current thread:" + Thread.currentThread().getName());
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        Log.d(TAG, "insert,current thread:" + Thread.currentThread().getName());
        String tableName = getTableName(uri);
        if (tableName == null) {
            throw new IllegalArgumentException("Unsupported Uri: " + uri);
        }
        mDb.insert(tableName, null, values);
        mContext.getContentResolver().notifyChange(uri, null);
        return uri;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        Log.d(TAG, "delete,current thread:" + Thread.currentThread().getName());
        String tableName = getTableName(uri);
        if (tableName == null) {
            throw new IllegalArgumentException("Unsupported Uri: " + uri);
        }
        int count = mDb.delete(tableName, selection, selectionArgs);
        if (count > 0) {
            getContext().getContentResolver().notifyChange(uri, null);
        }
        return count;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        Log.d(TAG, "update,current thread:" + Thread.currentThread().getName());
        String tableName = getTableName(uri);
        if (tableName == null) {
            throw new IllegalArgumentException("Unsupported Uri: " + uri);
        }
        int row = mDb.update(tableName, 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;
    }

    private void initProviderData() {
        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(2,'android');");
        mDb.execSQL("insert into book values(3,'Ios');");
        mDb.execSQL("insert into book values(4,'test');");
        mDb.execSQL("insert into user values(1,'jake',1);");
        mDb.execSQL("insert into user values(2,'jake1',0);");
    }
}

💡 注意:provider的注册必须要声明authorities ,如下所示,一般provider的访问都是并发的,因此需要做好线程同步操作。注意除了使用provider的增删改查进行操作,还可以通过ContentResolvercall方法来完成自定义操作

<provider
            android:name=".provider.BookProvider"
            android:authorities="com.example.artandroidlearn.provider.BookProvider"
            android:permission="com.example.PROVIDER"
            android:process=":provider" />
  • activity
package com.example.artandroidlearn.activity;

import androidx.appcompat.app.AppCompatActivity;

import com.example.artandroidlearn.Book;
import com.example.artandroidlearn.R;
import com.example.artandroidlearn.User;

import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;

public class ProviderActivity extends AppCompatActivity {
    public static final String TAG="ProviderActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_provider);
        Uri uri=Uri.parse("content://com.example.artandroidlearn.provider.BookProvider");
//        getContentResolver().query(uri,null,null,null,null);
//        getContentResolver().query(uri,null,null,null,null);
//        getContentResolver().query(uri,null,null,null,null);
        Uri bookUri=Uri.parse("content://com.example.artandroidlearn.provider.BookProvider/book");
        ContentValues contentValues=new ContentValues();
        contentValues.put("_id",2);
        contentValues.put("name","testeeee");
        getContentResolver().insert(bookUri,contentValues);
        Cursor bookCursor=getContentResolver().query(bookUri,new String[]{"_id","name"},
                null,null,null);
        while (bookCursor.moveToNext()){
            Book book=new Book();
            book.bookId=bookCursor.getInt(0);
            book.bookName=bookCursor.getString(1);
            Log.d(TAG,"query book: "+book.toString());
        }
        bookCursor.close();

        Uri userUri=Uri.parse("content://com.example.artandroidlearn.provider.BookProvider/user");
        getContentResolver().insert(bookUri,contentValues);
        Cursor userCursor=getContentResolver().query(userUri,new String[]{"_id","name","sex"},
                null,null,null);
        while (userCursor.moveToNext()){
            User user=new User();
            user.userId=userCursor.getInt(0);
            user.userName=userCursor.getString(1);
            user.sex=userCursor.getInt(2);
            Log.d(TAG,"query user: "+user.toString());
        }
        userCursor.close();
    }
}

1.6 使用Socket

💡 注意需要声明网络权限

1.6.1 代码示例

  • 服务端示例
package com.example.artandroidlearn.Service;

import android.app.Service;
import android.content.Intent;
import android.os.FileUtils;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.Nullable;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;

public class TCPServerService extends Service {
    private boolean mIsServiceDestroyed = false;
    private String[] mDefinedMessages = new String[]{
            "hello",
            "what is your name",
            "have a nice day",
            "chat with many people",
            "have a joke"
    };

    @Override
    public void onCreate() {
        Log.d("whll", "www");
        new Thread(new TcpServer()).start();
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        mIsServiceDestroyed = true;
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private class TcpServer implements Runnable {

        @Override
        public void run() {
            ServerSocket serverSocket = null;
            try {
                serverSocket = new ServerSocket(8688);
            } catch (IOException e) {
                Log.d("whl1", "ttt");
                e.printStackTrace();
                return;
            }
            while (!mIsServiceDestroyed) {
                try {
                    final Socket client = serverSocket.accept();
                    System.out.println("accept");
                    new Thread(() -> {
                        try {
                            responseClient(client);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }).start();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void responseClient(Socket client) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
        PrintWriter out = new PrintWriter(new BufferedWriter(new
                OutputStreamWriter(client.getOutputStream())), true);
        out.println("welcome");
        while (!mIsServiceDestroyed) {
            String str = in.readLine();
            System.out.println("msg from client: " + str);
            if (str == null) {
                break;
            }
            int i = new Random().nextInt(mDefinedMessages.length);
            out.println(mDefinedMessages[i]);
            System.out.println("send to client: " + mDefinedMessages[i]);
        }
        System.out.println("client quit");
        out.close();
        in.close();
        client.close();
    }
}
  • 客户端示例
package com.example.artandroidlearn.activity;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.example.artandroidlearn.R;
import com.example.artandroidlearn.Service.TCPServerService;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class TCPClientActivity extends AppCompatActivity implements View.OnClickListener {
    private static final int MESSAGE_RECEIVE_NEW_MSG = 1;
    private static final int MESSAGE_SOCKET_CONNECTED = 2;

    private Button mSendButton;
    private TextView mMessageTextView;
    private EditText mMessageEditView;

    private PrintWriter mPrintWriter;
    private Socket mClientSocket;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case MESSAGE_RECEIVE_NEW_MSG:
                    mMessageTextView.setText(mMessageTextView.getText() + (String) msg.obj);
                    break;
                case MESSAGE_SOCKET_CONNECTED:
                    mSendButton.setEnabled(true);
                    break;
                default:
                    super.handleMessage(msg);
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tcpclient);
        mMessageTextView = (TextView) findViewById(R.id.msg_container);
        mSendButton = (Button) findViewById(R.id.send);
//        mSendButton.setEnabled(true);
        mSendButton.setOnClickListener(this);
        mMessageEditView = (EditText) findViewById(R.id.msg);
        Intent service = new Intent(this, TCPServerService.class);
        startService(service);
        new Thread() {
            @Override
            public void run() {
                connectTCPServer();
            }
        }.start();

    }

    @Override
    protected void onDestroy() {
        if (mClientSocket != null) {
            try {
                mClientSocket.shutdownInput();
                mClientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        super.onDestroy();
    }

    @Override
    public void onClick(View v) {
        Log.d("whl", "test");
        if (v == mSendButton) {
            final String msg = mMessageEditView.getText().toString();

            if (!TextUtils.isEmpty(msg) && mPrintWriter != null) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        mPrintWriter.println(msg);
                    }
                }).start();
                mMessageEditView.setText("");
                String time = formatDateTime(System.currentTimeMillis());
                final String showedMsg = "server " + time + ": " + msg + "\n";
                mMessageTextView.setText(mMessageTextView.getText() + showedMsg);
            }
        }
    }

    private void connectTCPServer() {
        Socket socket = null;
        while (socket == null) {
            try {
                Log.d("whl", "test11");
                System.out.println("connect server success");
                socket = new Socket("localhost", 8688);
                mClientSocket = socket;
                mPrintWriter = new PrintWriter(new BufferedWriter(new
                        OutputStreamWriter(socket.getOutputStream())), true);
                mHandler.sendEmptyMessage(MESSAGE_SOCKET_CONNECTED);
                System.out.println("connect server success");
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                SystemClock.sleep(1000);
                e.printStackTrace();
            }
        }
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            while (!isFinishing()) {
                String msg = br.readLine();
                System.out.println("receive: " + msg);
                if (msg != null) {
                    String time = formatDateTime(System.currentTimeMillis());
                    final String showedMsg = "server " + time + ": " + msg + "\n";
                    mHandler.obtainMessage(MESSAGE_RECEIVE_NEW_MSG, showedMsg).sendToTarget();
                }
            }
            System.out.println("quit...");
            br.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String formatDateTime(Long time) {
        return new SimpleDateFormat("HH:mm:ss").format(new Date(time));
    }
}
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:46:08  更:2022-10-17 12:48:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 21:21:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码