如何在 Android 中以编程方式隐藏 AsyncTask 中的 ProgressBar?

Posted

技术标签:

【中文标题】如何在 Android 中以编程方式隐藏 AsyncTask 中的 ProgressBar?【英文标题】:How to hide a ProgressBar in AsyncTask programmatically in Android? 【发布时间】:2019-08-02 03:30:36 【问题描述】:

我有以下静态AsyncTask 类:

public static class MyAsyncTask extends AsyncTask<String, Void, String> 
    @Override
    protected void onPreExecute() 
        super.onPreExecute();
        progressBar.setVisibility(View.VISIBLE);
    

    @Override
    protected String doInBackground(String... params) 
        //Do heavy stuff
    

    @Override
    protected void onPostExecute(String string) 
        super.onPostExecute(string);
        progressBar.setVisibility(View.GONE);
    

我想显示/隐藏progressBar,正如您在这两种方法中看到的那样。问题是我必须将progressBar 设为静态。这样做,我得到:

不要将 android 上下文类放在静态字段中;这是内存泄漏(也会破坏 Instant Run)

如果我删除留在我的 MyAsyncTask 类前面的静态,我会得到:

此 AsyncTask 类应该是静态的,否则可能会发生泄漏 (MainActivity.MyAsyncTask)

如何解决?

编辑:

private void checkUser() 
    uidRef.get().addOnCompleteListener(task -> 
        if (task.isSuccessful()) 
            DocumentSnapshot document = task.getResult();
            User user = document.toObject(User.class);
            if (user == null) 
                MyAsyncTask myAsyncTask = new MyAsyncTask();
                myAsyncTask.execute(url);
            
        
    );

【问题讨论】:

如果您仅从 MainActivity 调用,则 MyAsyncTask 类不需要是静态的。 如何将字符串输出发送回主类/活动? @myatmins 我只从MainActivity 中的一个方法创建了一个新对象MyAsyncTask myAsyncTask = new MyAsyncTask();,为什么说它不需要是静态的? @amitava 只需在TextVIew 上设置值,就是这样。如何解决? 请同时显示执行异步任务的代码。 【参考方案1】:

我之前在异步任务中遇到了这个“静态”问题,有一种非常好的方法可以将异步任务的输出返回到活动中。简单地说

String output = myAsyncTask.execute(url).get();

你会得到输出,最终的代码是。

progressBar.setVisibility(View.VISIBLE);                                  
String output = myAsyncTask.execute(url).get();
progressBar.setVisibility(View.GONE);

在您获得输出之前,不会执行下一行。我正在添加示例代码以进行进一步演示。

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    Button exe = findViewById(R.id.async);
    exe.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            try 
                updateAsyncTask up = new updateAsyncTask();

                long l = up.execute().get();
                System.out.println("inside main "+l);                    
             catch (ExecutionException e) 
                e.printStackTrace();
             catch (InterruptedException e) 
                e.printStackTrace();
            
        
    );




 private static class updateAsyncTask extends AsyncTask<Void, Void, Long> 

    @Override
    protected Long doInBackground(Void... voids) 

        long l = 0;
        for(int i=0;i<2000;i++)
        
            l = l+i;
            System.out.println(l);              

        
        return l;
    

    

【讨论】:

谢谢,我现在应该在哪里设置progressBar.setVisibility(View.VISIBLE);?因为在我的代码中,我将其设置为onPreExecute() 正如我所说,您可以在 myAsyncTask.execute(url) 之前设置它。这会是个问题吗? 您确定在String output = myAsyncTask.execute(url).get(); 之后立即调用progressBar.setVisibility(View.GONE); 会等待doInBackground 内的工作完成吗? 这是我记得的,因为我使用输出作为返回,如果没有返回输出我会得到一个空指针异常。 让我试着让你回来。【参考方案2】:

我在使用 asyncTask 作为静态子类时遇到了同样的问题,为了解决它,我使用了方法反射。这可能有点棘手,但对我有用:

public class MainClass
 @keep
 public void AfterLoad(String value) 

  
 public void callAsync() 
   Class[] parameterTypes = new Class[1];
    parameterTypes[0] = String.class;
    try 
        Method method1 = MainClass.class.getMethod("AfterLoad", 
  parameterTypes);
        MyAsyncTask task = new MyAsyncTask(this, method1);
        task.execute(link);
     catch (NoSuchMethodException e) 
        e.printStackTrace();
    
  

public static class MyAsyncTask extends AsyncTask<String, String, Void> 
    private final Method mAfterLoad;
    private final Object mOwner;

    public MyAsyncTask(Object owner, Method afterLoad) 
        this.mAfterLoad = afterLoad;
        this.mOwner = owner;
      
   @Override
    protected Void doInBackground(String... requests) 
     // do what you want
    

    @Override
    protected void onProgressUpdate(String... values) 
        super.onProgressUpdate(values);
        if (mAfterLoad != null) 
            try 
                Object[] parameters = new Object[1];
                parameters[0] = values[0];
                mAfterLoad.invoke(mOwner, parameters);
             catch (IllegalAccessException e) 
                e.printStackTrace();
             catch (InvocationTargetException e) 
                e.printStackTrace();
            
        
    
 

这样做您将克服内存泄漏问题,但是,请注意,对于调用该方法,它的名称作为字符串传递,您应该添加 @keep 注释以将其从 pro-guard 优化和重构中保存。

【讨论】:

感谢您的回答。我会尽力让你回来。

以上是关于如何在 Android 中以编程方式隐藏 AsyncTask 中的 ProgressBar?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 8 中以编程方式隐藏状态栏 [重复]

以编程方式获取 Android 手机型号,如何在 android 中以编程方式获取设备名称和型号?

如何在android中以编程方式启用位置访问?

如何在 Android 10 中以编程方式安装任何 Android 应用

如何在Android中以编程方式打开MIUI系统Activity

如何在 Android 中以编程方式创建 TabLayout