2016-10-11 66 views
0

是否有可能在Realm(Java,Android)中進行進程間通信。因此,如果我們更新一個Process的RealmObject字段的值,我們是否會在另一個進程中觸發RealmChangeListener(對應於提及的RealmObject)。我認爲Realm的版本至少是2.0.2。在Android的Realm中可以進行內部進程通信嗎?

+0

你能否詳細說明 – nature1729

+0

@bigdestroyer你知道Realm不是關係型的,不會暴露遊標,對嗎?所以它不支持ContentProvider呢? – EpicPandaForce

回答

3

境界2.0.0及以後支持進程間通知非加密的國度,但are some edge cases that aren't covered yet (multi-process migrations, primarily).



我已經把一個樣本項目,它爲我工作。

在這裏,RecyclerView顯示從屬於遠程進程的廣播接收器插入的狗。

10-11 20:53:46.340 7302-7302/com.zhuinden.realm_multiprocess_example I/MainActivity: Activity in Process [7302] 
10-11 20:53:46.344 7302-7302/com.zhuinden.realm_multiprocess_example D/RealmManager: Incrementing Activity Count [0]: opening Realm. 
10-11 20:53:46.352 7302-7302/com.zhuinden.realm_multiprocess_example D/RealmManager: Increment: Count [1] 

10-11 20:54:01.352 7560-7560/com.zhuinden.realm_multiprocess_example:remote D/AlarmReceiver: Alarm received in process [7560] 
10-11 20:54:01.352 7560-8705/com.zhuinden.realm_multiprocess_example:remote I/AlarmReceiver: Inserting DOGE [Juice] 

完整源代碼:

public class RealmManager { 
    private static final String TAG = "RealmManager"; 

    static Realm realm; 

    static RealmConfiguration realmConfiguration; 

    public static RealmConfiguration buildDefaultRealmConfiguration() { 
     return new RealmConfiguration.Builder() 
       .deleteRealmIfMigrationNeeded() 
       .build(); 
    } 

    public static void initializeRealmConfig(Context appContext) { 
     if(realmConfiguration == null) { 
      Realm.init(appContext); 
      Log.d(TAG, "Initializing Realm configuration."); 
      setRealmConfiguration(buildDefaultRealmConfiguration()); 
     } 
    } 

    public static void setRealmConfiguration(RealmConfiguration realmConfiguration) { 
     RealmManager.realmConfiguration = realmConfiguration; 
     Realm.setDefaultConfiguration(realmConfiguration); 
    } 

    private static int activityCount = 0; 

    public static Realm getRealm() { 
     return realm; 
    } 

    public static void incrementCount() { 
     if(activityCount == 0) { 
      if(realm != null) { 
       if(!realm.isClosed()) { 
        Log.w(TAG, "Unexpected open Realm found."); 
        realm.close(); 
       } 
      } 
      Log.d(TAG, "Incrementing Activity Count [0]: opening Realm."); 
      realm = Realm.getDefaultInstance(); 
     } 
     activityCount++; 
     Log.d(TAG, "Increment: Count [" + activityCount + "]"); 
    } 

