2

I have an AsyncTask class SearchForQuestions that is called from an Activity QuizMap. When looping through an array in SearchForQuestions I can't find the correct context for toast to appear within the AsynTask.

The standard Toast.makeText(getApplicationContext(), "This is Toast!!!", Toast.LENGTH_SHORT).show(); gives error getApplicationContext() undefined.

I have tried some of the solutions to this offerred by SO, most of them are listed here and concern getting UiThread and running on that.

I can't get this to work however. Here's example code snippets of what i have tried. I have put a method in QuizMap and try calling it from SearchForQuestions but SearchForQuestions isn't recognised. How can I get around this? )Still a newbie at java...)

// QuizMap activity

public class QuizMap extends FragmentActivity 
implements OnMarkerClickListener {

private GoogleMap map;

private static final String TAG = "QuizMap"; // debugging
...

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_quizmap);
     map = ((SupportMapFragment)  getSupportFragmentManager().findFragmentById(R.id.map))
               .getMap();
...
}

    // make toast inside AsyncTask
public void showNotNearToast(final String toast) {
    QuizMap.this.runOnUiThread(new Runnable() {
        public void run() {
            Toast.makeText(QuizMap.this, "This is Toast!!!", Toast.LENGTH_SHORT).show();

        }});
}

.

// SearchForQuestions class
private class SearchForQuestions extends AsyncTask<String, Void, DataHandler> {
    // checks for proximity to question locations

    Location location = 
            locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

    @Override
    protected DataHandler doInBackground(String... pointsList) {
        String result = pointsList[0];
        ...
}

    @Override
    protected void onPostExecute(DataHandler result) {

        ArrayList<String> resultsArray = result.results;
        Integer numPoints = resultsArray.size();
        for (int i =0;i<numPoints;i++){

            String[] pointDetails = resultsArray.get(i).split("::");
            ...

            // we can make use of the Android distanceTo function to calculate the distances
            float distance = location.distanceTo(fixedLoc);

            if (i > DIST) { // this is UCL

                showNotNearToast("My Message"); // showNotNearToast undefined 


                if (distance < DIST) {

             ...
                 }
                    };
Community
  • 1
  • 1
mark
  • 537
  • 6
  • 25

6 Answers6

1

I'm going t close this question. I haven't solved my problem but the number of answers provided that apparently work in other situations suggest there's something else going on. I'm going to re-structure the classes to get around having to call from within AsyncTask.

mark
  • 537
  • 6
  • 25
0

Just Toast it, why do you want to create a function for it? onPostExecute() is already on UI thread.

You are not able to access because inner Class can not call functions of Outer class unless you pass instance of the outer class.

Karan
  • 2,120
  • 15
  • 27
  • See my edit. `Toast.makeText(getApplicationContext(), "This is Toast!!!", Toast.LENGTH_SHORT).show();` doesn't work inside AsyncTask. – mark Apr 12 '15 at 17:52
  • AFAICS OP can call parent class' methods because he's using inner not nested (`static`) class. Weird it's undefined though. – Eugen Pechanec Apr 12 '15 at 17:52
0
  1. Call your toast in onPostExecute
  2. Create an interface for a callback.

public interface ToastCallback {
    public void invoke(String text);
}

Your AsyncTask constructor

private ToastCallback toastCallback;
public SearchQuestions(ToastCallback callback) {
    this.toastCallback = callback;
}

// in doInBackground() {

      toastCallback.invoke("Toast from background");
 }

In Your Activity,

private void showNotNearToast(String text) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
        }
   }); 
}

public class MyToastCallback implements ToastCallback {
     @Override
     public void invoke(String text) {
         showNotNearToast(text);
     }
}

