Page 1 of 1
Reusing sfsClient between Activities
Posted: 13 Oct 2011, 04:13
by sylhouette
What is the best approach for using the sfsClient in Android for multiple activites? Should I reuse them? Or should I re-init the sfsClient for each activity?
For example, I have activity A, activity B, activity C.
In activity A, I have an instance of sfsClient that handles the login process, etc.
After logging in from activity A, I log the user in to the "general zone" (in activity B). On click from activity B, I want the user to move to the game zone, therefore I disconnect-reconnect to move the user to the game zone.
In activity C, should I reuse the sfsClient from activity A? Because in activity B, I reuse the sfsClient from activity A to disconnect-reconnect. However, if I reuse the sfsClient from activity A, does that mean I have to define all the dispatch() for activtiy C in activity A? If I re-init, does that mean I have reconnect the user again so that the newly init smartFox can handle the dispatch() in activity C?
One thing I've noticed though, each time I call finish(), I would get disconnected from the server, so I have to put the activities to the stack.
Code: Select all
Intent mainMenuIntent = new Intent(getApplicationContext(), MainMenuActivity.class);
startActivity(mainMenuIntent);
// I cannot call finish here, because I would get disconnected. (the login session destroyed will be destroyed and I would be disconnected)
Sorry for the newbie question. I'm still quite novice and will love to learn more

Thank you very much for the help.
Posted: 17 Oct 2011, 13:57
by mmilen
I need the same thing, and the solution is to have the sfsClient object as part of the global Application object. However the sfsClient can not be inited in the Application object, as it fails to find paths to some non public java API classes like sun.misc.BASE64Encoder. My guess is Android loads different set of classpaths when an activity is created and loaded..
Posted: 17 Oct 2011, 15:35
by stix
To answer your question specifically, you should re-use the client across activities. Each activity will need to have a dispatch method defined to handle any events listened to in that particular activity. So, if activity C listens for SFSEvent.EXTENSION_RESPONSE but activity A does not, then activity C's dispatch method will be of the form:
Code: Select all
@Override
public void dispatch(final BaseEvent event) throws SFSException
{
if (event.getType().equalsIgnoreCase(SFSEvent.EXTENSION_RESPONSE))
{
//...
}
}
The dispatch method in activity A will not handle an extension response event.
Posted: 19 Oct 2011, 14:54
by sylhouette
@mmilen: I haven't tried that though, it would be very interesting if I can do that, so that I can finish() all the unused activities in the stack

Great idea. I'll google around.
@stix: I've tried that, and it failed. I still have to place dispatch() in the activity where I inited the smartfox client. I'll dig further. Anyway, thanks

Posted: 19 Oct 2011, 15:01
by mmilen
Where you able to init the sfsClient in the Application object?
Posted: 19 Oct 2011, 15:44
by sylhouette
Code: Select all
public class SfsClient extends Application {
private SmartFox sfsClient = new SmartFox(true);
public SmartFox getSfsClient() {
return sfsClient;
}
public void setSfsClient(SmartFox sfsClient) {
this.sfsClient = sfsClient;
}
}
this is my application code. Is this enough? I tried to call this from my activity through
Code: Select all
sfsClient = ((SfsClient) getApplicationContext()).getSfsClient();
and attaching all the event listeners I need afterwards. It works, but still, I cannot safely call finish() to switch from this activity to another activity. I still get disconnected (my session is destroyed). I wonder is there any way to safely call finish() and switch to another activity while maintaining my session throughout the other activities.. ~.~
Posted: 19 Oct 2011, 16:31
by mmilen
Code: Select all
sfsClient = ((SfsClient) getApplicationContext()).getSfsClient();
When I try the code above in my Activity I get Cannot make static reference to the non static method.
if I make the getSfsClient() and sfsClient static , I get the extension path error mentioned in my previous post.
Posted: 19 Oct 2011, 19:57
by mmilen
I did some more digging and looks like sfsClient needs to be abstracted into a service, rather that an application. Android promises to keep a service running if there is enough resources.
Posted: 20 Oct 2011, 02:30
by sylhouette
Hmm..I'll try that..I'll try posting my code here after I succeed..please let me know if you have any success >,< thanks