    public static void decrementCount() { 
     activityCount--; 
     Log.d(TAG, "Decrement: Count [" + activityCount + "]"); 
     if(activityCount <= 0) { 
      Log.d(TAG, "Decrementing Activity Count: closing Realm."); 
      activityCount = 0; 
      realm.close(); 
      if(Realm.compactRealm(realmConfiguration)) { 
       Log.d(TAG, "Realm compacted successfully."); 
      } 
      realm = null; 
     } 
    } 
} 

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

    @BindView(R.id.recyclerview) 
    RecyclerView recyclerView; 

    Realm realm; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     RealmManager.initializeRealmConfig(getApplicationContext()); 
     Log.i(TAG, "Activity in Process [" + android.os.Process.myPid() + "]"); 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     ButterKnife.bind(this); 
     RealmManager.incrementCount(); //lazy for retained fragment 
     realm = RealmManager.getRealm(); 

     recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); 
     recyclerView.setAdapter(new RealmRecyclerViewAdapter<Dog, DogViewHolder>(this, realm.where(Dog.class).findAllAsync(), true) { 
      @Override 
      public DogViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
       TextView textView = new TextView(MainActivity.this); 
       RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 
         ViewGroup.LayoutParams.WRAP_CONTENT); 
       textView.setLayoutParams(layoutParams); 
       return new DogViewHolder(textView); 
      } 

      @Override 
      public void onBindViewHolder(DogViewHolder holder, int position) { 
       holder.bind(getData().get(position)); 
      } 
     }); 

     AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE); 
     Calendar calendar = Calendar.getInstance(); 
     calendar.add(Calendar.SECOND, 15); 
     Intent intent = new Intent(this, AlarmReceiver.class); 
     PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); 
     addNotification(alarmManager, pendingIntent, calendar.getTimeInMillis()); 
    } 

    public void addNotification(AlarmManager alarmManager, PendingIntent pendingIntent, long timeOfNotification) { 
     if(Build.VERSION.SDK_INT < 19) { 
      alarmManager.set(AlarmManager.RTC_WAKEUP, timeOfNotification, pendingIntent); 
     } else if(Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 23) { 
      alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeOfNotification, pendingIntent); 
     } else if(Build.VERSION.SDK_INT >= 23) { 
      alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeOfNotification, pendingIntent); 
     } 
    } 

    @Override 
    protected void onDestroy() { 
     RealmManager.decrementCount(); 
     super.onDestroy(); 
    } 
} 

public class DogViewHolder extends RecyclerView.ViewHolder { 

    TextView textView; 

    public DogViewHolder(View itemView) { 
     super(itemView); 
     textView = (TextView) itemView; 
    } 

    public void bind(Dog dog) { 
     textView.setText(dog.getName()); 
    } 
} 

public enum DogNames { 
    Jack, 
    Jill, 
    Joe, 
    Jarble, 
    Juice, 
    Jen, 
    Jim, 
    Munch, 
    Slurp, 
    Boop, 
    Largo, 
    Boson, 
    Pete, 
    Boner, 
    Derp, 
    Roger, 
    Bunbun, 
    Twix, 
    Dog 
} 

public class Dog extends RealmObject { 
    @PrimaryKey 
    private long id; 

    private String name; 

    public long getId() { 
     return id; 
    } 

    public void setId(long id) { 
     this.id = id; 
    } 

    public String getName() { 
     return name; 
    } 

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

public class AlarmReceiver extends BroadcastReceiver { 
    private static final String TAG = "AlarmReceiver"; 

    RealmConfiguration realmConfiguration; 

    Executor executor; 

    @Override 
    @SuppressLint("NewApi") 
    public void onReceive(Context context, Intent intent) { 
     Log.d(TAG, "Alarm received in process [" + android.os.Process.myPid() + "]"); 
     Realm.init(context); 
     if(realmConfiguration == null) { 
      realmConfiguration = RealmManager.buildDefaultRealmConfiguration(); 
     } 
     if(executor == null) { 
      executor = Executors.newSingleThreadExecutor(); 
     } 
     executor.execute(() -> { 
      try(Realm r = Realm.getInstance(realmConfiguration)) { 
       if(Looper.getMainLooper() == Looper.myLooper()) { 
        Log.i(TAG, "UI thread transaction: this should be fixed!"); 
       } 
       r.executeTransaction(realm -> { 
        Dog dog = new Dog(); 
        long id = realm.where(Dog.class).findAll().size()+1; 
        dog.setId(id); 
        dog.setName(DogNames.values()[((Long)id).intValue() % DogNames.values().length].name()); 
        realm.insert(dog); 
        Log.i(TAG, "Inserting DOGE [" + dog.getName() + "]"); 
       }); 
      } 
     }); 
    } 
} 

<?xml version="1.0" encoding="utf-8"?> 
<manifest package="com.zhuinden.realm_multiprocess_example" 
      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"> 
     <activity android:name=".MainActivity"> 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN"/> 

