Filip Rosca Filip Rosca - 6 months ago 31
Android Question

Is it ok to put AsyncTask class inside Activity class?

Is it ok to write an AsyncTask class inside an Activity class? Or should I create another file for this? But, in this case, I couldn't manipulate the UI, or update it from AsyncTask. So, if I'll create another file for AsyncTask, then how could I update the UI in Activity class? Thanks in advance!

JLT JLT
Answer

Is it ok to write an AsyncTask class inside an Activity class?

Yes, it is OK but not a good practice. It's a matter of clean coding, separating a view from a controller. It might also cause memory leak issues. You can pass the reference of your Activity to AsyncTask, but should only be a weak reference.

I couldn't manipulate the UI, or update it from AsyncTask. So, if I'll create another file for AsyncTask, then how could I update the UI in Activity class?

There are a lot of ways to update the UI in that case. You can use a BroadcastReceiver, Handler, or an Interface.

I suggest you use Interface because it's the simplest and I think the most appropriate one.

Here's a sample:

You create a new file for your AsyncTask. You write a new class subclassing AsyncTask.

public class DownloadTask extends AsyncTask<String, Float, Long>
{
    public DownloadTaskListener mListener;

    public interface DownloadTaskListener
    {
        public void onDownloadFinish();
        public void onDownloadProgress(float progress);
    }

    @Override
    protected Long doInBackground(String... arg0) 
    {
        //start downloading

        return 0L; //return download size
    }

    protected void onProgressUpdate(Float... progress) 
    {
        if(mListener != null)
        {
            mListener.onDownloadProgress(progress[0]);
        }
    }

    protected void onPostExecute(Long result) 
    {
        if(mListener != null)
        {
            mListener.onDownloadFinish();
        }
    }
}

As you can see here, you can use these methods of the interface to notify the updates for your UI.

public interface DownloadTaskListener
{
    public void onDownloadFinish();
    public void onDownloadProgress(float progress);
}

In your MainActivity you have to implement to that interface so that the callbacks would work:

public class MainActivity extends Activity implements DownloadTaskListener
{
    DownloadTask download = new DownloadTask();

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        download.mListener = this;
        download.execute("Download URL");
    }

    @Override
    public void onDownloadFinish() 
    {
        MainActivity.this.runOnUiThread(new Runnable() 
        {
            public void run() 
            {
                //updates to UI here.
            }
        });
    }

    @Override
    public void onDownloadProgress(float progress) 
    {
        MainActivity.this.runOnUiThread(new Runnable() 
        {
            public void run() 
            {
                //updates to UI here.
            }
        });
    }
}

Take a look at this line:

download.mListener = this;

You just pass the reference of your Activity (implementing the interface) so that the AsyncTask could call the interface methods of your Activity in order for you to update your Activity.

And also take note that AsyncTask is a Thread. When you update some changes to the UI, you should always do it in the Main Thread or UI Thread. Check this part:

MainActivity.this.runOnUiThread(new Runnable() 
            {
                public void run() 
                {

                }
            });

Sorry, not a professional explainer but I hope I made this clear for you. :)

Comments