【问题标题】:How to let Async Task finish in Android如何让异步任务在 Android 中完成
【发布时间】:2016-01-27 15:06:05
【问题描述】:

我正在开发一个从网络检索数据、将它们存储到设备然后读取它们的应用程序。 问题是,我在异步任务中获取数据。我的应用程序在尝试向用户显示数据之前没有让任务完成。 我试过 task.get() 但没有结果(它就停在那里)。

这是我的任务:

public GetOptionsTask(XMLPortalGetOptions request) {
        super(request);
    }
    protected void onCancelled(){
        // TODO afficher message pas d'options sur le disque
    }
    @Override
    public void handleError(Transaction transaction) {
        // TODO afficher message pas d'options sur le disque
    }
    @Override
    public void handleSuccess(Transaction transaction) {
        saveOptions(transaction.getResponse());
        request = null;
        Log.d(OptionsManager.class.getName(), this.getStatus().toString());
    }

此任务是我的自定义异步任务的一个实例:

protected BaseXMLTransaction request;

public abstract void handleError(Transaction transaction);
public abstract void handleSuccess(Transaction transaction);
public TransactionTask(BaseXMLTransaction request){
    this.request = request;
}
@Override
protected Void doInBackground(Void... params) {
    try {
        Log.i(TransactionTask.class.getName(), "Doing in background");
        SocketHandler.sendTransaction(this, request.getRequest());
    } catch (SocketHandlerNotConfiguredException e) {
        Log.e(TransactionTask.class.getName(), "SocketHandler's parameters were not set.");
    }
    return null;
}
@Override
public void transactionResult(Transaction transaction) {
    switch (transaction.getCode()) {
        case ERROR:
            Log.e(TransactionTask.class.getName(), "ERROR !!!");
            handleError(transaction);
            break;
        case NO_CLIENT:
            Log.e(TransactionTask.class.getName(), "No Client Error");
            handleError(transaction);
            break;
        case NO_SERVER:
            Log.e(TransactionTask.class.getName(), "No Server Error");
            handleError(transaction);
            break;
        case OLD_VERSION:
            Log.e(TransactionTask.class.getName(), "Old Version");
            handleError(transaction);
            break;
        case TIMEOUT:
            Log.e(TransactionTask.class.getName(), "Transaction Timeout");
            handleError(transaction);
            break;
        case SUCCESS:
            Log.i(TransactionTask.class.getName(), "Transaction Success");
            handleSuccess(transaction);
    }
}

我真的不知道该怎么办......执行速度很快,get 没有做任何事情,因为我没有返回任何我猜的东西。

【问题讨论】:

  • 这是每次用户使用您的应用程序时都需要做的事情,还是数据下载到设备一次并保存?
  • 保存一次,除非用户要求应用重新加载来自网络的数据或数据过期(一周后)
  • “我的应用程序在尝试向用户显示数据之前没有让任务完成”到底是什么意思?如@Matias Elorriaga 回答所示,是否在 onPostExecute() 中触发了 gui 更新。可以添加 onPostExecute() 的代码和 gui 更新代码吗?
  • 还有saveOptions这个方法有什么作用呢?您如何保存选项?
  • saveOptions() 只是将数据写入设备上的 xml 文件中。

标签: java android android-asynctask


【解决方案1】:

onPostExecute(Result),在后台计算完成后在 UI 线程上调用。后台计算的结果作为参数传递给这一步。

@Override
protected void onPostExecute(String result) {

}

