現在、ファイルのダウンロード中にアクティビティ内の進行状況バーを更新する AsyncTask を実行しています。問題は、アクティビティを離れて再入力すると、ProgressBar が更新されなくなることです。
サービス内で AsyncTask を実行しようとしましたが、ProgressBar の値をアクティビティの UI スレッドに戻す方法がわかりません。
現在、ファイルのダウンロード中にアクティビティ内の進行状況バーを更新する AsyncTask を実行しています。問題は、アクティビティを離れて再入力すると、ProgressBar が更新されなくなることです。
サービス内で AsyncTask を実行しようとしましたが、ProgressBar の値をアクティビティの UI スレッドに戻す方法がわかりません。
私はあなたと同じ問題に遭遇しました:
私は次のようなものを思いつきました:
public class DatabaseIncompleteActivity extends RoboActivity {
private BroadcastReceiver receiver;
private ProgressDialog progressDialog;
@Inject
private DatabaseSetManager databaseSetManager;
@Inject
private DatabaseDownloadLogger databaseDownloadLogger;
private LocalBroadcastManager localBroadcastManager;
private String jobId;
private static final int ERROR_RETRY_DIALOG = 1;
private static final String ERROR_MESSAGE = "errorMsg";
@Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
localBroadcastManager = LocalBroadcastManager.getInstance( this );
showProgressDialog();
if ( getLastNonConfigurationInstance() == null ) {
startService();
}
}
private void showProgressDialog() {
progressDialog = new ProgressDialog( this );
progressDialog.setMessage( getString( R.string.please_wait ) );
progressDialog.setProgressStyle( ProgressDialog.STYLE_HORIZONTAL );
progressDialog.setIndeterminate( true );
progressDialog.setCancelable( false );
progressDialog.show();
}
private void startService() {
this.jobId = UUID.randomUUID().toString();
Intent intent = new Intent( this, ClientDatabaseDroidService.class );
intent.putExtra( ClientDatabaseDroidService.JOB_ID,
jobId );
intent.putExtra( ClientDatabaseDroidService.INTERACTIVE,
true );
startService( intent );
}
private void registerListenerReceiver() {
if ( receiver != null ) {
return;
}
localBroadcastManager.registerReceiver( this.receiver = new ClientDatabaseBroadcastReceiver(),
new IntentFilter( ClientDatabaseDroidService.PROGRESS_NOTIFICATION ) );
}
@Override
protected void onPause() {
super.onPause();
unregisterListenerReceiver();
}
@Override
protected void onResume() {
super.onResume();
DatabaseDownloadLogEntry logEntry = databaseDownloadLogger.findByJobId( jobId );
// check if service finished while we were not listening
if ( logEntry != null ) {
if ( logEntry.isSuccess() )
onFinish();
else {
Bundle bundle = new Bundle();
bundle.putString( ERROR_MESSAGE,
logEntry.getErrorMessage() );
onError( bundle );
}
return;
}
registerListenerReceiver();
}
@Override
public Object onRetainNonConfigurationInstance() {
return Boolean.TRUE;
}
final class ClientDatabaseBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive( Context context, Intent intent ) {
Bundle extras = intent.getExtras();
int eventType = extras.getInt( ClientDatabaseDroidService.EVENT_TYPE );
switch ( eventType ) {
case ClientDatabaseDroidService.EVENT_TYPE_DOWNLOADING:
onDownloading( extras );
break;
case ClientDatabaseDroidService.EVENT_TYPE_FINISHED:
onFinish();
break;
case ClientDatabaseDroidService.EVENT_TYPE_ERROR:
Bundle bundle = new Bundle();
bundle.putString( ERROR_MESSAGE,
extras.getString( ClientDatabaseDroidService.EXTRA_ERROR_MESSAGE ) );
onError( bundle );
break;
default:
throw new RuntimeException( "should not happen" );
}
}
}
private void unregisterListenerReceiver() {
if ( receiver != null ) {
localBroadcastManager.unregisterReceiver( receiver );
receiver = null;
}
}
private void onError( Bundle extras ) {
progressDialog.dismiss();
showDialog( ERROR_RETRY_DIALOG,
extras );
}
private void onFinish() {
progressDialog.dismiss();
setResult( RESULT_OK );
finish();
}
@Override
protected Dialog onCreateDialog( final int id, Bundle args ) {
if ( id == ERROR_RETRY_DIALOG ) {
Builder builder = new AlertDialog.Builder( this );
builder.setTitle( R.string.error );
builder.setMessage( "" );
builder.setPositiveButton( R.string.yes,
new OnClickListener() {
@Override
public void onClick( DialogInterface dialog, int which ) {
showProgressDialog();
startService();
}
} );
builder.setNegativeButton( R.string.no,
new OnClickListener() {
@Override
public void onClick( DialogInterface dialog, int which ) {
setResult( RESULT_CANCELED );
finish();
}
} );
return builder.create();
}
return super.onCreateDialog( id,
args );
}
@Override
protected void onPrepareDialog( int id, Dialog dialog, Bundle args ) {
if ( id == ERROR_RETRY_DIALOG ) {
( (AlertDialog) dialog ).setMessage( String.format( "%s\n\n%s",
args.getString( ERROR_MESSAGE ),
getString( R.string.do_you_wish_to_retry ) ) );
return;
}
super.onPrepareDialog( id,
dialog );
}
private void onDownloading( Bundle extras ) {
String currentDatabase = extras.getString( ClientDatabaseDroidService.EXTRA_CURRENT_CLASSIFIER );
Progress databaseProgress = extras.getParcelable( ClientDatabaseDroidService.EXTRA_DATABASE_PROGRESS );
Progress downloadProgress = extras.getParcelable( ClientDatabaseDroidService.EXTRA_DOWNLOAD_PROGRESS );
progressDialog.setIndeterminate( false );
progressDialog.setMessage( String.format( "[%d/%d] %s",
databaseProgress.getProcessed(),
databaseProgress.getSize(),
currentDatabase ) );
progressDialog.setProgress( (int) downloadProgress.getProcessed() );
progressDialog.setMax( (int) downloadProgress.getSize() );
}
}
主なアイデアは次のとおりです。
それが役立つことを願っています。
アクティビティ グラブを再入力すると、静的変数または設定から進行状況を設定します。
これは正常です。アクティビティから離れたり、デバイスを回転させたりすると、アクティビティは消滅します。その後、それらは再作成されます。AsyncTasks は、新しい Activity インスタンスに自動的に再リンクしません。
実際、RoboSpiceはあなたが探しているライブラリです: アクティビティからダウンロードを開始したり、デバイスを回転させたり、アクティビティを終了したり、アプリを終了したり、タスク スイッチャーを使用して終了したりすることができ、ダウンロードは存続します。アクティビティ、以前のアクティビティの新しいインスタンス、またはまったく異なるアクティビティでさえ、ダウンロードに再リンクできます。
ストアからアプリRoboSpice Motivationsをダウンロードする必要があります。ネットワークに AsyncTasks を使用するのが得策ではない理由が説明され、RoboSpice の使用方法が示されます。
この問題の概要をすばやく把握するには、このインフォグラフィックをご覧ください。
また、たとえば、バイナリ データのみをダウンロードし、POJO に関心がない場合でも、RoboSpice またはDownloadManagerを使用できます(ただし、API は RoboSpice ほど直感的ではありません)。