Posted: 20 Oct 2011, 02:40
by mmilen
Here is what I came up with. A service wrapper where my activities do bind (for direct access to service methods) and register as broadcast listeners (to receive notifications). I still have to figure out a way to nicely pass SFSObjects via Intent interface. The example below connects, when I press a button in the main activity and bind it to the service (not the best place to do all that).
Any ideas of any efficient way to move BaseEvent to the service listeners via Intent or any other mechanism would be great.
Here is my code
Code: Select all
public class NetworkProtocol extends Service implements IEventListener{
//these are ID of various request that can be sent the NetworkProtocol to action
public static final int APP_DELEGATE=1;
private SmartFox sfsClient=new SmartFox(true);
//Login properties
private String username=null;
private String password=null;
public class NP_Binder extends Binder implements IBinder {
public NetworkProtocol getService() {
return NetworkProtocol.this;
}
}
// This is the object that receives interactions from clients. See
// RemoteService for a more complete example.
private IBinder mBinder=null;
@Override
public IBinder onBind(Intent intent) {
switch (intent.getIntExtra("sender", 0)){
case APP_DELEGATE: {
if (!sfsClient.isConnected()) this.connectToServer("some.server.host", 9933);
Toast.makeText(this, "Main Activity binded...", Toast.LENGTH_LONG).show();
break;
}
default: break;
}
if (mBinder==null) mBinder = new NP_Binder();
return mBinder;
}
/** iBRIDGEBARON protocol methods
*
*/
/** Connect to server
*
*/
/** END iBRIDGEBARON protocol methods
*
*/
@Override
public void onCreate() {
super.onCreate();
// mBinder = new NP_Binder();
sfsClient = new SmartFox(true);
// Add event handlers
sfsClient.addEventListener(SFSEvent.CONNECTION, this);
sfsClient.addEventListener(SFSEvent.CONNECTION_LOST, this);
sfsClient.addEventListener(SFSEvent.LOGIN, this);
sfsClient.addEventListener(SFSEvent.ROOM_JOIN, this);
sfsClient.addEventListener(SFSEvent.USER_ENTER_ROOM, this);
sfsClient.addEventListener(SFSEvent.USER_EXIT_ROOM, this);
sfsClient.addEventListener(SFSEvent.PUBLIC_MESSAGE, this);
Toast.makeText(this, "Service created...", Toast.LENGTH_LONG).show();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// super.onStartCommand(intent,flags, startId);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service destroyed...", Toast.LENGTH_LONG).show();
}
@Override
public void dispatch(final BaseEvent event) throws SFSException
{
Log.v("dispatch", event.getType());
if(event.getType().equalsIgnoreCase(SFSEvent.CONNECTION))
{
//if the connections is successful login dialog is shown
if(event.getArguments().get("success").equals(true))
{
sendBroadcast(new Intent(event.getType()));
}
//otherwise error message is shown
else
{
}
}
//When the connection is lost
//the UI is disabled and message is shown
else if(event.getType().equalsIgnoreCase(SFSEvent.CONNECTION_LOST))
{
}
else if(event.getType().equalsIgnoreCase(SFSEvent.LOGIN))
{
//safe the user/pass for other login requests
this.username="";
this.password="";
// Join The Lobby room
sendBroadcast(new Intent(event.getType()));
}
//if the login is not successful then error message and
//the login dialog are shown until it's successful
else if(event.getType().equalsIgnoreCase(SFSEvent.LOGIN_ERROR))
{
sendBroadcast(new Intent(SFSEvent.CONNECTION));
}
//When the user joins new room then a message is added to
//the chat history and the UI is enabled
else if(event.getType().equalsIgnoreCase(SFSEvent.ROOM_JOIN))
{
Room room = (Room)event.getArguments().get("room");
for(User user : room.getUserList()) {
// mUsers.add(user.getName());
}
}
//When a user enter the room the user list is updated
else if(event.getType().equals(SFSEvent.USER_ENTER_ROOM))
{
User user = (User)event.getArguments().get("user");
}
//When a user leave the room the user list is updated
else if(event.getType().equals(SFSEvent.USER_EXIT_ROOM))
{
User user = (User)event.getArguments().get("user");
}
//When public message is received it's added to the chat history
else if(event.getType().equals(SFSEvent.PUBLIC_MESSAGE))
{
User sender = (User)event.getArguments().get("sender");
String msg = event.getArguments().get("message").toString();
}
}
/** private SmartFox methods
*
*/
/**
* Connects to SmartFoxServer instance.
*
* @param ip the server IP.
* @param port the server port.
*/
private void connectToServer(final String ip, final int port) {
this.sfsClient.connect(ip, port);
}
}
This is the activity code.
Code: Select all
public class BridgeBaronActivity extends Activity{
/** Called when the activity is first created. */
private NetworkProtocol mService;
private Boolean isLoggedIn=false;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. Because we have bound to a explicit
// service that we know is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
@SuppressWarnings("unused")
String tempstr=className.toShortString();
NetworkProtocol.NP_Binder tempBinder=((NetworkProtocol.NP_Binder) service);
mService = tempBinder.getService();
// Tell the user about this for our demo.
Toast.makeText(getApplicationContext(), "Binder call back ...",Toast.LENGTH_LONG).show();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// Because it is running in our same process, we should never
// see this happen.
mService = null;
Toast.makeText(getApplicationContext(), "Disconnected from service ...",
Toast.LENGTH_SHORT).show();
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
public void onStop() {
super.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onRestart() {
super.onRestart();
}
@Override
public void onResume() {
super.onResume();
// startService(npIntent);
// registerReceiver(broadcastReceiver, new IntentFilter(NetworkProtocol.BROADCAST_ACTION));
}
@Override
public void onPause() {
super.onPause();
// unregisterReceiver(broadcastReceiver);
// stopService(npIntent);
}
public void bActionOnlineHelp(View view) {
/* Show table after good login
Intent myIntent = new Intent(view.getContext(), BridgeTable.class);
startActivity(myIntent);
*/
Intent npIntent=new Intent(getApplicationContext(), NetworkProtocol.class);
npIntent.putExtra("sender", NetworkProtocol.APP_DELEGATE);
startService(npIntent);
bindService(npIntent, mConnection, Context.CONTEXT_IGNORE_SECURITY);
registerReceiver(timelToLoginReceiver, new IntentFilter(SFSEvent.CONNECTION));
registerReceiver(timelToLoginReceiver, new IntentFilter(SFSEvent.LOGIN_ERROR));
/* WebView webview = new WebView(this);
setContentView(webview);
webview.loadUrl("http://www.greatgameproducts.com/ibridgebaron/help.cfm");
*/
}
private BroadcastReceiver timelToLoginReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Intent myIntent = new Intent(getApplicationContext(), LoginBox.class);
startActivity(myIntent);
Toast.makeText(getApplicationContext(), "Time to login ...", Toast.LENGTH_LONG).show();
}
};
}
[/code]
Posted: 20 Oct 2011, 04:04
by sylhouette
I found out something interesting..can this help? I am still looking at it though
http://www.eigo.co.uk/Managing-State-in ... ivity.aspx
Posted: 20 Oct 2011, 15:01
by ThomasLund
I'll fix the Base64 stuff in the next release. Just FYI
/Thomas
Posted: 20 Oct 2011, 15:09
by sylhouette
Here's my successful approach:
- I put the instance of SmartFox client into a class that extends Application and specify that in AndroidManifest.xml, in the <application android:name="myClass">
I call the instance of sfsClient like this:
Code: Select all
sfsClient = ((SfsClient) getApplicationContext()).getSfsClient();
I have to remove all event listeners onPause() of each activity.
I have to re-attach event listeners each onCreate() of each activity, so that the events will properly dispatched to the current activity you are in.
The drawback is that we cannot call sfsClient.disconnect() in onDestroy(). Therefore, I have to specify in the zone configurator the idle time for users is 15 minutes, otherwise, they will be disconnected.
I have successfully implemented this approach and it works. If anyone is able to come up with a better approach, please let me know

Thank you

Re: Reusing sfsClient between Activities
Posted: 18 Aug 2021, 16:39
by mihi
Anyone found useful solution?
Re: Reusing sfsClient between Activities
Posted: 19 Aug 2021, 07:28
by Lapo
Hi,
this is a 10 year old post, so it would be best to post a new topic.
In any case, generally speaking an instance of the SmartFox client is valid until disconnection, then you need to create a new instance.
Cheers