// Asynctask call
new SearchQuestion(new MyTosatCallback()).execute(<Your params here>);
Froyo
  • 17,947
  • 8
  • 45
  • 73
  • So `public void showNotNearToast(...` , `public interface ToastCallback {...`, and `public class MyToastCallback implements ToastCallback {...` go in `QuizMap` and `private void showNotNearToast(String text) {...` . `public class MyToastCallback implements ToastCallback {...` and `new SearchQuestion(new...` go in `onPostExecute`? – mark Apr 12 '15 at 18:06
  • using the code placements I've specified above `new SearchQuestion(new MyToastCallback` cannot be resolved to a type – mark Apr 12 '15 at 18:13
  • You should put interface in a different file. `showNotNearToast` and `MyToastCallback class` go in your Activity class. – Froyo Apr 12 '15 at 18:20
  • sorry @Froyo, when you say different file for interface, do you mean any other .java file in my package? – mark Apr 12 '15 at 18:38
  • Yeah. You could do that – Froyo Apr 12 '15 at 19:32
0

Try this from inside your AsyncTask:

myActivity.this.runOnUiThread(new Runnable() {
    public void run() {
        Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
    }
});

Where you have your

showNotNearToast("My Message"); // showNotNearToast undefined

Replace myActivity with the name of your Activity.

Jonas Czech
  • 12,018
  • 6
  • 44
  • 65
  • Placing `myActivity.this.runOnUiThread(new...` just above `showNotNearToast("My Message");` gives `QuizMap.this`: No enclosing instance of the type QuizMap is accessible in scope – mark Apr 12 '15 at 18:28
0

(Ab)use the publishProgress method

private class ToastAsyncTask extends AsyncTask<Void, String, Void>{
        @Override
        protected Void doInBackground(Void... voids) {
            SystemClock.sleep(1000);
            publishProgress("Toast msg string");
            SystemClock.sleep(1000);
            return null;
        }

        @Override
        protected void onProgressUpdate(String... values) {
            Toast.makeText(getApplicationContext(), values[0], Toast.LENGTH_SHORT).show();
        }
    }

**UPDATE: ** since you are having problems with context for some reason, use this version. Tough the implementation above works for me.

private class ToastAsyncTask extends AsyncTask<Void, String, Void> {

        private WeakReference<Context> contextRef;

        public ToastAsyncTask(Context context) {
            contextRef = new WeakReference<Context>(context);
        }

        @Override
        protected Void doInBackground(Void... voids) {
            SystemClock.sleep(1000);
            publishProgress("Toast msg string");
            SystemClock.sleep(1000);
            return null;
        }

        @Override
        protected void onProgressUpdate(String... values) {
            if (contextRef.get() != null) {
                Toast.makeText(contextRef.get(), values[0], Toast.LENGTH_SHORT).show();
            } else {
                // The context was destroyed.. check what you are doing
            }
        }
    }

Use it like this

new ToastAsyncTask(MainActivity.this).execute();
Bojan Kseneman
  • 15,488
  • 2
  • 54
  • 59
-2

Pass the activity into the AsyncTask. See below.

private class SearchForQuestions extends AsyncTask<String, Void, DataHandler> {
    Activity activity;
    public void SearchForQuestions(Activity activity){
        this.activity = activity;
    }
//... rest of the code

  public class QuizMap extends FragmentActivity implements OnMarkerClickListener {
    /*...*/
    new SearchForQuestions(this).execute();
    /*...*/
    /*When calling the toast:*/
Toast.makeText(this.activity, "This is Toast!!!", Toast.LENGTH_SHORT).show();
Val
  • 495
  • 1
  • 4
  • 24
  • This is just bad. You don't need to pass activity. It will leak if you close the app. – Froyo Apr 12 '15 at 17:46
  • I suggest a [Handler](http://developer.android.com/reference/android/os/Handler.html) or a [BroadcastListener](http://developer.android.com/reference/android/content/BroadcastReceiver.html) – Sai Phani Apr 12 '15 at 17:47
  • @Froyo I got my answer from here: http://stackoverflow.com/a/4538370/2363810 has a lot of upvotes there – Val Apr 12 '15 at 17:59
  • Answer is incomplete? – Karan Apr 12 '15 at 18:04