3

ProgressDialog with Threadsの質問が何度も行われていることは知っていますが、私のプロジェクトではどのソリューションも機能していないようです。基本的に私がしたいのはこれです:1)ユーザーがボタンをクリックするとアクティビティがサーバーに認証リクエストを送信します2)これが行われている間ProgressDialogが表示されます3)応答が来たらProgressDialogを却下したいと思いますアクティビティによって読み取られ、解釈されるリターンオブジェクト

Iの場合:1)応答でアプリケーションフィールドを更新するようにスレッドを設定すると、フィールドにアクセスするときに次のメソッド(スレッドの外側)がNPEをスローします2)スレッドに次のメソッドを含めると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

4 に答える 4

8

あなたはより良い使用法です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アプリについて説明していますが、同じ概念をさまざまな種類のアプリに適用できます):AndroidRESTクライアントアプリケーションの開発

于 2011-01-23T20:25:08.710 に答える
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を使用することをお勧めします(提案されているように)。

于 2011-01-23T20:27:13.933 に答える
1

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あなたのコードから、変数がどこに割り当てられているかは100%明確ではありませんnew Handler()。明確にするために、私のコードでは、これはそれ自体のprivateフィールドである必要がありclassます。authenticate()エラーが発生した場合にダイアログを閉じるためのメッセージを送信するには、メソッドでエラー処理を行う必要もあります。

于 2011-01-23T21:31:40.337 に答える
1

他の人がすでに書いたように、AsyncTaskは先に進む方法です。

ただし、AsyncTaskとThreadsには、UI要素に関するいくつかの落とし穴があります。

電話の向きを変更し、Manifest.xmlでアクティビティを設定しなかった場合android:configChanges="keyboardHidden|orientation"(つまり、onConfigChangeを自分で処理する必要がある場合)、向きを変更すると、ActivityとContentViewが破棄および再作成され、表示されているウィンドウからProgressDialogが切断されます(古いものに接続されています)。AndroidはスレッドやAsyncTaskを強制終了しません。また、アクティビティが破壊されても殺されません。これらのバックグラウンドタスクは、完了するまで続行されます。

以前に作成したProgressDialogをdismiss()しようとすると、ContentViewが破棄された後、ウィンドウの一部ではなくなったため、例外がスローされます。切り離された(非同期の)作業を行う状況で、LOTを試して/キャッチします。onPostExecute()が再度呼び出されたときに、依存している可能性のあるものはすべて消えるか、別のものに置き換えられた可能性があります。最終的には、アクティビティの配列で開始するすべてのASyncTaskを登録することを検討し、Activity.onDestroy()でそれらをcancel()してみてください。

于 2011-01-23T23:10:06.507 に答える