【问题标题】:How to implement a ProgressDialog while Activity requests a SoapObject from a Web Service?如何在 Activity 从 Web 服务请求 SoapObject 时实现 ProgressDialog?
【发布时间】:2011-01-23 20:17:07
【问题描述】:

我知道带有线程问题的 ProgressDialog 已被多次询问,但似乎没有一个解决方案适用于我的项目。基本上我想做的是: 1)当用户单击按钮时,Activity 向服务器发送身份验证请求 2)在完成此操作时,会显示 ProgressDialog 3)当响应到来时,我想关闭 ProgressDialog 和返回对象以由 Activity 读取和解释

如果我: 1)设置Thread以响应更新Application字段,next方法(在Thread之外)访问该字段时会抛出NPE 2) 如果我在 Thread 中包含下一个方法,则第二种方法会抛出“java.lang.RuntimeException: Can't create handler inside thread that has not called 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() {
// (...)
}

【问题讨论】:

  • 我可能在这里遗漏了一些关于线程的基本知识,因为我从来没有真正读过足够多的东西……抱歉,我很抱歉。 authenticateReal() 的内容可以很容易地转移到 autenticate() 的 try 块中。

标签: android multithreading android-activity progressdialog


【解决方案1】:

你最好使用AsyncTask(这是Android方式):

@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();
    }
}

顺便说一句...我发现这个演示文稿非常有用(它讨论的是 REST 应用程序,但您可以将相同的概念应用于不同类型的应用程序):Developing Android REST client applications

【讨论】:

  • 非常感谢伙计。这已经解决了问题:)
  • 正是我需要的!!谢谢!!没有这个对话框甚至不会显示,直到执行完成,因为它是异步的!
【解决方案2】:

对于你的最后一个问题,输入“Looper.prepare();”进入你的 run() 方法。

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

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

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

【讨论】:

  • 感谢您的宝贵意见。我也尝试过您的解决方案,但是当使用 ASyncTask 时,我的课程更干净。
【解决方案3】:

如果您真的想使用Thread 而不是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
        ...
    }
}

从您的代码来看,变量mHandler 分配给new Handler() 的位置并不是100% 清楚的。需要明确的是,在我的代码中,这应该是 class 本身的 private 字段。您还需要在 authenticate() 方法中进行一些错误处理,以便在遇到错误时发送消息以关闭对话框。

【讨论】:

  • 嗨,是的,处理程序也是一个私有字段,我只是错误地从我的代码中省略了它。我确信您的解决方案可能对我有用,但 ASyncTask 答案解决了我的问题。似乎 ASyncTask 更可取。非常感谢您的回复。
【解决方案4】:

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

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

如果您更改手机方向并且没有在 Manifest.xml 中为您的 Activity 设置 android:configChanges="keyboardHidden|orientation"(意味着您必须自己处理 onConfigChange),则方向更改将破坏并重新创建您的 Activity 和 ContentView 并断开可见窗口中的 ProgressDialog(它连接到旧窗口)。 Android 不会杀死你的 Thread 或 AsyncTask。如果 Activity 被销毁,它也不会杀死它。那些后台任务一直持续到完成为止。

在 ContentView 被销毁后,尝试解除您先前创建的 ProgressDialog 会引发异常,因为它不再是您窗口的一部分。在做一些分离(异步)工作的情况下尝试/捕捉很多。当再次调用 onPostExecute() 时,您可能依赖的所有东西都可能消失或被不同的东西取代。 最终考虑在 Activity 的某个数组中注册每个 ASyncTask,并尝试在 Activity.onDestroy() 中取消它们。

【讨论】:

    猜你喜欢
    • 2014-10-02
    • 2017-09-15
    • 2011-04-18
    • 2021-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-06
    相关资源
    最近更新 更多