进行Android活动等待服务回复



我创建了一个远程服务,该服务照顾所有客户服务器通信。我之所以使用服务,是因为很少有分离的应用程序会使用相同的通信套接字,并且没有其他方法可以在应用程序之间"共享"插座(据我所知)。

服务效果很好,可以启动插座连接并通过它发送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();
    }
};

}

说明:

您可以看到,我只启动"空"服务并等待应用程序绑定。绑定后,我创建了连接线程,以照顾套接字等...所有方法都调用线程方法,以通过套接字输入输出。

连接线:

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",这只是一个简单的检查连接的线程。它使用不同的端口,因此不可能是问题...)所有其他方法都非常简单,只需使用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;
    }
}

}

在我的主要活动中,我为连接断开连接和测试按钮创建了按钮。测试按钮将"测试"字符串发送到服务器端。服务器正常工作,获取"测试"字符串,然后将其他字符串返回到客户端。但是"吐司"味精总是空白的。

  • 我在没有服务的情况下测试了服务器端,而且效果很好,因此不用担心。
  • 我进行了一个带有连接线程的测试,从其ReadString方法返回测试字符串,并且效果很好,意味着线程通过服务返回答案到客户端(所有链条都很好)。

我现在唯一想到的是,该活动永远不会等待服务中的弦,这就是导致问题的原因。

有什么想法?

谢谢lioz。

终于得到了它。我使用了" 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

提供的处理程序类别

adnroid链接:http://developer.android.com/reference/android/android/os/handlerthread.html

教程链接:

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

使用此操作可以为处理程序创建一个新线程并将其传递给服务。因此,服务发送的所有消息都将在新线程中处理,您可以在活动中使用Wait/Notify。

ex:

/* 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();
            }
        }
    }
}

尝试使用asynctask代替线程或将线程包装在异步(如果可能的话,我没有尝试过)

这样做可以使您的应用程序等待这样的结果:

 class YourClass  extends AsyncTask <Bla,Object,Bla>{
 doInBackGround(Bla blah){
  //do the stuff here
  return result;
 }

 onPostCalculate(Object result){
  // use the result.
  }
}

查看我的帖子:

显示收到通知的警报或视图。

这将为您提供一种活动的方式,可以使用广播公司聆听活动。如果您想让等待块用户执行其他操作,也可以提出一个简单的模态对话框,该对话可以在超时或收到意图后取消。

相关内容

最新更新