0

すべてのクライアント/サーバー通信を処理するリモート サービスを作成しました。同じ通信ソケットを使用する分離されたアプリケーションはほとんどなく、アプリケーション間でソケットを「共有」する他の方法がないため、サービスを使用します(私の知る限り)。

このサービスはうまく機能し、ソケット接続を開始して int/String を送信できますが、readString() のような入力として使用することはできません。

アクティビティがサービスからの応答を待たないために問題が発生していると思います。サービスの readString メソッドのすべての部分でカスタム文字列を返しながらテストしました。

そしてコードのために...

接続リモート サービス:

public class ConnectionRemoteService extends Service {

private String deviceID;
private ConnectionThread ct;

@Override
public void onCreate() {
    super.onCreate();
    //Toast.makeText(this, "Service On.", Toast.LENGTH_LONG).show();

}

@Override
public void onDestroy() {
    //Toast.makeText(this, "Service Off.", Toast.LENGTH_LONG).show();
    if(ct != null)
        ct.close();
}

@Override
public IBinder onBind(Intent intent) {
    return myRemoteServiceStub;
}   

private ConnectionInterface.Stub myRemoteServiceStub = new ConnectionInterface.Stub() {
    public void startConnection(){
        WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
        deviceID = wm.getConnectionInfo().getMacAddress();
        ct = new ConnectionThread(deviceID);
        ct.start();
    }

    public void closeConnection(){
        if(ct != null)
            ct.close();
    }

    public void writeInt(int i) throws RemoteException {
        if(ct != null)
            ct.writeInt(i);
    }

    public int readInt() throws RemoteException {
        if(ct != null)
            return ct.readInt();
        return 0;
    }

    public void writeString(String st) throws RemoteException {
        if(ct != null)
            ct.writeString(st);
    }

    public String readString() throws RemoteException {
        if(ct != null)
            return ct.readString();
        return null;
    }

    public String deviceID() throws RemoteException {
        return deviceID;
    }

    public boolean isConnected() throws RemoteException {
        return ct.isConnected();
    }

};

}

説明:

ご覧のとおり、「空の」サービスのみを開始し、アプリケーションがそれにバインドするのを待ちます。バインド後、ソケットなどを処理する ConnectionThread を作成します...すべてのメソッドは、ソケットを介して入力\出力のスレッド メソッドを呼び出します。

接続スレッド:

