How to implement a ProgressDialog while Activity requests a SoapObject from a Web Service?

大憨熊 提交于 2019-12-31 02:14:36

问题


I know that ProgressDialog with Threads questions have been asked many times but none of the solutions seem to work for my project. Basically what I want to do is this: 1) when a user clicks a button the Activity sends an auth request to the server 2) while this is being done a ProgressDialog is shown 3) when the reponse comes I want to dismiss the ProgressDialog and the return object to be read and interpreted by the Activity

If I: 1) set the Thread to update the Application field with the reponse, the next method (which is outside of the Thread) throws an NPE when accessing the field 2) if I include the next method in the Thread, the second method throws a 'java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()'

Sorry for a long text, but I am totally losing it over this... My code is sth like this:

public class XXX extends Activity implements OnClickListener {

// (...)
private SoapObject returnObject;
private String response;

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

    // (...)
        authProgressDialog = ProgressDialog.show(XXX.this, "", "Authenticating...", true, false);
        new Thread(new Runnable() {
            @Override
            public void run() {
                authenticate(); // method that calls the API via SOAP
                authenticateReal(); // method that handles the response
            }
        }).start();

        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 10:
                        authProgressDialog.dismiss();
                        break;
                }
            }
        };
    }
}

public void authenticate() {
    // API stuff (...)
    AndroidHttpTransport aht = new AndroidHttpTransport(URL);
    try {
        aht.call(SOAP_ACTION, soapEnvelope);
        returnObject = (SoapObject) soapEnvelope.getResponse();
        response = returnObject.getProperty("ResponseStatus").toString();
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    finally {
        mHandler.sendEmptyMessage(10);
    }
}

// Method that needs to access returnObject and reponse objects and
// it is here where the NPE's or other exceptions are thrown
public void authenticateReal() {
// (...)
}

回答1:


You better use AsyncTask (which is the Android way):

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    new TheTask().execute();
}

private class TheTask extends AsyncTask<Void, Void, Void>{

    @Override
    protected void onPreExecute() {
        authProgressDialog = ProgressDialog.show(XXX.this, "", "Authenticating...", true, false);
    }

    @Override
    protected Void doInBackground(Void... params) {
        authenticate(); // method that calls the API via SOAP
        authenticateReal(); // method that handles the response
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        authProgressDialog.dismiss();
    }
}

By the way... I have found this presentation to be very useful (it talks about REST apps, but you can apply the same concept for different kind of apps): Developing Android REST client applications




回答2:


For your last problem, put "Looper.prepare();" into your run() method.

        @Override
        public void run() {
            Looper.prepare();
            authenticate(); // method that calls the API via SOAP
            authenticateReal(); // method that handles the response
        }

Did you check if your response in your authenticate() method is working correctly? (using LogCat to display the response)

Otherwise, better use AsyncTask (like suggested).




回答3:


If you really want to use a Thread instead of an AsyncTask you can try it this way:

public class XXX extends Activity implements OnClickListener {
...
    private static int HANDLER_MESSAGE_AUTH_REQUEST_COMPLETE = 10;
...
    private void performAuthentication(){
        authProgressDialog = ProgressDialog.show(XXX.this, "", "Authenticating...", true, false);
        Thread backgroundThread = new Thread() {
            @Override
            public void run() {
                authenticate();
            }
        }
        backgroundThread.start();
    }

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what){
            case HANDLER_MESSAGE_AUTH_REQUEST_COMPLETE:
                authProgressDialog.dismiss();
                break;
            }
        }
    }

    private void authenticate(){
        // existing authenticate code goes here
        ...
        Message msg = Message.obtain();
        msg.what = HANDLER_MESSAGE_AUTH_REQUEST_COMPLETE;
        handler.sendMessage(msg);
        // existing authenticateReal code goes here
        ...
    }
}

From your code it is not 100% clear where the variable mHandler is assigned to the new Handler(). To be clear, in my code this should be a private field on the class itself. You will also need some error handling in your authenticate() method to send a message to dismiss the dialog if you encounter an error.




回答4:


As others already wrote, AsyncTask is the way to proceed.

BUT: AsyncTask and Threads have some pitfalls for UI elements:

If you change the phone orientation and did not set android:configChanges="keyboardHidden|orientation" for your Activity (means you have to handle onConfigChange by yourself) in the Manifest.xml, an orientation change will destroy and recreate your Activity and ContentView and also disconnect the ProgressDialog from the visible window (it's connected to the old one). Android is NOT going to kill your Thread or AsyncTask. It also won't kill it if the Activity is destroyed. Those background Task continue until they are done.

Trying to dismiss() your previsously created ProgressDialog throws an exception after the ContentView got destroyed, as it is not part of your window anymore. try/catch a LOT in situations doing something detached (async) work. Everything you possibly rely on just could have vanished or replaced by something different when onPostExecute() gets called again. Eventually think about registering every ASyncTask you start in some Array in your Activity and try to cancel() them at your Activity.onDestroy().



来源:https://stackoverflow.com/questions/4776236/how-to-implement-a-progressdialog-while-activity-requests-a-soapobject-from-a-we

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!