Reputation: 841
I currently have an AsyncTask running that updates the progress bar inside the Activity while downloading a file. The problem is when i leave the Activity and reenters, the ProgressBar will not update anymore.
I tried running the AsyncTask inside a Service but i have no idea how to send the ProgressBar value back to my Activity's UI thread.
Upvotes: 0
Views: 900
Reputation: 632
I came to the same problem as you did:
I came up with something like:
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() );
}
}
The main idea is:
hope that helps.
Upvotes: 1
Reputation: 38168
This is normal. Activities die when you leave them or rotate your device. Then they are recreated. AsyncTasks don't relink to the new Activity instance automatically.
Actually, RoboSpice is the library you are looking for : it will allow you to launch a download from an activity, rotate the device, leave the activity, even leave the app, even kill it using the task switcher and your download will survive. Any activity, a new instance of your former activity, or even a completely different one will be able to relink to your download.
You should download the app RoboSpice Motivations from the store, it will explain you why it's not a good idea to use AsyncTasks for networking and show you how to use RoboSpice.
To get a good & fast overview of this problem, please have a look at this infographics.
Also note that if you only download binary data and are not interested in POJOs for instance, then you can use RoboSpice still or the DownloadManager (but it's API is less intuitive than RoboSpice).
Upvotes: 0
Reputation: 19788
When you re-enter activity grab and set progress from static variable or preferences.
Upvotes: 1