public class ConnectionThread extends Thread {

private static final int SERVERPORT = 7777;
private static final String SERVERADDRESS = "192.168.1.106";

private String deviceID;
private Socket socket;
private DataInputStream in;
private DataOutputStream out;
private ObjectInputStream inObj;
private ObjectOutputStream outObj;
private boolean isConnected = false;

PingPongThread ppt;

public ConnectionThread(String deviceID) {
    super();
    this.deviceID = deviceID;
}

@Override
public void run() {
    super.run();
    open();

}

void open(){
    try{
        socket = new Socket(SERVERADDRESS,SERVERPORT);
        out = new DataOutputStream(socket.getOutputStream());
        out.flush();
        in = new DataInputStream(socket.getInputStream());
        outObj = new ObjectOutputStream(out);
        outObj.flush();
        inObj = new ObjectInputStream(in);
        out.writeUTF(deviceID);
        isConnected = true;
        ppt = new PingPongThread(SERVERADDRESS, SERVERPORT);
        ppt.start();
    }
    catch(Exception  e){
        isConnected = false;
        System.err.println(e.getMessage());
    }
}

public void close(){
    try {
        if(ppt!=null){
            ppt.stopThread();
            ppt.notify();
        }
        if(in!=null)
            in.close();
        if(out!=null)
            out.close();
        if(socket!=null)
            socket.close();
    } 
    catch(Exception  e){
        System.err.println(e.getMessage());
    }
    isConnected = false;
    socket=null;

}

public void writeInt(int i){
    try {
        out.writeInt(i);
        out.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public int readInt(){
    try {

        int i = in.readInt();
        return i;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return 0;
}

public void writeString(String st){
    try {
        out.writeUTF(st);
        out.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public String readString(){
    String st = "";
    try {
        st = in.readUTF();
        return st;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return st;
}

public boolean isConnected(){
    return isConnected;
}

}

説明:

私のスレッドでは、ソケットを作成し、後で使用するすべての in/out オブジェクトを初期化します。(「PingPongThread」は無視してください。接続を確認するための単純なスレッドです。別のポートを使用するため、問題になることはありません...)他のすべての方法は非常に単純で、in/out オブジェクトを使用するだけです...

そして主な活動のために:

public class MainLauncherWindow extends Activity {
private ConnectionInterface myRemoteService;
private boolean isServiceBinded = false;
private OnClickListener onclicklistener;

final ServiceConnection conn = new ServiceConnection() {
    public void onServiceConnected(ComponentName name, IBinder service) {
        myRemoteService = ConnectionInterface.Stub.asInterface(service);
    }
    public void onServiceDisconnected(ComponentName name) {
        myRemoteService = null;
    }
};

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main_launcher_window);

    final Button connectButton = (Button)findViewById(R.id.Connect);
    final Button disconnectButton = (Button)findViewById(R.id.Disconnect);


    startService(new Intent(getApplicationContext(), ConnectionRemoteService.class));
    isServiceBinded = bindService(new Intent("com.mainlauncher.ConnectionRemoteService"),conn,Context.BIND_AUTO_CREATE);

    //Connect button
    onclicklistener = new OnClickListener(){
        public void onClick(View v) {
            try {
                if(isServiceBinded){
                    myRemoteService.startConnection();
                    connectButton.setEnabled(false);
                    disconnectButton.setEnabled(true);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    };
    connectButton.setOnClickListener(onclicklistener);

    //Disconnect button
    onclicklistener = new OnClickListener(){
        public void onClick(View v) {
            connectButton.setEnabled(true);
            disconnectButton.setEnabled(false);
            try {
                if(isServiceBinded)
                    myRemoteService.closeConnection();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    };
    disconnectButton.setOnClickListener(onclicklistener);


    //read test button
    final Button bt1 = (Button)findViewById(R.id.bt1);

    onclicklistener = new OnClickListener(){
        public void onClick(View v) {
            try {
                if(isServiceBinded){
                    myRemoteService.writeString("Testing");
                    Toast.makeText(v.getContext(), myRemoteService.readString(), Toast.LENGTH_LONG).show();
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    };
    bt1.setOnClickListener(onclicklistener);        
}




@Override
public void onBackPressed() {
    super.onBackPressed();
    if(isServiceBinded){
        unbindService(conn);
        stopService(new Intent(getApplicationContext(), ConnectionRemoteService.class));
        isServiceBinded = false;
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if(isServiceBinded){
        unbindService(conn);
        stopService(new Intent(getApplicationContext(), ConnectionRemoteService.class));
        isServiceBinded = false;
    }
}



}

私の主な活動では、接続\切断およびテストボタンのボタンを作成しました。テストボタンは「テスト中」文字列をサーバー側に送信します。サーバーは正常に動作し、「テスト」文字列を取得して、他の文字列をクライアントに返します。ただし、「トースト」メッセージは常に空白です。

  • サービスなしでサーバー側をテストしたところ、問題なく動作するので、心配する必要はありません。
  • 私は ConnectionThread でテストを行い、その readString メソッドからテスト文字列を返しましたが、うまくいきました。これは、スレッドがサービスを介してクライアント側に応答を返すことを意味します (すべてのチェーンがうまく機能します)。

私が今心に留めている唯一のことは、アクティビティがサービスから文字列が返されるのを決して待たず、それが問題の原因であるということです。

何か案は?

ありがとう、リオズ。

4

4 に答える 4

1

androidが提供するhandlerThreadクラスを利用する

Adnroid リンク : http://developer.android.com/reference/android/os/HandlerThread.html

チュートリアル リンク :

  1. http://stephendnicholas.com/archives/42

これを使用して、ハンドラー用の新しいスレッドを作成し、それをサービスに渡すことができます。したがって、サービスによって送信されたすべてのメッセージは新しいスレッドで処理され、アクティビティで待機/通知を使用できます。

元:

/* This is running in hadlerThread */

static class IncomingHandler extends Handler 
{

    public IncomingHandler(Looper looper)
    {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {

        switch (msg.what) {
        case DATA:
            //Your code
            synchronized (sync) {
                if(gotReply == false){
                    gotReply = true;
                    sync.notify();
                }
            }
            break;
        default:
            super.handleMessage(msg);
        }
    }
}

/* This is running in main thread */

void foo(){
    synchronized (sync) {
        gotReply = false;
    }
    Message msg = Message.obtain(null, DATA);       
    sendMessage(msg);

    synchronized (sync) {
        if(gotReply == false){
            try {
                sync.wait();
            } catch (InterruptedException e) {

                e.printStackTrace();
            }
        }
    }
}
于 2013-07-08T10:38:10.690 に答える
1

やっと手に入れました。AsyncTask で "Ercan" 方式を使用しました。

最終的な解決策は、私のアクティビティ内に実装することでした(私のスレッド/サービスではありません)。今ではうまく機能します。ご協力いただきありがとうございます。

最終的なコード:

class ReadString extends AsyncTask <String,Object,String>{
    @Override
    protected String doInBackground(String... params) {
        try {
            if(isServiceBinded){
                String st = myRemoteService.readString();
                return st;
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return "Nothing";
    }
}

class ReadInt extends AsyncTask <Integer,Object,Integer>{
    @Override
    protected Integer doInBackground(Integer... params) {
        try {
            if(isServiceBinded){
                int i = myRemoteService.readInt();
                return i;
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return 0;
    }
}
于 2012-11-12T19:18:59.613 に答える
0

スレッドの代わりに AsyncTask を使用するか、スレッドを AsyncTask でラップしてみてください (可能な場合は試していません)。

そうすることで、次のようにアプリに結果を待たせることができます。

 class YourClass  extends AsyncTask <Bla,Object,Bla>{

 doInBackGround(Bla blah){
  //do the stuff here
  return result;
 }


 onPostCalculate(Object result){

  // use the result.
  }
}
于 2012-11-11T22:32:53.383 に答える
0

私の投稿をチェックしてください:

通知の受信時にアラートまたはビューを表示します。

これにより、アクティビティが BroadcastReciever を使用してイベントをリッスンする方法が提供されます。ユーザーが他のことをするのを待機ブロックしたい場合は、タイムアウト後またはインテントが受信されたときにキャンセルできる単純なモーダル ダイアログを表示することもできます。

于 2012-11-11T22:20:56.607 に答える