前言
最近过完年了, 打算把自己的 Android 知识都整理一下
Android 技能书系列:
Android 技能树 动画小结
Android 技能树 View 小结
Android 技能树 Activity 小结
Android 技能树 View 事件体系小结
Android 技能树 Android 存储路径及 IO 操作小结
这次是讲 Android 存储路径及 IO 的基本操作因为我们在开发的时候会经常这种方便的需求这篇文章的内容我写的可能很少, 都没有细写别吐槽 o(︶)o
其他不多说, 先上脑图:
多进程小结脑图下载
多进程
进程与线程
有时候面试别人的时候, 我会问说什么是多进程, 怎么开启多进程, 他们会说 new 一个 Thread 所以很多人会把多进程和多线程弄错我就简单说明下: 一般来说我们启动一个 APP, 就是一个进程, 然后这个 APP 里面有很多线程, 最熟悉的就是我们平常的主线程 (UI) 线程所以进程是包含线程的
当然我这讲的就比较通俗了: 可以看下其他类似的文章介绍: Android-- 进程与线程
开启多进程
其实开启多进程很简单只需要在 AndroidManifest.xml 的四大组件中添加 android:process 即可这时候就会运行在你定义好的名字的进程中了
多进程开启后的问题
简单来说就是同步会有问题我们刚才说了一般来说启动一个 APP, 就创建了一个进程, 然后所有的东西都在这个进程里面这时候你对某个 Activity 定义了 android:process 他就运行在另外一个进程了这时候 Application 也会重新创建一次, 在这个新的进程中这个 Activity 也会在这个新的进程中而且我们建立的一些实体类对象也是不同进程里面各自产生自己的副本对象互不关联
所以我们知道了一些线程同步单例模式都无效了, 因为对象是各个进程中有副本, 同步锁的锁对象都不是同一个对象当然线程同步机制就失效了
其中 SharePreferences 本身是一个文件, 所以不受多进程的影响, 但是因为 SharePreferences 不支持多个进程同时执行写操作, 所以有可能会导致出现数据丢失等问题甚至是并发读和写也可能有问题但是如果你只是一个进程写, 一个进程读, 而且不是同时, 那就问题不大了
进程间通信
既然说了多进程, 如果我们现在就是二个进程进行通信怎么办在讲如何通信之前, 我们可以先看下相关的基础, 那就是序列化及反序列化
我们看序列化有哪些:
我们可以看到, 序列化一般主要是二个, 那就是 Serialzable 和 Parcelable
具体的时候都很简单下面写大致提下这二个的使用
Serialzable
User.java (要传递的实体类)
- public class User implements Serializable {
- private static final long serialVersionUID = 512345678910L;
- public int userId;
- public String userName;
- public boolean isMale;
- public User(int userId, String userName, boolean isMale) {
- this.userId = userId;
- this.userName = userName;
- this.isMale = isMale;
- }
- }
我们只要直接将我们的类实现 Serializable 接口即可很简单这里我提一下 serialVersionUID 因为我们平时写都不会写这个也是正常使用但是比如我把这个 User 对象通过 ObjectOutputStream 序列化后写到了本地文件, 但是这时候我们把我们的 User 对象里面的属性改了, 比如增加了一项:
public boolean haha;
然后再通过 ObjectInputStream 去读取出来就会抛异常因为反序列化会和序列化时候的 serialVersionUID 进行比较, 如果不同, 直接不进行反序列化了, 就抛出异常但是我们不手动写这个值, 它会根据当前这个类结构去生成的 hash 值为值所以当我们把这个类结构更改后, 再去反序列化就报错了
- Parcelable
- public class User implements Parcelable {
- public int userId;
- public String userName;
- public boolean isMale;
- public User(int userId, String userName, boolean isMale) {
- this.userId = userId;
- this.userName = userName;
- this.isMale = isMale;
- }
- protected User(Parcel in) {
- userId = in.readInt();
- userName = in.readString();
- isMale = in.readInt() == 1;
- }
- public static final Creator<User> CREATOR = new Creator<User>() {
- @Override
- public User createFromParcel(Parcel in) {
- return new User(in);
- }
- @Override
- public User[] newArray(int size) {
- return new User[size];
- }
- };
- @Override
- public int describeContents() {
- return 0;
- }
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(userId);
- dest.writeString(userName);
- dest.writeInt(isMale ? 1 : 0);
- }
- }
你写的类实现了 Parcelable 后 AS 会自动提示, 你就按照他的提示生成相应的代码即可这里我们只要注意这么几个地方:
1. 我们在序列化前, 总要先把这个类实例化成对象, 然后把相应的内容赋值进去是吧, 所以上面代码中, 我写了个构造函数:
- public User(int userId, String userName, boolean isMale) {
- this.userId = userId;
- this.userName = userName;
- this.isMale = isMale;
- }
这样我们写代码的时候就
new User(10,"dyp",true)
(当然你也可以写 setXXX 方法去设置)
2. 我们要序列化了, 我们把我们的这个类里面的属性值都写进 Parcel 中, 就好比我们是拿了个本子, 一行行的记下内容, 然后等会一行行的取出来所以我们看到了我们是按照顺序先记录下来, 所以等会还原的时候也要按顺序取出来相应的值所以顺序很重要
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- // 记下 userId, 因为是 Int 类型, 所以用 writeInt
- dest.writeInt(userId);
- // 记下 userName, 因为是 String 类型, 所以用 writeString
- dest.writeString(userName);
- /* 记下 isMale , 因为是 Boolean 类型,
- 但是没有 writeBoolean, 只有 writeBooleanArray,
- 所以我们用 writeInt()来记录, 1 是 true,0 是 false
- 额外说下 writeBooleanArray 内部其实还是用 writeInt 来记录的
- */
- dest.writeInt(isMale ? 1 : 0);
- }
3. 我们最后传到了其他的进程, 肯定是要从 Parcel 里面把我们的对象给还原出来, 肯定是先 new 一个 User 对象, 然后把各种我们前面第二步保存好的值给它重新赋值
- public static final Creator<User> CREATOR = new Creator<User>() {
- @Override
- public User createFromParcel(Parcel in) {
- // 这里是不是我们先进行了 new 一个对象, 同时把 Parcel 对象传入
- return new User(in);
- }
- @Override
- public User[] newArray(int size) {
- return new User[size];
- }
- };
- protected User(Parcel in) {
- // 然后我们再生成这个对象的同时, 再把这个对象的属性都赋值好, 切记要按照上面写入的顺序来读取出来赋值
- userId = in.readInt();
- userName = in.readString();
- isMale = in.readInt() == 1;
- }
- Binder
- MainActivity.java
- User user = new User(10,"dongyaoping",true);
- Intent intent = new Intent(MainActivity.this,MyService.class);
- Bundle bundle = new Bundle();
- bundle.putSerializable("data",user);
- bundle.putInt("int",10);
- bundle.putString("string","haha");
- intent.putExtras(bundle);
- startService(intent);
- public class MyService extends Service{
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- User user = (User) intent.getExtras().getSerializable("data");
- Log.v("dyp","user:"+user.toString());
- return super.onStartCommand(intent, flags, startId);
- }
- }
- User user = new User(100,"dyp",true);
- try {
- ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(path));
- out.writeObject(user);
- out.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- try {
- ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(path));
- User user = (User ) inputStream.readObject();
- } catch (Exception e) {
- e.printStackTrace();
- }
- AIDL
- Messenger
- ContentProvider
- interface IMyAidlInterface {
- String getInfor(String s);
- String getName(char name);
- // 传递对象
- String getBook(in Book book);
- }
- final ServiceConnection connection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- }
- };
- Intent intent = new Intent(MainActivity.this, MyService.class);
- bindService(intent, connection, Context.BIND_AUTO_CREATE);
- final ServiceConnection connection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- Log.v("dyp", "已经连接上了");
- IMyAidlInterface iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
- try {
- String haha = iMyAidlInterface.getInfor("hello, 我是 activity");
- Log.v("dyp", "接受到 Service 发过来的字符串:" + haha);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Log.v("dyp","断开了连接");
- }
- };
- private IBinder binder = new IMyAidlInterface.Stub() {
- @Override
- public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
- }
- @Override
- public String getInfor(String s) throws RemoteException {
- Log.v("dyp","接收到 Activity 的字符串:"+s);
- return "service 传过去的字符串";
- }
- @Override
- public String getBook(Book book) throws RemoteException {
- return null;
- }
- @Override
- public String getName(char name) throws RemoteException {
- return null;
- }
- };
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- return binder;
- }
来源: https://juejin.im/post/5a95211bf265da4e96742012