Android 当Activity从Web服务请求SoapObject时,如何实现ProgressDialog?

Android 当Activity从Web服务请求SoapObject时,如何实现ProgressDialog?,android,multithreading,android-activity,progressdialog,Android,Multithreading,Android Activity,Progressdialog,我知道ProgressDialog和Threads的问题已经被问过很多次了,但是没有一个解决方案适合我的项目。基本上我想做的是: 1) 当用户单击按钮时,“活动”会向服务器发送一个身份验证请求 2) 执行此操作时,将显示ProgressDialog 3) 当响应到来时,我想关闭ProgressDialog和要由活动读取和解释的返回对象 如果我: 1) 设置线程以使用响应更新应用程序字段,下一个方法(在线程之外)在访问字段时抛出NPE 2) 如果我在线程中包含下一个方法,则第二个方法将抛出“jav

我知道ProgressDialog和Threads的问题已经被问过很多次了,但是没有一个解决方案适合我的项目。基本上我想做的是: 1) 当用户单击按钮时,“活动”会向服务器发送一个身份验证请求 2) 执行此操作时,将显示ProgressDialog 3) 当响应到来时,我想关闭ProgressDialog和要由活动读取和解释的返回对象

如果我: 1) 设置线程以使用响应更新应用程序字段,下一个方法(在线程之外)在访问字段时抛出NPE 2) 如果我在线程中包含下一个方法,则第二个方法将抛出“java.lang.RuntimeException:无法在未调用Looper.prepare()的线程内创建处理程序”

很抱歉发了这么长的短信,但是我完全失去了它。。。我的代码是这样的:

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() {
// (...)
}
您最好使用(这是Android的方式):

@覆盖
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
新建任务().execute();
}
私有类任务扩展异步任务{
@凌驾
受保护的void onPreExecute(){
authProgressDialog=ProgressDialog.show(XXX.this,“,“Authentication…”,true,false);
}
@凌驾
受保护的Void doInBackground(Void…参数){
authenticate();//通过SOAP调用API的方法
authenticateReal();//处理响应的方法
返回null;
}
@凌驾
受保护的void onPostExecute(void结果){
authProgressDialog.disclose();
}
}

顺便说一下。。。我发现这个演示非常有用(它讨论REST应用程序,但您可以将相同的概念应用于不同类型的应用程序):

对于上一个问题,请在run()方法中添加“Looper.prepare();”

您是否检查了authenticate()方法中的响应是否正常工作?(使用LogCat显示响应)


否则,最好使用AsyncTask(如建议的)。

如果您真的想使用
线程而不是
异步任务,可以这样尝试:

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
        ...
    }
}

从您的代码中,无法100%清楚地知道变量
mHandler
分配给
新处理程序()的位置。要清楚,在我的代码中,这应该是
本身的
私有
字段。您还需要在
authenticate()
方法中进行一些错误处理,以便在遇到错误时发送消息以关闭对话框。

正如其他人已经编写的那样,AsyncTask是继续的方法

但是:AsyncTask和线程对于UI元素有一些缺陷:

如果您更改了手机方向,并且没有在Manifest.xml中为您的活动(意味着您必须自己处理onConfigChange)设置android:configChanges=“keyboardHidden | orientation”
,方向更改将破坏并重新创建活动和内容视图,还将断开ProgressDialog与可见窗口的连接(它已连接到旧窗口)。Android不会杀死你的线程或异步任务。如果活动被破坏,它也不会杀死它。这些后台任务将继续执行,直到完成为止

试图关闭()您先前创建的ProgressDialog会在ContentView被销毁后引发异常,因为它不再是窗口的一部分。在做一些分离(异步)工作的情况下,尝试/捕获很多。当再次调用onPostExecute()时,您可能依赖的所有内容都可能消失或被其他内容所取代。
最后,考虑注册活动中某个数组中启动的每个异步任务,并尝试在活动中取消它们。onDestroy()。

我可能会遗漏一些关于线程的基本信息,因为我从来没有真正读够它们。。。对不起,我问了个问题。authenticateReal()的内容可以轻松地传输到autenticate()的try块。非常感谢。这解决了问题:)正是我所需要的!!谢谢没有这个对话框甚至在执行完成之前都不会显示,因为它是异步的!谢谢你的宝贵意见。我也尝试过你的解决方案,但当使用ASyncTask时,我的类更干净。嗨,是的,处理程序也是一个私有字段,我只是在代码中错误地省略了它。我相信您的解决方案可能对我有用,但ASyncTask的答案解决了我的问题。看来异步任务更可取。非常感谢您的回复。
        @Override
        public void run() {
            Looper.prepare();
            authenticate(); // method that calls the API via SOAP
            authenticateReal(); // method that handles the response
        }
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
        ...
    }
}