2012-11-11 3 views
0

나는 모든 클라이언트 - 서버 통신을 돌보는 원격 서비스를 만들었습니다. 동일한 통신 소켓을 사용할 별도의 응용 프로그램이 거의없고 응용 프로그램간에 소켓을 "공유"할 수있는 방법이 없기 때문에 서비스를 사용합니다 (알고있는 한).안드로이드 액티비티가 서비스 응답을 기다림

서비스는 훌륭하게 작동하며 소켓 연결을 시작하고이를 통해 int/String을 보낼 수 있지만 readString()과 같은 입력으로 사용할 수는 없습니다.

나는 활동이 서비스의 응답을 기다리지 않기 때문에 문제가 발생한다고 생각합니다. 내 서비스에서 내 readString 메서드의 모든 부분에서 사용자 지정 문자열을 반환하는 동안 테스트했습니다.

및 코드에 대한

...

ConnectionRemoteService :

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를 만듭니다. 모든 메서드는 소켓을 통해 input \ output 스레드 메서드를 호출합니다.

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; 
} 

}

설명 :

내 스레드에서, 내가 소켓을 만들고 나중에 사용하기 위해 인/아웃 개체의 모든를 초기화합니다. ("PingPongThread"를 무시하십시오. 연결을 확인하는 간단한 스레드 일 뿐이므로 다른 포트를 사용하므로 문제가 될 수 없습니다 ...) 다른 모든 메소드는 입력/출력 객체를 사용하는 것만으로 매우 간단합니다. ..

및 주요 활동에 대한

:

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; 
    } 
} 



} 

내 주요 활동에서 내가 연결 \ 차단 및 테스트 버튼 버튼을 만들었습니다. 테스트 버튼은 서버 측에 "Testing"문자열을 보냅니다. 서버가 제대로 작동하고 "Testing"String을 가져 와서 다른 문자열을 클라이언트에 반환합니다. "Toast"msg는 항상 비어 있습니다.

  • 나는 서비스없이 서버 측을 테스트 했으므로 잘 작동하므로 걱정할 필요가 없습니다.
  • 나는 ConnectionThread를 사용하여 테스트 문자열을 반환하고 테스트 문자열을 readString 메서드에서 반환했으며 제대로 작동했기 때문에 스레드가 클라이언트 측에 서비스를 통해 응답을 반환합니다 (모든 체인이 잘 작동 함).

내가 지금 염두에 두어야 할 것은 서비스에서 문자열을 기다리지 않고 문제가 발생한다는 것입니다.

어떤 아이디어가 있습니까?

감사합니다. 리오즈.

답변

0

대신 스레드의 AsyncTask를를 사용하여 시도하거나 앱이 같이 당신의 결과를 기다릴 수 있음을 수행하여 (가능한 경우 내가 그것을 시도 didnt한다)는 AsyncTask를에

을 스레드 포장 :

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

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


onPostCalculate(Object result){ 

    // use the result. 
    } 
} 
+0

"extends AsyncTask"는 내 수업에서 사용할 수 없다. 첫 번째 서비스 확장, 두 번째 확장 스레드 ... AsyncTask를 작동시키는 다른 아이디어는 없나요? – HFDO5

+0

글쎄, 아마도 내부 클래스를 만드는 것이 트릭을 할 수 있습니다. 내부 클래스 doInBackGround()에서 작업을 이동하고 실행하십시오. 또는 스레드를 AsyncTask로 변경하십시오. 스레드와 같습니다. – Ercan

+0

많은 테스트를 마친 후에 제대로 작동 할 수있는 방법을 찾을 수 없습니다. 도움이 될만한 아이디어가 있습니까? – HFDO5

0

체크 아웃 내 게시물 :

Display an alert or a view on receiving a notification합니다.

이것은 BroadcastReciever를 사용하여 이벤트를 수신 대기하는 활동을 제공합니다. wait를 사용하여 사용자가 다른 작업을 할 수 없게하려는 경우, 간단한 모달 대화 상자를 불러올 수 있습니다.이 대화 상자는 제한 시간 이후 또는 의도가 수신 될 때 취소 될 수 있습니다.

+0

은 내가 설명하는 문제가 아니라, 내가 아니라 사용자를 차단하려면 ... 문제는 활동이 내 서비스 (사용자와 관련된 일에서 문자열 응답을 "대기"하지 않는 것이있다). 그리고 나는 활동을 "차단"하거나 BroadcastReciever를 사용할 아무 이유도 없다. – HFDO5

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; 
    } 
} 
안드로이드

Adnroid 링크에서 제공

1

사용 handlerThread 클래스 : http://developer.android.com/reference/android/os/HandlerThread.html

튜토리얼 링크 :

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

이 핸들러를 사용하면 핸들러 용 새 스레드를 만들어 서비스에 전달할 수 있습니다. 따라서 서비스에 의해 보내지는 모든 메시지는 새로운 쓰레드에서 처리 될 것이고 당신은 활동에서 wait/notify를 사용할 수 있습니다.

예 :

/* 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(); 
      } 
     } 
    } 
} 
관련 문제