すべてのクライアント/サーバー通信を処理するリモート サービスを作成しました。同じ通信ソケットを使用する分離されたアプリケーションはほとんどなく、アプリケーション間でソケットを「共有」する他の方法がないため、サービスを使用します(私の知る限り)。
このサービスはうまく機能し、ソケット接続を開始して 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 メソッドからテスト文字列を返しましたが、うまくいきました。これは、スレッドがサービスを介してクライアント側に応答を返すことを意味します (すべてのチェーンがうまく機能します)。
私が今心に留めている唯一のことは、アクティビティがサービスから文字列が返されるのを決して待たず、それが問題の原因であるということです。
何か案は?
ありがとう、リオズ。