我正在尝试在Android中测试领域还原和备份功能。我正在关注文章here。我正在使用Realm github的示例recyclerview代码link。
我能够成功备份。但是,如果我恢复备份然后尝试打开活动(RecyclerViewExampleActivity.java),它与领域恢复的数据库交互以填充recyclerview,应用程序崩溃,当我重新启动应用程序然后再次启动recyclerview活动它恢复工作正常db,崩溃时抛出以下异常:
07-25 12:52:18.262 1531-1627/io.realm.examples.adapters A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x4 in tid 1627 (amples.adapters)
[ 07-25 12:52:18.263 441: 441 W/ ]
debuggerd: handling request: pid=1531 uid=10157 gid=10157 tid=1627
以下是应用的代码 -
MyApplication.java
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Realm.init(this);
RealmConfiguration realmConfig = new RealmConfiguration.Builder()
.initialData(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
realm.createObject(Parent.class);
}})
.build();
Realm.setDefaultConfiguration(realmConfig);
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
Button btnbackup,btnrest;
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupButton(R.id.button_listview, ListViewExampleActivity.class);
setupButton(R.id.button_recyclerview, RecyclerViewExampleActivity.class);
checkStoragePermissions(this);
btnbackup=(Button) findViewById(R.id.button_backup);
btnrest=(Button) findViewById(R.id.button_restore);
btnrest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("restore clicked");
RealmBackupRestore rel = new RealmBackupRestore(MainActivity.this);
rel.restore();
}
});
btnbackup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("backup clicked");
RealmBackupRestore rel = new RealmBackupRestore(MainActivity.this);
rel.backup();
}
});
}
void startActivity(Class<? extends Activity> activityClass) {
startActivity(new Intent(this, activityClass));
}
private void setupButton(int id, final Class<? extends Activity> activityClass) {
findViewById(id).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(activityClass);
}
});
}
private void checkStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if(permission != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
}
RecyclerViewExampleActivity.java
public class RecyclerViewExampleActivity extends AppCompatActivity {
private Realm realm;
private RecyclerView recyclerView;
private Menu menu;
private MyRecyclerViewAdapter adapter;
private class TouchHelperCallback extends ItemTouchHelper.SimpleCallback {
TouchHelperCallback() {
super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return true;
}
@Override
public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction) {
DataHelper.deleteItemAsync(realm, viewHolder.getItemId());
}
@Override
public boolean isLongPressDragEnabled() {
return true;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recyclerview);
realm = Realm.getDefaultInstance();
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
setUpRecyclerView();
}
@Override
protected void onDestroy() {
super.onDestroy();
recyclerView.setAdapter(null);
realm.close();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
this.menu = menu;
getMenuInflater().inflate(R.menu.listview_options, menu);
menu.setGroupVisible(R.id.group_normal_mode, true);
menu.setGroupVisible(R.id.group_delete_mode, false);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch(id) {
case R.id.action_add:
DataHelper.addItemAsync(realm);
return true;
case R.id.action_random:
DataHelper.randomAddItemAsync(realm);
return true;
case R.id.action_start_delete_mode:
adapter.enableDeletionMode(true);
menu.setGroupVisible(R.id.group_normal_mode, false);
menu.setGroupVisible(R.id.group_delete_mode, true);
return true;
case R.id.action_end_delete_mode:
DataHelper.deleteItemsAsync(realm, adapter.getCountersToDelete());
// Fall through
case R.id.action_cancel_delete_mode:
adapter.enableDeletionMode(false);
menu.setGroupVisible(R.id.group_normal_mode, true);
menu.setGroupVisible(R.id.group_delete_mode, false);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void setUpRecyclerView() {
if(realm==null)
realm=Realm.getDefaultInstance();
adapter = new MyRecyclerViewAdapter(realm.where(Parent.class).findFirst().getCounterList());
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
TouchHelperCallback touchHelperCallback = new TouchHelperCallback();
ItemTouchHelper touchHelper = new ItemTouchHelper(touchHelperCallback);
touchHelper.attachToRecyclerView(recyclerView);
}
}
RecyclerViewAdapter.java
class MyRecyclerViewAdapter extends RealmRecyclerViewAdapter<Counter, MyRecyclerViewAdapter.MyViewHolder> {
private boolean inDeletionMode = false;
private Set<Integer> countersToDelete = new HashSet<Integer>();
MyRecyclerViewAdapter(OrderedRealmCollection<Counter> data) {
super(data, true);
setHasStableIds(true);
}
void enableDeletionMode(boolean enabled) {
inDeletionMode = enabled;
if (!enabled) {
countersToDelete.clear();
}
notifyDataSetChanged();
}
Set<Integer> getCountersToDelete() {
return countersToDelete;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.row, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
final Counter obj = getItem(position);
holder.data = obj;
//noinspection ConstantConditions
holder.title.setText(obj.getCountString());
holder.deletedCheckBox.setChecked(countersToDelete.contains(obj.getCount()));
if (inDeletionMode) {
holder.deletedCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
countersToDelete.add(obj.getCount());
} else {
countersToDelete.remove(obj.getCount());
}
}
});
} else {
holder.deletedCheckBox.setOnCheckedChangeListener(null);
}
holder.deletedCheckBox.setVisibility(inDeletionMode ? View.VISIBLE : View.GONE);
}
@Override
public long getItemId(int index) {
//noinspection ConstantConditions
return getItem(index).getCount();
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView title;
CheckBox deletedCheckBox;
public Counter data;
MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.textview);
deletedCheckBox = (CheckBox) view.findViewById(R.id.checkBox);
}
}
}
Counter.java
public class Counter extends RealmObject {
public static final String FIELD_COUNT = "count";
private static AtomicInteger INTEGER_COUNTER = new AtomicInteger(0);
@PrimaryKey
private int count;
public int getCount() {
return count;
}
public String getCountString() {
return Integer.toString(count);
}
// create() & delete() needs to be called inside a transaction.
static void create(Realm realm) {
create(realm, false);
}
static void create(Realm realm, boolean randomlyInsert) {
Parent parent = realm.where(Parent.class).findFirst();
RealmList<Counter> counters = parent.getCounterList();
Counter counter = realm.createObject(Counter.class, increment());
if (randomlyInsert && counters.size() > 0) {
Random rand = new Random();
counters.listIterator(rand.nextInt(counters.size())).add(counter);
} else {
counters.add(counter);
}
}
static void delete(Realm realm, long id) {
Counter counter = realm.where(Counter.class).equalTo(FIELD_COUNT, id).findFirst();
// Otherwise it has been deleted already.
if (counter != null) {
counter.deleteFromRealm();
}
}
private static int increment() {
return INTEGER_COUNTER.getAndIncrement();
}
}
Datahelper.java
public class DataHelper {
// Create 3 counters and insert them into random place of the list.
public static void randomAddItemAsync(Realm realm) {
realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
for (int i = 0; i < 3; i++) {
Counter.create(realm, true);
}
}
});
}
public static void addItemAsync(Realm realm) {
realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
Counter.create(realm);
}
});
}
public static void deleteItemAsync(Realm realm, final long id) {
realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
Counter.delete(realm, id);
}
});
}
public static void deleteItemsAsync(Realm realm, Collection<Integer> ids) {
// Create an new array to avoid concurrency problem.
final Integer[] idsToDelete = new Integer[ids.size()];
ids.toArray(idsToDelete);
realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
for (Integer id : idsToDelete) {
Counter.delete(realm, id);
}
}
});
}
}
Parent.java
public class Parent extends RealmObject {
@SuppressWarnings("unused")
private RealmList<Counter> counterList;
public RealmList<Counter> getCounterList() {
return counterList;
}
}
的AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name=".MyApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name="io.realm.examples.adapters.MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".ui.listview.ListViewExampleActivity"
android:label="ListView Example"/>
<activity
android:name=".ui.recyclerview.RecyclerViewExampleActivity"
android:label="RecyclerView Example"/>
</application>
</manifest>
Gradle App
apply plugin: 'com.android.application'
apply plugin: 'android-command'
apply plugin: 'realm-android'
android {
compileSdkVersion sdkVersion
buildToolsVersion buildTools
defaultConfig {
applicationId "io.realm.examples.adapters"
minSdkVersion 15
targetSdkVersion sdkVersion
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
}
}
command {
events 2000
}
repositories {
jcenter()
mavenCentral()
maven { url 'https://github.com/uPhyca/stetho-realm/raw/master/maven-repo' }
}
}
dependencies {
compile project(':adapters')
compile "com.android.support:appcompat-v7:${supportLibraryVersion}"
compile "com.android.support:recyclerview-v7:${supportLibraryVersion}"
compile 'com.uphyca:stetho_realm:2.0.0'
compile 'com.facebook.stetho:stetho:1.5.0'
}
有人可以帮忙弄清楚为什么异常会从何而来?为什么不重新启动app重启?有没有资源我可以得到更好的Realm db备份/恢复示例,这不会让应用程序崩溃?感谢。
在更多的测试中,我注意到应用程序有时会在执行还原后立即崩溃,代码2错误而不是1,如上所述,错误显示如下:
07-25 13:36:12.318 17784-18482/io.realm.examples.adapters A/libc: Fatal signal 11 (SIGSEGV), code 2, fault addr 0xaa8ea000 in tid 18482 (StethoWorker-ma)
[ 07-25 13:36:12.319 441: 441 W/ ]
debuggerd: handling request: pid=17784 uid=10160 gid=10160 tid=18482