0

これはかなり一般的な問題だと思いますが、それでも満足のいく答えが見つからなかったので、自問してみます。

これはコードの一部です:

// this is insine OnClickView
TextView status = (TextView) findViewById(R.id.status);
status.setText("Trying to connect to the server...");
try {
    // this opens a socket and send a login request to the server.
    int result = CommunicationManager.login(String email, String password);
    switch (result) {
    case CommunicationManager.SUCCESS:
        // login ok, go on with next screen
        break;
    case CommunicationManager.WRONG_EMAIL:
        status.setTextColor(Color.RED);
        status.setText("Wrong Email!");
        break;
    case CommunicationManager.WRONG_PASSWORD:
        status.setTextColor(Color.RED);
        status.setText("Wrong Password!");
        break;
    }
} catch (CommunicationException e) {
    status.setTextColor(Color.RED);
    status.setText("Unable to estabilish a connection!");
} catch (ProtocolException e) {
    status.setTextColor(Color.RED);
    status.setText("Protocol error!");
}

これが私が達成したいことです:

  1. ユーザーが [送信] ボタンをクリックします。
  2. status textview に「サーバーに接続しようとしています...」と表示されます。
  3. UI は通信が終了するまで「待機」します。
  4. status textview はそれに応じて結果を表示します。

しかし、代わりに、ユーザーが [送信] ボタンをクリックすると、通信が完了するまでUI がフリーズします(奇妙なことに、ステータス テキストが表示される前に) (不明なホストに接続しようとしました)。簡単な解決策はソケットのタイムアウトを設定することですが、この種の解決策は好きではありません: UI がまだフリーズしており、どのタイムアウトを設定する必要がありますか?

私の最初の考えは明らかに Thread でしたが、ご覧のとおり、値を返す必要があります。スレッド環境では、スレッドが独立して非同期で実行されるため、これはあまり意味がありません。

したがって、私が必要としているのは、サービスが実行されるのを UI が待機することですが、フリーズすることはありません。ちなみに、戻り値を待つということは、UIタスクが終了するのを待たなければならないことを意味しているように思えます。

AsyncTask に遭遇しましたが、2 つの大きな欠点があります。

  1. UI との結びつきが強すぎるように思えます。
  2. 整数、文字列、およびブール値のパラメーターを使用してサービスを実行したい場合はどうすればよいですか? 延長する必要がありAsyncTask<Object, Void, Void>ますか?

どちらも非拡張性につながります。

目標を達成するために何ができますか? サービスへの別のリクエストは、まだ準備ができていない何かに対するリクエストになることに注意してください。そのため、数回 (たとえば 10 分) ごとにリクエストを自動的に繰り返す必要があります。したがって、おそらく で使用できるものが必要になるでしょうがTimerTask、そのサービスを実行するたびに UI に値を返す必要があります (ステータス テキストを更新して、何が起こっているかをユーザーに知らせることができます)。

4

3 に答える 3

6

これは、HTTP 呼び出しなどの外部通信を処理する場合の典型的な使用例です。

最善の方法は、AsyncTask を使用することです。AsyncTask に関する懸念事項に対する回答を提供するため。

UI との結びつきが強すぎるように思えます。

ここでは、優れたコード設計が役割を果たします。独自のコールバック メカニズムを記述して、密結合を取り除くことができます。例を以下に示します。

WS 呼び出しに必要なリクエストとレスポンスのバージョンを作成します。非常に単純なプリミティブ型または複雑な型のパラメーターにすることができます。

class Result{
    //Define more para.

}

class Request{
    //Deinf more para.
}

コールバック インターフェイスの下に記述します。

public interface MyCallBack {
     public void onComplete(Result result);}

AsyncTask を作成し、コンストラクターで Interface オブジェクトの上に取得すると、同じオブジェクトが Result オブジェクトを返すことができます。

    class LongRunningTask extends AsyncTask<Request, Integer, Long>{
    private MyCallBack callback;
    public LongRunningTask(MyCallBack callback) {
        super();
        this.callback = callback;
    }
    @Override
    protected Long doInBackground(Request... params) {
        // Perform your back ground task.
        return null;
    }
    @Override
    protected void onPostExecute(Long result) {
        super.onPostExecute(result);            
        callback.onComplete(new Result()); //Here result is dummy but in real it should be contructred from doInBackground() method
    }
}

インターフェイスを実装して asynctask を呼び出す最後の重要な部分です。わかりやすくするために、コードを再利用しようとしています。

public class MainActivity extends Activity implements MyCallBack{

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    TextView status = (TextView) findViewById(R.id.status);
    status.setText("Trying to connect to the server...");
}

private void onClick(){
    //Similer to CommunicationManager.login(String email, String password); in your code.
    LongRunningTask longRunningTask = new LongRunningTask(this);
    longRunningTask.execute(new Request());
}

@Override
public void onComplete(Result result) {     
    try {

        int result = result.getStatus 
        switch (result) {
        case CommunicationManager.SUCCESS:
            // login ok, go on with next screen
            break;
        case CommunicationManager.WRONG_EMAIL:
            status.setTextColor(Color.RED);
            status.setText("Wrong Email!");
            break;
        case CommunicationManager.WRONG_PASSWORD:
            status.setTextColor(Color.RED);
            status.setText("Wrong Password!");
            break;
        }
    } catch (CommunicationException e) {
        status.setTextColor(Color.RED);
        status.setText("Unable to estabilish a connection!");
    } catch (ProtocolException e) {
        status.setTextColor(Color.RED);
        status.setText("Protocol error!");
    }
}

整数、文字列、およびブール値のパラメーターを使用してサービスを実行したい場合はどうすればよいですか? AsyncTask を拡張する必要がありますか?

最初のパラメーターは、任意のユーザー定義のパラメーターです。複数のパラメータを渡す必要がある場合は、それらをエンティティの形式 (つまり、クラス) に入れます。また、AsyncTask ie - Communication URL のコンストラクターで初期構成パラメーターを渡すこともできます。

それが役立つことを願っています。

于 2013-02-17T11:36:47.480 に答える
0

マルチスレッドを使用し、すべての通信を別のスレッドで行う

于 2013-02-17T11:08:29.550 に答える
0

長時間実行される操作を行うには、ワーカー スレッドまたは AsyncTask を使用します。

さらに、Android Honeycomb から、UI スレッドでネットワーク操作を実行すると、システムが例外をスローします。

于 2013-02-17T11:42:09.200 に答える