Retrofit 2 - 如何异步显示进度条?

Posted

技术标签:

【中文标题】Retrofit 2 - 如何异步显示进度条?【英文标题】:Retrofit 2 - How show progress bar async? 【发布时间】:2016-12-24 02:16:38 【问题描述】:

我在 android 中创建新项目时创建了默认登录活动。 默认情况下会创建一个progressBar,可以很好地登录并正确显示。这一切都是通过 AsyncTask 实现的。

现在我使用 Retrofit 2 让路异步登录。

当我按下按钮登录时启动了一个方法,内容:

    ....
    ....
    showProgress(true);
    call.enqueue(new Callback<User>() 

        @Override
        public void onResponse(Call<User> call, retrofit2.Response<User> response) 

            try 
                Thread.sleep(3000);
             catch (InterruptedException e) 
                e.printStackTrace();
            

            User userdatos = response.body();

                if(userdatos != null)
                    // redirect to Main Activity page
                    showProgress(false);
                    Intent i = new Intent(LoginActivity.this, MainActivity.class);
                    startActivity(i);
                
                else
                    showProgress(false);
                    mPasswordView.setError(getString(R.string.error_incorrect_password));
                    mPasswordView.requestFocus();
                
        
        @Override
        public void onFailure(Call<User> call, Throwable t) 
            call.cancel();
            showProgress(false);
            Toast.makeText(LoginActivity.this, "Please check your network connection and internet permission", Toast.LENGTH_LONG).show();
        
    );

我强制 Thread.sleep (3000) 检查。 没有进度条出现,调试显示: 跳过了 180 帧!应用程序可能在 ITS 主线程上做了太多工作。

如何解决?

我会有很多异步调用,我总是会显示一个进度条来等待响应完成。

谢谢

【问题讨论】:

你不应该在 UI 线程上调用 Thread.sleep() mmmm.... oki... 但是:从那以后我模拟请求需要几秒钟?这样才能保证进度条显示出来?另外,我认为使用 Retrofit 2 进行调用,所以 Async,会喜欢 AsyncTask。 我认为问题在于您的 showProgress 实现或该调用执行速度如此之快,并且您看不到进度条,因为它立即显示/隐藏。如果您添加延迟而不是睡眠(处理程序帖子),您将看到一个进度条。 感谢@Beloo,调用执行速度如此之快...... O_o。我尝试使用 hadlet post 添加延迟,效果很好 【参考方案1】:

让我与您分享由 Android Studio 创建的默认登录活动的代码实现和我的 Retrofit 实现。默认登录活动,包括AsyncTask,它称为UserLoginTask,在其中,我做了所有登录逻辑的东西。我使用.execute 而不是.enqueue,因为它是同步的,我们不需要AsyncTask 中的新线程

public class UserLoginTask extends AsyncTask<Void, Void, Boolean> 

        private final String mEmail;
        private final String mPassword;

        UserLoginTask(String email, String password) 
            mEmail = email;
            mPassword = password;
        

        @Override
        protected Boolean doInBackground(Void... params) 
            Retrofit restAdapter = new Retrofit.Builder()
                    .baseUrl(Constants.ROOT_API_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            IConstructSecureAPI service = restAdapter.create(IConstructSecureAPI.class);
            Call<JsonElement> result = service.getToken(mEmail, mPassword, "password");
            try 
                //using sync request and get response 
                JsonElement element = result.execute().body();
                if(element!=null) 
                    //do whatever you want with your response
                
             catch (IOException e) 
                e.printStackTrace();
                return false;
            
            return true;
        

        @Override
        protected void onPostExecute(final Boolean success) 
            mAuthTask = null;
            showProgress(false);

            if (success) 
                if(clientType != 2)
                    mPasswordView.setError(getString(R.string.error_incorrect_password));
                    mPasswordView.requestFocus();
                    clientType = 0;
                
                else 
                    Intent intent = new Intent(getApplicationContext(), MainActivity.class);
                    startActivityForResult(intent, 1);
                
//                finish();
             else 
                mPasswordView.setError(getString(R.string.error_incorrect_password));
                mPasswordView.requestFocus();
            
        

        @Override
        protected void onCancelled() 
            mAuthTask = null;
            showProgress(false);
        

    

【讨论】:

感谢您的代码。在我的一项测试中,我做到了。但我有一个问题:我们想使用 Rretrofit 2 Sync 和 AsyncTask 的原因是什么,可以使用 Retrofit 2 Async 吗?谢谢 @daicon 当然可以,但是在您的问题中,我没有看到您所有的活动代码。我也不明白你写了什么 sleep 。一般来说,你的问题对我来说不是很清楚,你是否有改造问题或 UI 的一些异常,或者只是看到警告“ITS 主线程上的工作太多”?【参考方案2】:

无耻宣传

我为此创建了RxLoading library,它可以做到这一点以及更多,

你可以这样做:

networkCall().compose(RxLoading.<>create(loadingLayout)).subscribe(...);

它由 2 个类组成,一个自定义视图 (loadingLayout) 和 RxLoading,它是一个 transformer,将它们粘合在一起,您可以选择同时使用它们或其中之一。

不过,您需要在 RxJava 中使用 retrofit2。

RxLoading 还支持空和错误状态(具有内置重试机制,因此请务必检查此选项)

您可以通过GitHub page了解更多信息。

【讨论】:

以上是关于Retrofit 2 - 如何异步显示进度条?的主要内容,如果未能解决你的问题,请参考以下文章

当片段视图加载是异步任务的一部分时,如何在片段加载之前显示进度条?

如何更新异步任务中的进度条

如何使用界面更新异步任务中的进度条

C# Winform 多线程异步委托进度条

异步上传,显示进度条

在 Unity3D 中,如何在迭代 FileInfo[] 数组(非阻塞)时异步显示 UI 径向进度条?