我正在使用 library bitcoinj 创建一个 Android 钱包。案例是我希望在后台下载区块链,以便用户可以开始使用应用程序的其他功能,但是当它开始下载并打开一个新活动时,应用程序冻结,你不能使用任何东西,甚至没有返回到上一个屏幕。这是代码的一部分:
public class BitcoinService extends Service {
private final PeerDataEventListener blockchainDownloadListener = new AbstractPeerEventListener() {
private final long CALLBACK_TIME = 1000L;
private final AtomicLong lastMessageTime = new AtomicLong(0);
private int height;
private int blocksLeft;
private Block block;
@Override
public void onBlocksDownloaded(final Peer peer, final Block block, final FilteredBlock filteredBlock, final int blocksLeft) {
config.maybeIncrementBestChainHeightEver(blockChain.getChainHead().getHeight());
delayHandler.removeCallbacksAndMessages(null);
final long now = System.currentTimeMillis();
this.block = block;
this.height = (int) peer.getBestHeight() - blocksLeft;
this.blocksLeft = blocksLeft;
if (now - lastMessageTime.get() > CALLBACK_TIME) {
delayHandler.post(RUNNER);
} else {
delayHandler.postDelayed(RUNNER, CALLBACK_TIME);
}
}
private final Runnable RUNNER = new Runnable() {
@Override
public void run() {
notifyBlockchainProgress(height, (height + blocksLeft));
Log.e(TAG, "LAST_BLOCK=" + height + ", REMAINS=" + blocksLeft);
if (blocksLeft == 0) {
broadcastBlockchainDownloaded();
}
}
};
};
private final BroadcastReceiver connectivityReceiver = new BroadcastReceiver() {
@SuppressLint("Wakelock")
@Override
public void onReceive(final Context context, final Intent intent) {
Log.d(TAG, "acquiring wakelock");
wakeLock.acquire();
// consistency check
final int walletLastBlockSeenHeight = wallet.getLastBlockSeenHeight();
final int bestChainHeight = blockChain.getBestChainHeight();
if (walletLastBlockSeenHeight != -1 && walletLastBlockSeenHeight != bestChainHeight) {
final String message = "wallet/blockchain out of sync: " + walletLastBlockSeenHeight + "/" + bestChainHeight;
Log.e(TAG, message);
}
Log.i(TAG, "starting peergroup");
peerGroup = new PeerGroup(Constants.WALLET.NETWORK_PARAMETERS, blockChain);
peerGroup.setDownloadTxDependencies(false);
peerGroup.setUserAgent("TestWallet", "0.0.1");
peerGroup.setMaxConnections(6);
peerGroup.setConnectTimeoutMillis(15000);
peerGroup.setPeerDiscoveryTimeoutMillis(10000);
// start peergroup
peerGroup.startAsync();
peerGroup.startBlockChainDownload(blockchainDownloadListener);
}
};
private final Handler delayHandler = new Handler();
private PeerGroup peerGroup;
private WakeLock wakeLock;
private PeerConnectivityListener peerConnectivityListener;
private NotificationManager nm;
private Configuration config;
private Wallet wallet;
@Override
public void onCreate() {
wallet = new Wallet(Constants.WALLET.NETWORK_PARAMETERS);
nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
final String lockName = getPackageName() + " blockchain sync";
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, lockName);
config = Configuration.getInstance();
broadcastPeerState(0);
blockChainFile = Constants.WALLET.BLOCKCHAIN_FILE;
final boolean blockChainFileExists = blockChainFile.exists();
if (!blockChainFileExists) {
new File(Constants.WALLET.WALLET_PATH).mkdirs();
}
try {
blockStore = new SPVBlockStore(Constants.WALLET.NETWORK_PARAMETERS, blockChainFile);
blockStore.getChainHead(); // detect corruptions as early as possible
final long earliestKeyCreationTime = wallet.getEarliestKeyCreationTime();
if (!blockChainFileExists && earliestKeyCreationTime > 0){
try {
config.setDeletingBlockchain(true);
final long start = System.currentTimeMillis();
final InputStream checkpointsInputStream = getAssets().open("bitcoin/" + Constants.WALLET.CHECKPOINTS_FILENAME);
CheckpointManager.checkpoint(Constants.WALLET.NETWORK_PARAMETERS, checkpointsInputStream, blockStore, earliestKeyCreationTime);
Log.i(TAG, String.format("checkpoints loaded from '%1$s', took %2$dms", Constants.WALLET.CHECKPOINTS_FILENAME, System.currentTimeMillis() - start));
} catch (final IOException x) {
Log.e(TAG, "problem reading checkpoints, continuing without", x);
}
}
} catch (final BlockStoreException x) {
blockChainFile.delete();
final String msg = "blockstore cannot be created";
Log.e(TAG, msg, x);
}
try {
blockChain = new BlockChain(Constants.WALLET.NETWORK_PARAMETERS, walletHelper.getMainWallet(), blockStore);
} catch (final BlockStoreException x) {
throw new Error("blockchain cannot be created", x);
}
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
registerReceiver(connectivityReceiver, intentFilter); // implicitly start PeerGroup
}
@Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
Log.e(TAG, "onStartCommand");
...
return START_NOT_STICKY;
}
private void notifyBlockchainProgress(int progress, int max) {
boolean isCompleted = progress == max;
if (config.isDeletingBlockchain()) {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
long percent = Math.round(Math.floor((progress * 100) / max));
mBuilder.setContentTitle("Blockchain download")
.setContentText(" Synchronization in progress - " + percent + "%")
.setSmallIcon(R.drawable.ic_logo_splash)
.setProgress(max, progress, false)
.setAutoCancel(false);
if (isCompleted) {
mBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setProgress(0, 0, false)
.setAutoCancel(true)
.setContentText(getString(R.string.synchronization_completed));
config.setDeletingBlockchain(false);
}
Notification notif = mBuilder.build();
if (isCompleted) {
notif.flags = Notification.FLAG_FOREGROUND_SERVICE;
} else {
notif.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE;
}
nm.notify(2, notif);
}
}
public void broadcastBlockchainDownloaded() {
Intent i = new Intent(UiRefreshReceiver.REFRESH_UI);
LocalBroadcastManager.getInstance(this).sendBroadcast(i);
}
}
我使用了安卓钱包官方项目的部分代码