简体   繁体   中英

How to show spinning progress dialogue with using separate Async Task Class

In my app, i'm reading text files from web server using Async Tasking from a separate class because it is used in many activities, so i've made a dedicated class. I'm trying to show a spinning progress dialogue but it is giving me error when i put the code in Async Tasking class.

here is my cod for Async Task Class

public class Utilssss extends AsyncTask<String, String, String> {
    private Context         mContext;
    private ProgressDialog  pdia;

    // constructor
    public Utilssss(Context activityContext) {
        mContext = activityContext;
    }

    protected void onPreExecute() {
        super.onPreExecute();
        pdia = new ProgressDialog(mContext);
        pdia.setMessage("Loading...");
        pdia.show();
    }

    protected String doInBackground(String... url) {
        return GetLinkss(url[0]);

    }

    protected void onPostExecute(String result) {
        // Toast.makeText(mContext, result, Toast.LENGTH_LONG).show();
        super.onPostExecute(result);
        pdia.dismiss();
    }

    private String GetLinkss(String url) {

        // your stuff
        String StringBuffer = "";
        String stringText = "";
        try {
            URL link = new URL(url);
            BufferedReader bufferReader = new BufferedReader(new InputStreamReader(link.openStream()));

            while ((StringBuffer = bufferReader.readLine()) != null) {
                stringText += StringBuffer;
            }
            bufferReader.close();
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return stringText;
    }

}

Code how i'm accessing this class

public void urdu(View view) throws InterruptedException, ExecutionException {
        String fileexist = null;

        fileexist = new Utilssss(getBaseContext()).execute("http://192.168.1.2/eWorldLiterature/urdu/index.txt").get();

        Toast.makeText(getBaseContext(), fileexist, Toast.LENGTH_SHORT).show();

        // if (fileexist != 229) {
        Intent i = new Intent(getBaseContext(), MainPage.class);
        i.putExtra(LANGUAGE, "urdu");
        startActivity(i);

Here is the LogCat results.

12-05 00:38:06.266: E/AndroidRuntime(28766): FATAL EXCEPTION: main
12-05 00:38:06.266: E/AndroidRuntime(28766): java.lang.IllegalStateException: Could not execute method of the activity
12-05 00:38:06.266: E/AndroidRuntime(28766):    at android.view.View$1.onClick(View.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at android.view.View.performClick(View.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at android.view.View$PerformClick.run(View.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at android.os.Handler.handleCallback(Handler.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at android.os.Handler.dispatchMessage(Handler.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at android.os.Looper.loop(Looper.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at android.app.ActivityThread.main(ActivityThread.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at java.lang.reflect.Method.invokeNative(Native Method)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at java.lang.reflect.Method.invoke(Method.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at dalvik.system.NativeStart.main(Native Method)
12-05 00:38:06.266: E/AndroidRuntime(28766): Caused by: java.lang.reflect.InvocationTargetException
12-05 00:38:06.266: E/AndroidRuntime(28766):    at java.lang.reflect.Method.invokeNative(Native Method)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at java.lang.reflect.Method.invoke(Method.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    ... 12 more
12-05 00:38:06.266: E/AndroidRuntime(28766): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
12-05 00:38:06.266: E/AndroidRuntime(28766):    at android.view.ViewRootImpl.setView(ViewRootImpl.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at android.app.Dialog.show(Dialog.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at md.literature.imranseries.Utilssss.onPreExecute(Utilssss.java:35)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at android.os.AsyncTask.executeOnExecutor(AsyncTask.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at android.os.AsyncTask.execute(AsyncTask.java)
12-05 00:38:06.266: E/AndroidRuntime(28766):    at md.literature.imranseries.Selection.urdu(Selection.java:65)
12-05 00:38:06.266: E/AndroidRuntime(28766):    ... 14 more

Just one more thing i want to ask. Sorry to bother you guys again.. Here is the thing, one of my activity relies on the results of Asynctask and should no proceed unless the task is completed, but this is not happening, here is a sample piece of code which proves it.

        final Context context = this;
        new Utils(context, new Utils.UtilsCallback() {
            @Override
            public void onResult(String lstr) {
//              lstr = string;
                Toast.makeText(getBaseContext(), "Now Raeading" + Novelselected, Toast.LENGTH_LONG).show();
            }
        }).execute(ulti_link + "/" + Novelselected.replace(" ", "%20") + ".txt");

        Toast.makeText(getBaseContext(), "Now Raeading", Toast.LENGTH_LONG).show();

in the above code, the following Toast appears before the Toast within the AsyncTAsk appears, The question is, how can i pause my main thread to wait for the AsyncTAsk to complete. Thanks a lot :)

I suggest you read this explanation about the different types of Context Android has. There are some instances of Context that do not allow you to do certain things that other Context instances do (ie Service is a Context that doesn't allow layout inflation).

In your case you are passing the Application Context to the AsyncTask constructor, and subsequently to the Dialog . You should use an Activity Context instead.

Since you are calling the AsyncTask from an Activity and Activity extends from Context you can use the keyword this in the AsyncTask instantiation like Cata said.

Besides using the correct Context you must not use AsyncTask#get() . Never. It blocks the Ui thread until the result is available and you can not show a progress dialog during that time then because you are already waiting for the result.

If you want to use an AsyncTask from a different class add a callback mechanism of your own.

public class Utilssss extends AsyncTask<String, String, String> {

    /** Implement this somewhere to get the result */
    public interface UtilssssCallback {
        void onResult(String string);
    }

    private Context mContext;
    private ProgressDialog pdia;

    private UtilssssCallback mListener;

    // constructor
    public Utilssss(Context activityContext, UtilssssCallback listener) {
        mContext = activityContext;
        mListener = listener; // save callback
    }

    @Override
    protected void onPostExecute(String result) {
        pdia.dismiss();
        mListener.onResult(result);
    }

    // rest omitted since unchanged

}

And inside your Activity

public void urdu(View view) {
    final Context context = this;
    new Utilssss(context, new Utilssss.UtilssssCallback() {
        @Override
        public void onResult(String string) {
            Toast.makeText(context, string, Toast.LENGTH_LONG).show();
            Intent i = new Intent(context, MainPage.class);
            i.putExtra(LANGUAGE, "urdu");
            context.startActivity(i);
        }
    }).execute("http://192.168.1.2/eWorldLiterature/urdu/index.txt");
}

Note that the code inside onResult is executed way after the program flow has already left the urdu(View view) method.


Alternatively to implementing the callback as an anonymous inner class ( new UtilssssCallback(){...} ) you could also let the Activity implement the interface and make it a method. Doing it that way looks less confusing but is essentially the same.

public class TheActivity extends FragmentActivity implements UtilssssCallback {

    public void urdu(View view) {
        // those two are not necessary but help make it obvious what parameters we have
        Context context = this;
        UtilssssCallback callback = this; // the class implements that
        new Utilssss(context, callback).execute("http://192.168.1.2/eWorldLiterature/urdu/index.txt");
    }

    @Override
    public void onResult(String string) {
        Toast.makeText(context, string, Toast.LENGTH_LONG).show();
    }

....

I would suggest two things:

  1. Use a WeakReference when passing a context to an AsyncTask
  2. Call a method on your Activity to start and stop your progress dialog

Something like this:

public class ProgressAsyncTask extends AsyncTask<Void, Void, Void> {

    private WeakReference<Activity> weakActivity;

    public ProgressAsyncTask(Activity activity) {
        weakActivity = new WeakReference<Activity>(activity);
    }

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

        Activity activity = weakActivity.get();
        ((MainActivity) activity).showProgressDialog(true);

    }

    @Override
    protected void doInBackground(Void... params) {
        // Do stuff
    }

    @Override
    protected void onPostExecute(List<Color> result) {
        super.onPostExecute(result);

        Activity activity = weakActivity.get();
        ((MainActivity) activity).showProgressDialog(false);
    }

In your MainActivity you implement the method showProgressDialog(boolean show) .

And as Emmanuel pointed out you should most likely pass an Activity 's context.

Try this:

fileexist = new Utilssss(this).execute("http://192.168.1.2/eWorldLiterature/urdu/index.txt").get();

Where "this" should be the Activity and assumming that the parameter represents the mContext on the Utilssssclass side :).

And also pay attention to Emmanuel's answer too.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM