• 【Android


      文件共享是一种非常不错的IPC方式,即两个进程可以通过读/写同一个文件来交换数据。和Windows系统不同,Android系统是基于Linux的,这使得并发读/写文件的操作可以没有限制地进行,甚至两个线程同时对一个文件进行读/写也是可以的(尽管这样可能会出问题)。

      使用文件共享的方式实现IPC时,文件中除了可以存储一些文本信息外,我们也可以序列化一个对象到文件系统中,然后在另一个进程中恢复这个对象。

      下面用一个例子来演示在文件系统中读/写对象的功能。

      我们在一个Module中创建两个Activity,分别是MainActivity和SecondActivity,Manifest文件中的代码如下:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
              package="my.itgungnir.ipc">
    
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
        <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity"></activity>
            <activity
                android:name=".SecondActivity"
                android:process=":remote">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
    
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
            </activity>
        </application>
    
    </manifest>

      我们通过在SecondActivity中设置 android:process 属性,让SecondActivity运行在另一个进程中,然后通过控制 <intent-filter> 标签的位置来决定当前启动哪个Activity(即哪个进程)。

      另外,不要忘记在Manifest文件中添加访问SD卡的权限。

      在这个例子中,我们将一个User对象存储到文件中,我们首先需要对User类进行序列化,以保证能够在进程中传递,User类中的代码如下:

    public class User implements Serializable {
        private static final long serialVersionUID = 1L;
    
        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;
        }
    }

      需要注意的是,将对象存储到文件系统中的过程可以理解为持久化的过程,而Parcelable接口不适合用来序列化可持久化的数据,因此这个我们必须使用Serializable接口进行序列化。

      在MainActivity中有一个按钮,当点击这个按钮的时候,就会生成一个User类的对象,存储到设备的SD卡中,代码如下:

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private Button btn;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            btn = (Button) findViewById(R.id.a_btn);
            btn.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    User user = new User(1001, "Alice", false);
                    String sdCardState = Environment.getExternalStorageState();
                    if (Environment.MEDIA_MOUNTED.equals(sdCardState)) {
                        File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/file_ipc/");
                        if (!dir.exists()) {
                            dir.mkdirs();
                        }
                        File tmpFile = new File(dir + File.separator + "fileipc.txt");
                        if (tmpFile.exists()) {
                            tmpFile.delete();
                        }
                        File file = new File(dir + File.separator + "fileipc.txt");
                        if (!file.exists()) {
                            try {
                                file.createNewFile();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        ObjectOutputStream oos = null;
                        try {
                            oos = new ObjectOutputStream(new FileOutputStream(file));
                            oos.writeObject(user);
                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {
                            if (oos != null) {
                                try {
                                    oos.close();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
            }).start();
        }
    }

      需要说明的是,笔者做这个DEMO使用的是Android 6.0的SDK,因此在涉及到权限的时候,除了在Manifest文件中声明权限之外,还在在Activity中通过 ActivityCompat.requestPermissions() 方法申请权限,然后在 onRequestPermissionsResult() 方法中回调要执行的代码。

      通过运行项目(此时 <intent-filter> 标签在MainActivity下),User对象就被存储到SD卡的文件系统中了。

      SecondActivity中有一个TextView,用来显示从SD卡的文件系统中读取出来的User对象中的数据。SecondActivity中的代码如下:

    public class SecondActivity extends AppCompatActivity {
        private TextView tv;
    
        private Handler textHandler;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_second);
            tv = (TextView) findViewById(R.id.b_tv);
            initHandler();
            initView();
        }
    
        private void initHandler() {
            textHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    if (msg.what == 1) {
                        User user = (User) msg.obj;
                        tv.setText("读取文件成功!
    ");
                        tv.append("用户编号:" + user.userId + "
    ");
                        tv.append("用户姓名:" + user.userName + "
    ");
                        tv.append("用户性别:" + (user.isMale ? "男" : "女") + "
    ");
                    }
                }
            };
        }
    
        private void initView() {
            ActivityCompat.requestPermissions(SecondActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    User user = null;
                    File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "file_ipc" + File.separator + "fileipc.txt");
                    if (file.exists()) {
                        ObjectInputStream ois = null;
                        try {
                            ois = new ObjectInputStream(new FileInputStream(file));
                            user = (User) ois.readObject();
                            Message msg = Message.obtain();
                            msg.what = 1;
                            msg.obj = user;
                            textHandler.sendMessage(msg);
                        } catch (IOException | ClassNotFoundException e) {
                            e.printStackTrace();
                        } finally {
                            if (ois != null) {
                                try {
                                    ois.close();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
            }).start();
        }
    }

      注意:由于我们的读写操作都是耗时操作,因此我们新开了一个现成执行这些代码,因此当我们需要将读取到的数据展示到TextView中的时候,就需要使用Handler将数据传送到主线程中,再跟新UI界面。

      在Manifest文件中将 <intent-filter> 标签移动到SecondActivity下,再次运行项目,就可以看到SD卡中存储的User对象中的信息就被展示到TextView中了。

      最后,注意一点,SharedPreferences虽然也是以文件的形式存储数据的,但是不适合在IPC中使用,原因是Android系统对SharedPreferences的读/写有一定的缓存策略,即在内存中会有一份SharedPreferences文件的缓存,因此在多进程的模式下,系统对SharedPreferences的读写就变得不可靠,当面对高并发的读/写访问时,SharedPreferences有很大几率会丢失数据,因此,不建议在IPC中使用SharedPreferences。

  • 相关阅读:
    函数后面加const
    关于C++ const 的全面总结
    待下载的东西
    GDI与DC
    Windows GDI与DC
    认识句柄
    什么是客户区/非客户区
    OpenCV 2.4.8 +VS2010的开发环境配置
    对话框类的数据交换和检验
    怎么调处vs2010的MSDN帮助文档
  • 原文地址:https://www.cnblogs.com/itgungnir/p/6555849.html
Copyright © 2020-2023  润新知