Skip to content

Commit

Permalink
Add multi-process example
Browse files Browse the repository at this point in the history
All Realm public APIs should be process-safe now.

Encryption is not supported for multi processes due to core
restriction realm/realm-core#1845

Accessing same Realm file in different processes from different apks
is safe, but the notifications won't work.
  • Loading branch information
beeender committed Oct 26, 2017
1 parent d6c84d4 commit b12402e
Show file tree
Hide file tree
Showing 23 changed files with 390 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,8 @@

### Enhancements

* Added support for using non-encrypted Realm in multiple processes from the same apk (#1091).

### Bug Fixes

### Interal
Expand Down
1 change: 1 addition & 0 deletions examples/multiProcessExample/.gitignore
@@ -0,0 +1 @@
/build
38 changes: 38 additions & 0 deletions examples/multiProcessExample/build.gradle
@@ -0,0 +1,38 @@
apply plugin: 'com.android.application'
apply plugin: 'android-command'
apply plugin: 'realm-android'

android {
compileSdkVersion rootProject.sdkVersion
buildToolsVersion rootProject.buildTools

defaultConfig {
applicationId "io.realm.examples.realmmultiprocessexample"
targetSdkVersion rootProject.sdkVersion
minSdkVersion 9
versionCode 1
versionName "1.0"
}

buildTypes {
release {
minifyEnabled true
signingConfig signingConfigs.debug
}
debug {
minifyEnabled true
}
}

productFlavors {
}

command {
monkey.events 2000
}
}

dependencies {
compile 'com.android.support:appcompat-v7:23.1.1'
}

17 changes: 17 additions & 0 deletions examples/multiProcessExample/proguard-rules.pro
@@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/cc/.android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
26 changes: 26 additions & 0 deletions examples/multiProcessExample/src/main/AndroidManifest.xml
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="io.realm.examples.realmmultiprocessexample"
xmlns:android="http://schemas.android.com/apk/res/android" >

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:name="io.realm.examples.realmmultiprocessexample.MyApplication">
<activity android:name="io.realm.examples.realmmultiprocessexample.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>

<service
android:name="io.realm.examples.realmmultiprocessexample.AnotherProcessService"
android:enabled="true"
android:exported="false"
android:process=":remote">
</service>
</application>
</manifest>
@@ -0,0 +1,43 @@
package io.realm.examples.realmmultiprocessexample;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;

import io.realm.Realm;

public class AnotherProcessService extends Service {

Handler handler;

@Override
public void onCreate() {
super.onCreate();

handler = new Handler(Looper.myLooper());
final Runnable runnable = new Runnable() {
@Override
public void run() {
Realm realm = Realm.getDefaultInstance();
realm.beginTransaction();
realm.copyToRealmOrUpdate(Utils.createStandaloneProcessInfo(AnotherProcessService.this));
realm.commitTransaction();
realm.close();
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(runnable, 1000);
}

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

@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
@@ -0,0 +1,90 @@
/*
* Copyright 2014 Realm Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.realm.examples.realmmultiprocessexample;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Locale;

import io.realm.Realm;
import io.realm.RealmChangeListener;
import io.realm.RealmResults;
import io.realm.examples.realmmultiprocessexample.models.ProcessInfo;

public class MainActivity extends AppCompatActivity {

private TextView textView;
private Realm realm;
private RealmResults<ProcessInfo> processInfoResults;

private RealmChangeListener<RealmResults<ProcessInfo>> listener =
new RealmChangeListener<RealmResults<ProcessInfo>>() {
@Override
public void onChange(RealmResults<ProcessInfo> results) {
StringBuilder stringBuilder = new StringBuilder();

for (ProcessInfo processInfo : results) {
stringBuilder.append(processInfo.getName());
stringBuilder.append("\npid: ");
stringBuilder.append(processInfo.getPid());
stringBuilder.append("\nlast response time: ");
DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss", Locale.ENGLISH);
stringBuilder.append(df.format(processInfo.getLastResponseDate()));
stringBuilder.append("\n------\n");
}
textView.setText(stringBuilder.toString());
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);

if (realm == null) {
realm = Realm.getDefaultInstance();
processInfoResults = realm.where(ProcessInfo.class).findAllAsync();
processInfoResults.addChangeListener(listener);
}

realm.beginTransaction();
realm.copyToRealmOrUpdate(Utils.createStandaloneProcessInfo(this));
realm.commitTransaction();
}

@Override
protected void onDestroy() {
super.onDestroy();
if (realm != null) {
realm.close();
realm = null;
processInfoResults = null;
}
}

public void onStartButton(View button) {
Intent intent = new Intent(MainActivity.this, AnotherProcessService.class);
startService(intent);
button.setEnabled(false);
}
}
@@ -0,0 +1,16 @@
package io.realm.examples.realmmultiprocessexample;

import android.app.Application;

import io.realm.Realm;
import io.realm.RealmConfiguration;

public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Realm.init(this);
RealmConfiguration configuration = new RealmConfiguration.Builder().deleteRealmIfMigrationNeeded().build();
Realm.setDefaultConfiguration(configuration);
}
}
@@ -0,0 +1,41 @@
package io.realm.examples.realmmultiprocessexample;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
import android.os.Process;

import java.util.Date;
import java.util.List;

import io.realm.examples.realmmultiprocessexample.models.ProcessInfo;

public class Utils {

public static String getMyProcessName(Context context) {
String processName = "";
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> infoList= am.getRunningAppProcesses();
if (infoList == null) {
throw new RuntimeException("getRunningAppProcesses() returns 'null'.");
}
for (RunningAppProcessInfo info : infoList) {
try {
if (info.pid == Process.myPid()) {
processName = info.processName;
}
} catch (Exception ignored) {
}
}
return processName;
}

public static ProcessInfo createStandaloneProcessInfo(Context context) {
ProcessInfo processInfo = new ProcessInfo();
processInfo.setName(getMyProcessName(context));
processInfo.setPid(android.os.Process.myPid());
processInfo.setLastResponseDate(new Date());

return processInfo;
}
}
@@ -0,0 +1,54 @@
/*
* Copyright 2014 Realm Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.realm.examples.realmmultiprocessexample.models;

import java.util.Date;

import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
import io.realm.annotations.Required;

public class ProcessInfo extends RealmObject {
@PrimaryKey
private String name;
private int pid;
@Required
private Date lastResponseDate;

public int getPid() {
return pid;
}

public void setPid(int pid) {
this.pid = pid;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Date getLastResponseDate() {
return lastResponseDate;
}

public void setLastResponseDate(Date lastResponseDate) {
this.lastResponseDate = lastResponseDate;
}
}
26 changes: 26 additions & 0 deletions examples/multiProcessExample/src/main/res/layout/activity_main.xml
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" >

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/start_remote_service"
android:id="@+id/button"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:onClick="onStartButton"/>

<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/textView"
android:layout_centerHorizontal="true"
android:layout_below="@+id/button"/>
</RelativeLayout>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,6 @@
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>
6 changes: 6 additions & 0 deletions examples/multiProcessExample/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>
5 changes: 5 additions & 0 deletions examples/multiProcessExample/src/main/res/values/dimens.xml
@@ -0,0 +1,5 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>
4 changes: 4 additions & 0 deletions examples/multiProcessExample/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
<resources>
<string name="app_name">Realm Multi Process example</string>
<string name="start_remote_service">Start remote service</string>
</resources>

0 comments on commit b12402e

Please sign in to comment.