       <category android:name="android.intent.category.LAUNCHER"/> 
      </intent-filter> 
     </activity> 
     <receiver 
      android:name=".AlarmReceiver" 
      android:process=":remote"/> 
    </application> 

</manifest> 

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout 
    android:id="@+id/activity_main" 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    tools:context="com.zhuinden.realm_multiprocess_example.MainActivity"> 

    <android.support.v7.widget.RecyclerView 
     android:id="@+id/recyclerview" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"/> 
</RelativeLayout> 

// Top-level build file where you can add configuration options common to all sub-projects/modules. 

buildscript { 
    repositories { 
     mavenCentral() 
     jcenter() 
     maven {url "https://clojars.org/repo/"} 
     maven { url "https://jitpack.io" } 
    } 
    dependencies { 
     classpath 'com.android.tools.build:gradle:2.2.0' 
     classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' 
     classpath "io.realm:realm-gradle-plugin:2.0.2" 
     classpath 'me.tatarka:gradle-retrolambda:3.2.5' 
     // NOTE: Do not place your application dependencies here; they belong 
     // in the individual module build.gradle files 
    } 
} 

allprojects { 
    repositories { 
     mavenCentral() 
     jcenter() 
     maven {url "https://clojars.org/repo/"} 
     maven { url "https://jitpack.io" } 
    } 
} 

task clean(type: Delete) { 
    delete rootProject.buildDir 
} 

apply plugin: 'com.android.application' 
apply plugin: 'com.neenbedankt.android-apt' 
apply plugin: 'me.tatarka.retrolambda' 
apply plugin: 'realm-android' 

android { 
    compileSdkVersion 24 
    buildToolsVersion "24.0.2" 
    compileOptions { 
     sourceCompatibility JavaVersion.VERSION_1_8 
     targetCompatibility JavaVersion.VERSION_1_8 
    } 
    defaultConfig { 
     applicationId "com.zhuinden.realm_multiprocess_example" 
     minSdkVersion 14 
     targetSdkVersion 24 
     versionCode 1 
     versionName "1.0" 
     testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 
    } 
    buildTypes { 
     release { 
      minifyEnabled false 
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 
     } 
    } 
    packagingOptions { 
     // Exclude file to avoid 
     // Error: Duplicate files during packaging of APK 
     exclude 'META-INF/DEPENDENCIES' 
     exclude 'META-INF/LICENSE' 
     exclude 'META-INF/LICENSE.txt' 
     exclude 'META-INF/license.txt' 
     exclude 'META-INF/NOTICE' 
     exclude 'META-INF/NOTICE.txt' 
     exclude 'META-INF/notice.txt' 
     exclude 'META-INF/ASL2.0' 
     exclude 'META-INF/services/javax.annotation.processing.Processor' 
    } 
} 

dependencies { 
    compile fileTree(dir: 'libs', include: ['*.jar']) 
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 
     exclude group: 'com.android.support', module: 'support-annotations' 
    }) 
    compile 'com.android.support:appcompat-v7:24.2.1' 
    testCompile 'junit:junit:4.12' 
    compile "com.android.support:recyclerview-v7:24.2.1" 

    apt 'com.jakewharton:butterknife-compiler:8.4.0' 
    compile 'com.jakewharton:butterknife:8.4.0' 

    apt 'dk.ilios:realmfieldnameshelper:1.1.0' 
    compile 'io.realm:android-adapters:1.3.0' 
} 
+0

我已看過此頁面。但我沒有遵守預期的行爲。你有沒有工作的例子? – nature1729

+0

那麼,預期的行爲是什麼,它是如何發生的? SharedRealm中的'waitForChange'應該處理這個問題。 – EpicPandaForce

+0

代替觸發器,waitForChange在本質上將被阻塞。 – nature1729

相關問題