Как реализовать ProgressDialog, когда Activity запрашивает SoapObject из веб-службы? - PullRequest
3 голосов
/ 23 января 2011

Я знаю, что вопросы ProgressDialog with Threads задавались много раз, но ни одно из решений, похоже, не работает для моего проекта.По сути, я хочу сделать следующее: 1) когда пользователь нажимает кнопку, действие отправляет запрос на проверку подлинности на сервер. 2) в то время, когда это делается, отображается ProgressDialog. 3) когда приходит ответ, я хочу отклонить ProgressDialog иобъект возврата, который должен быть прочитан и интерпретирован Activity

Если I: 1) установить Thread для обновления поля Application с ответом, следующий метод (который находится вне Thread) выбрасывает 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() {
// (...)
}

Ответы [ 4 ]

8 голосов
/ 23 января 2011

Вам лучше использовать 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, но вы можете применять одну и ту же концепцию для различных типов приложений): Разработка клиентских приложений Android REST

2 голосов
/ 23 января 2011

Для вашей последней проблемы поставьте "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 (как предложено).

1 голос
/ 24 января 2011

Как уже писали другие, AsyncTask - это способ продолжить.

НО: у AsyncTask и Threads есть некоторые подводные камни для элементов пользовательского интерфейса:

Если вы изменили ориентацию телефона и не установили android:configChanges="keyboardHidden|orientation" для вашей Деятельности (означает, что вы должны обрабатывать onConfigChange самостоятельно) в файле Manifest.xml, изменение ориентации уничтожит и заново создаст ваши Activity и ContentView, а также отключит ProgressDialog из видимого окна (оно подключено к старому).Android НЕ собирается убивать ваш поток или AsyncTask.Он также не убьет его, если действие будет уничтожено.Эти фоновые задачи продолжаются до тех пор, пока они не будут выполнены.

Попытка отклонить () ваш предварительно созданный ProgressDialog выдает исключение после уничтожения ContentView, так как он больше не является частью вашего окна.попробуйте / поймайте LOT в ситуациях, выполняющих что-то отдельное (асинхронное).Все, на что вы можете положиться, могло просто исчезнуть или заменить что-то другое, когда onPostExecute () будет вызван снова.В конце концов подумайте о регистрации каждой ASyncTask, которую вы запускаете в каком-либо массиве в вашей деятельности, и попытайтесь отменить () их в вашем Activity.onDestroy ().

1 голос
/ 24 января 2011

Если вы действительно хотите использовать 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
        ...
    }
}

Из вашего кода не на 100% ясно, где переменная mHandler присвоена new Handler(). Чтобы быть понятным, в моем коде это должно быть поле private на самом class. Вам также потребуется некоторая обработка ошибок в вашем методе authenticate(), чтобы отправить сообщение о закрытии диалогового окна, если вы обнаружите ошибку.

...