0

I am trying to finish my AsyncTask named DownloadSong while cancel Asynctask, but it gives nullPointerException as error. How can i finish Asynctask on onCancelled().

public class DownloadSong extends AsyncTask<String, Integer, String> {

Context context;
Activity activity;
public static String songName, songURL;

private NotificationHelper mNotificationHelper;
public static int notificationID = 1;
boolean download = false;

DownloadSong asynk;

public DownloadSong()
{
    this.activity=activity;
}

public DownloadSong(Activity activity, String songName, String songURL) {
    this.activity = activity;
    this.songName = songName;
    this.songURL = songURL;

    mNotificationHelper = new NotificationHelper(activity, songName);
}

@Override
protected void onPreExecute() {
    super.onPreExecute();

    notificationID++;
    mNotificationHelper.createNotification(notificationID);
}

@Override
protected String doInBackground(String... file_URL) {

    try {
        URL url = new URL(songURL);
        HttpURLConnection URLconnection = (HttpURLConnection) url.openConnection();
        URLconnection.setRequestMethod("GET");
        URLconnection.setDoOutput(true);
        URLconnection.connect();

        // Detect the file length
        int fileLength = URLconnection.getContentLength();

        File fSDcard = Environment.getExternalStorageDirectory();
        String strSdcardPath = fSDcard.getAbsolutePath();

        File fDirectory = new File(strSdcardPath + "/GSD");

        if (!fDirectory.exists()) {
            fDirectory.mkdir();
        }

        File fMyFile = new File(fDirectory.getAbsolutePath() + "/" + songName + ".mp3");
        Log.e("Download file name ", fMyFile.toString());

        FileOutputStream out = new FileOutputStream(fMyFile, true);

        InputStream input_File = URLconnection.getInputStream();

        byte[] data = new byte[1024];
        int total = 0;
        int count;

        while ((count = input_File.read(data)) != -1 && !isCancelled()) {

            total += count;
            publishProgress((int) (total * 100 / fileLength));

            out.write(data, 0, count);
        }

        out.flush();
        out.close();
        input_File.close();

    } catch (IOException e) {

        Log.e("Download Error : ", "Failed");
    }
    Log.e("Download status", " Complete ");

    return null;
}

@Override
protected void onPostExecute(String s) {

    if (download) {

        mNotificationHelper.clearNotification();

        Toast.makeText(activity, "Could Not Connect to Server.", Toast.LENGTH_LONG).show();
        Log.e("download","could not connect to server");
    } else {

        mNotificationHelper.completed();
        try {
            Toast.makeText(activity, "Song " + "'" + songName + "'" + " downloaded successfully", Toast.LENGTH_LONG).show();
        }catch (Exception e)
        {
            Toast.makeText(activity, "Song downloaded successfully", Toast.LENGTH_LONG).show();
        }
        Log.e("download", "completed");
    }
}

@Override
protected void onProgressUpdate(Integer... progress) {

    mNotificationHelper.progressUpdate(progress[0]);
    super.onProgressUpdate(progress);
}

@Override
protected void onCancelled() {
    super.onCancelled();
    asynk.activity.finish();
}}

I cancel asynctask from BroadcastReceiver.

public class CancelDownloadReceiver extends BroadcastReceiver {

Context context;
DownloadSong asynk;
NotificationHelper manage;
Activity activity;

public CancelDownloadReceiver() {
}

@Override
public void onReceive(Context context, Intent intent) {

    int notificationId = intent.getIntExtra("notificationId", 0);
    Log.e("Notification ID ",notificationId+"");

    NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    manager.cancel(notificationId);

    asynk=new DownloadSong(activity);
    Log.e("Activity",activity+"");
    asynk.cancel(true);

    Toast.makeText(context,"Download cancelled.",Toast.LENGTH_LONG).show();}

But it gives fatal error as below :

Process: com.dnk.gsd, PID: 31934
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.app.Activity.finish()' on a null object reference
at com.dnk.gsd.DownloadSong.onCancelled(DownloadSong.java:144)
at android.os.AsyncTask.onCancelled(AsyncTask.java:405)
at android.os.AsyncTask.finish(AsyncTask.java:630)
at android.os.AsyncTask.access$600(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5576)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:956)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:751)
Urvashi Patel
  • 110
  • 1
  • 2
  • 12

1 Answers1

2

The problem of nullPointerException is not because you cancel the AsyncTask, but because you trying to finish the caller activity. Your activity could be destroyed before your AsyncTask finish working its process. So, instead using

Activity activity;

Change to:

WeakReference<Activity> activityWeakRef;

Then in your constructor change to:

public DownloadSong(Activity activity, String songName, String songURL) {
    this.activityWeakRef = new WeakReference<>(activity);
    this.songName = songName;
    this.songURL = songURL;

    mNotificationHelper = new NotificationHelper(activity, songName);
}

then you get the activity by using:

activityWeakRef.get();

And in your onCancelled():

@Override
protected void onCancelled() {
    activityWeakRef.get().finish();
    super.onCancelled();

}

Those following change will avoid you from the leaking activity and nullPointerException.

-- UPDATE --

You can read the following QA about killing AsyncTask:

How to completely kill/remove/delete/stop an AsyncTask in Android

-- NEW UPDATE --

To make sure your activity not null, always check it. change to this:

@Override
protected void onCancelled() {
  if(activityWeakRef.get() != null) {
     activityWeakRef.get().finish();
  }
  super.onCancelled();
}

-- NEW NEW UPDATE -- Remember to your default contstructor to private and remove initialization of activity there. From following code:

public DownloadSong()
{
    this.activity=activity;
}

to

private DownloadSong()
{
}

This will assure you don't accidentally create a new AsyncTask without initializing activity.

Community
  • 1
  • 1
ישו אוהב אותך
  • 28,609
  • 11
  • 78
  • 96
  • Still it gives an error that java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.lang.ref.WeakReference.get()' on a null object reference. – Urvashi Patel Jun 25 '16 at 10:23
  • java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.lang.ref.WeakReference.get()' on a null object reference at com.dnk.gsd.DownloadSong.onCancelled(DownloadSong.java:150) – Urvashi Patel Jun 25 '16 at 11:15
  • @UrvashiBhalala: change on cancelled to this. **Activity activity = activityWeakRef.get(); if(activity != null) {activity.finish()} super.onCancelled();** – ישו אוהב אותך Jun 25 '16 at 11:47