2016-04-04 2 views
2

Ich benutze die Bibliothek bitcoinj, um eine Android-Brieftasche zu erstellen. Der Fall ist, dass ich möchte, dass die Blockchain im Hintergrund heruntergeladen wird, so dass der Benutzer die anderen Funktionen der App nutzen kann. Wenn er jedoch den Download startet und eine neue Aktivität öffnet, friert die Anwendung ein und Sie können nichts mehr verwenden , nicht einmal zum vorherigen Bildschirm zurückkehren. Dies ist Teil des Codes:Android-Benutzeroberfläche einfrieren, wenn der Dienst Fortschritt herunterlädt

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); 
    } 
} 

ich Teil des Codes des offiziellen Projektes des Android wallet verwendet

+0

Überprüfen Sie diese: http://stackoverflow.com/questions/7875926/does-android-service-run-from-a-seperated-thread-instead-of-ui –

+0

Foreground-Dienste auf dem UI-Thread ausgeführt. Jede E/A-gebundene Arbeit sollte mit AsyncTasks, neuen Threads (Senden von Nachrichten an Ihren Handler) oder (** beste Option **) RxJava erfolgen. –

+0

Verwenden Sie IntentService zum Herunterladen –

Antwort

2

Service im Android läuft in UI-Thread. Sie müssen den gesamten Job in verschiedene Threads in Ihrem Service stecken

0

Sie müssen IntentService für den Download-Prozess verwenden.

public class BitcoinService extends IntentService { 
    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 
    protected void onHandleIntent(Intent intent) { 
     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 
    } 

    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); 
     } 

    } 
} 

Hoffe, das wird Ihnen helfen.

+0

Vielen Dank! Aber ich habe es getestet und es funktioniert nicht. Ich habe versucht, den Prozess mit einer AsyncTask zu machen, ich habe das gleiche Ergebnis. –