0

我目前正在运行一个 AsyncTask,它在下载文件时更新 Activity 中的进度条。问题是当我离开 Activity 并重新进入时,ProgressBar 将不再更新。

我尝试在服务中运行 AsyncTask,但我不知道如何将 ProgressBar 值发送回我的 Activity 的 UI 线程。

4

3 回答 3

1
  1. 在您的活动中添加静态进度变量
  2. 将进度保存到首选项

当您重新进入活动抓取并从静态变量或首选项设置进度。

于 2012-11-03T23:04:50.047 回答
1

我遇到了和你一样的问题:

  • 我想要执行一个异步任务(作为服务)
  • 我希望能够旋转设备,能够更新 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() );
}

}

主要思想是:

  • 活动通过广播与服务通信。以下事件从服务分派到 UI:下载进度(每 x 个字节报告一次)、下载完成、发生错误
  • 每个活动开始都被分配一个唯一的作业 ID,该 ID 保留用于屏幕旋转。
  • 每个作业结果都被持久化到数据库(或任何其他持久性存储)中。这样,即使收到的广播目前没有收听(屏幕关闭),我也可以获得工作结果。

希望有帮助。

于 2012-11-04T20:36:54.600 回答
0

这很正常。当您离开它们或旋转您的设备时,活动就会消失。然后它们被重新创建。AsyncTasks 不会自动重新链接到新的 Activity 实例。

实际上,RoboSpice是您正在寻找的库:它允许您从 Activity 启动下载、旋转设备、离开 Activity,甚至离开应用程序,甚至使用任务切换器杀死它,您的下载将继续存在。任何活动、以前活动的新实例,甚至是完全不同的活动,都可以重新链接到您的下载。

您应该从商店下载应用程序RoboSpice Motivations,它将向您解释为什么使用 AsyncTasks 进行网络不是一个好主意,并向您展示如何使用 RoboSpice。

要快速了解此问题,请查看此信息图表

另请注意,如果您只下载二进制数据并且对 POJO 不感兴趣,那么您仍然可以使用 RoboSpice 或DownloadManager(但它的 API 不如 RoboSpice 直观)。

于 2012-11-03T23:40:56.203 回答