【讨论】:

    【解决方案2】:
    private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
         protected Long doInBackground(URL... urls) {
             int count = urls.length;
             long totalSize = 0;
             for (int i = 0; i < count; i++) {
                 totalSize += Downloader.downloadFile(urls[i]);
                 publishProgress((int) ((i / (float) count) * 100));
                 // Escape early if cancel() is called
                 if (isCancelled()) break;
             }
             return totalSize;
         }
    
         protected void onProgressUpdate(Integer... progress) {
             setProgressPercent(progress[0]);
         }
    
         protected void onPostExecute(Long result) {
             showDialog("Downloaded " + result + " bytes");
         }
     }
    

    然后这样称呼它:

    new DownloadFilesTask().execute(url1, url2, url3);
    

    【讨论】:

    • 只是一个例子,重点是你需要重写onPostExecute,该方法在UI线程中运行并作为参数接收asyncTask的响应(doInBackground方法)
    【解决方案3】:

    我使用接口作为委托来执行此操作。这是一个例子:

    在我的主要活动中,我有一个 onClick 监听器来触发我的异步调用,还有一个监听器在调用完成后进行处理。

    private void enableLocationButton(){
        locationButton = (Button) findViewById(R.id.locationButton);
        locationButton.setEnabled(true);
        locationButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this, selectLocationActivity.class);
                intent.putExtra("serverURL",server.getWebServerAddressField());
                startActivityForResult(intent, 200);
            }
        });
    
    }
    
     @Override
    protected void onActivityResult(int requestCode,int resultCode, Intent data){
        if(resultCode == RESULT_OK) {
            switch (requestCode){
                case 100:
                    processServerResponse((PmsWebServer) data.getBundleExtra("server").get("server"));
                    break;
                case 200:
                    processLocationResponse((PmsDataSource)data.getBundleExtra("location").get("location"));
                default:processError();
            }
        }else{
            processError();
        }
    }
    

    在 selectLocationActivity 的某处,我调用了 Async 调用并处理了响应,请注意,该类实现了 Async 调用中使用的接口。

    public class selectLocationActivity extends ListActivity implements SoapServiceInterface{
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_location_select);
        chosenServer = this.removeURLHeader(getIntent().getStringExtra("serverURL"));
        this.retrieveLocationOptionsByServer(chosenServer);
    }
    
    private void retrieveLocationOptionsByServer(String server) {
        Map<String,Object> parms = new HashMap<String,Object>();
        parms.put(WEB_SERVER_NAME,server);
        SoapServiceObject service = new SoapServiceObject(Services.SERVICE_DETAILS,parms);
        callTheService(service);
    }
    
    private void callTheService(SoapServiceObject service){
        SoapServiceHelper helper = new SoapServiceHelper();
        helper.delegate = thisActivity;
        helper.execute(service);
    }
    
    @Override
    public void serviceCallComplete(SoapObject response){
        this.createClickableListOnScreen(response);
    } 
    //...more code...//
    }
    

    serviceCallComplete 由 asyncTask 启动。以下是该任务的代码

    public class SoapServiceHelper extends AsyncTask<SoapServiceObject, Void, SoapObject>{
    public SoapServiceInterface delegate = null;
    private Integer RETRY_COUNT = 0;
    private final Integer MAX_RETRY_COUNT = 2;
    
    protected SoapObject doInBackground(SoapServiceObject... args){
        SoapServiceObject service = args[0];
        try{
            service.callTheService();
        }catch(Exception e){
            System.out.println("An error occurred calling the service\n" + e.getMessage());
        }
        return service.getResponse();
        //return callDateTimeService();
    }
    
    protected void onPostExecute(SoapObject result){
        delegate.serviceCallComplete((SoapObject)(result.getProperty(0)));
    } 
    }
    

    最后是界面

    public interface SoapServiceInterface {
    
        public void serviceCallComplete(SoapObject response);
    }
    

    我知道我正在从结果中直接在屏幕上显示一些内容,只需将那部分替换为保存并读取;)

    【讨论】:

    • 仅供参考,这只是一个帮助我的队友了解 asyncTask 工作原理的实验,我知道我不应该打印出异常
    【解决方案4】:

    该任务的一个特点是将内容保存到单例中。我设法使用保存在 onResume() 的单例中的网络信息来调用这些方法。当线程结束时,它会进入 onResume,一切正常!

    【讨论】:

      猜你喜欢
      • 2017-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-26
      • 2013-03-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多