[英]making android activity wait for reply from service
我創建了一個遠程服務,負責所有客戶端 - 服務器通信。 我使用服務,因為很少有分離的應用程序將使用相同的通信套接字,並且沒有其他方法可以在應用程序之間“共享”套接字(據我所知)。
服務很好,可以啟動套接字連接並通過它發送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 ...所有方法都通過套接字調用輸入\\輸出的線程方法。
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;
}
}
}
在我的主要活動中,我創建了connect \\ disconnect和test按鈕的按鈕。 測試按鈕將“測試”字符串發送到服務器端。 服務器工作正常,獲取“測試”字符串並將其他字符串返回給客戶端。 但“Toast”消息總是空白。
我現在唯一想到的是,活動永遠不會等待來自服務的字符串,這就是造成問題的原因。
有任何想法嗎?
謝謝,Lioz。
終於明白了。 我在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;
}
}
使用android提供的handlerThread類
Adnroid鏈接: http : //developer.android.com/reference/android/os/HandlerThread.html
教程鏈接:
使用這個可以為處理程序創建一個新線程並將其傳遞給服務。 因此,服務發送的所有消息都將在新線程中處理,您可以在活動中使用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();
}
}
}
}
看看我的帖子:
這將為您提供一種使用BroadcastReciever監聽事件的方法。 如果你想讓等待阻止用戶做其他事情,你也可以提出一個簡單的模態對話框,可以在超時或收到意圖后取消。
嘗試使用AsyncTask而不是線程或將您的線程包裝在AsyncTask中(如果有可能我沒有嘗試過)
通過這樣做,你可以讓你的應用程序等待你的結果:
class YourClass extends AsyncTask <Bla,Object,Bla>{
doInBackGround(Bla blah){
//do the stuff here
return result;
}
onPostCalculate(Object result){
// use the result.
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.