I am working on chat application and using ejabberd saas edition as xmpp server for it. I am using smack library ver-4.2.3. To keep connection alive I am using ping manager. Here is the code I am using:
ReconnectionManager.getInstanceFor(AppController.mXmpptcpConnection).enableAutomaticReconnection();
ServerPingWithAlarmManager.onCreate(context);
ServerPingWithAlarmManager.getInstanceFor(AppController.mXmpptcpConnection).setEnabled(true);
ReconnectionManager.setEnabledPerDefault(true);
//int i = 1;
// PingManager.setDefaultPingInterval(i);
PingManager.getInstanceFor(AppController.mXmpptcpConnection).setPingInterval(300);
I am using sticky-service also for connection, but when I keep my application open (ideal-state) for 15-20 mins then the connection is lost, so I am using ping manger to resolve this issue.
Is there any other better way of doing it or ping manager is the only option?
Insted of pinging chat server constantly, you better to use ConnectionListener() in smack library. You need to use something like this:
XMPPTCPConnection connection;
// initialize your connection
// handle the connection
connection.addConnectionListener(new ConnectionListener() {
#Override
public void connected(XMPPConnection connection) {
}
#Override
public void authenticated(XMPPConnection connection, boolean resumed) {
}
#Override
public void connectionClosed() {
// when the connection is closed, try to reconnect to the server.
}
#Override
public void connectionClosedOnError(Exception e) {
// when the connection is closed, try to reconnect to the server.
}
#Override
public void reconnectionSuccessful() {
}
#Override
public void reconnectingIn(int seconds) {
}
#Override
public void reconnectionFailed(Exception e) {
// do something here, did you want to reconnect or send the error message?
}
});
Best way to keep the alive connection with XMPP server you should reconnect after every network change.
Like this:
public class NetworkStateChangeReceiver extends BroadcastReceiver {
private Context context;
private static NetworkStateChangeListener mListener;
#Override
public void onReceive(Context context, Intent intent) {
this.context = context;
try {
if (!ApplicationHelper.isInternetOn(context)) {
if (mListener != null) {
mListener.OnInternetStateOff();
}
return;
} else {
XMPPTCPConnection xmpptcpConnection = XmppConnectionHelper.getConnection();
if(!StringHelper.isNullOrEmpty(new SessionManager(context).getAuthenticationToken())) {
Intent XmppConnectionServicesIntent = new Intent(context, XmppConnectionServices.class);
context.stopService(XmppConnectionServicesIntent);
context.startService(XmppConnectionServicesIntent);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
//to initialize NetworkStateChangeListener because null pointer exception occurred
public static void setNetworkStateChangeListener(NetworkStateChangeListener listener) {
mListener = listener;
}
}
Yes, There is. Few points before the solution
Make your service STICKY, with a foreground notification as it would be necessary to work on or after Build.VERSION_CODES.O
This sticky service, you should start on every boot, via BOOT_COMPLETED intent action and starting this foreground service from receiver.
Yes, Now it is always there, Now you can always go for checking your connection
You can use google-volley for making connections and even you can communicate using it.
There is no good documentation on it, But i like it much, as it works flawlessly once added the dependency successfully.
Adding this dependency will take time as i said no good documentation..
For communication :
StringRequest stringRequest = new StringRequest(Request.Method.POST, "https://oniony-leg.000webhostapp.com/user_validation.php",
new Response.Listener<String>()
{
#Override
public void onResponse(String response)
{
serverKeyResponse = response;
// get full table entries from below toast and writedb LICENSETABLE
//Toast.makeText(getActivity(),response,Toast.LENGTH_LONG).show();
showKeyResponse();
// Log.d("XXXXXX XXXXX", "\n SUCCESS : "+serverKeyResponse);
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error)
{
serverKeyResponse = error.toString();
// show below toast in alert dialog and it happens on slow internet try again after few minutes
// on ok exit app
// Toast.makeText(getActivity(),error.toString(),Toast.LENGTH_LONG).show();
showKeyResponse();
//Log.d("YYYYYY YYYYYY", "\n FAILURE : "+serverKeyResponse);
}
})
{
#Override
protected Map<String,String> getParams()
{
Map<String,String> params = new HashMap<String, String>();
params.put("INPUT",LicenseKey.getText().toString());
params.put("USER", MainActivity.deviceid);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(getActivity());
requestQueue.add(stringRequest);
You just have to reply ECHO "SUCCESS" from server using a php ( or whatever server side language you like ). In response check for SUCCESS presence, any any other cases.., Use other KEYWORDS YOU LIKE. You can handle Server response errors too. Even you can communicate from android in request - response handshake. But you have to implement few handshake on your own.
I Hope, It helps...
Use the ReconnectionManager class as described here.
ReconnectionManager manager = ReconnectionManager.getInstanceFor(connection);
manager.enableAutomaticReconnection();
It will automatically re-connect when necessary.
Related
My Android application needs to do an initial http request on app start to fetch a config json file from a RESTful service. This request is done by Volley
As soon as the application gets the data, the MainActivity starts. I also defined some deeplinks, to open a WebView in my application with a given URI. The deeplinks have to be handled by the SplashActivity as the config needs to be loaded first by Volley. I don't know if this is the right way to handle this.
Maybe it would be an option to request the config in the Application class, so that the config is always available, no matter which Activity starts first?
This is the correct way.
In your Splash activity you should handle the incoming intent with your deeplinks, fire up your Volley request and only then you should move on with your logic.
BTW, in the meanwhile, you should show the user some loader/progress and handle failures of course.
If you are making an asynchronous call in the Application class, you can make the request with a callback and show the required activity.
public interface ConfigListener {
public void onConfigReceived(List<ofSomething> list, boolean error, String message);
}
private void requestConfig(){
final DownloadUsingVolley downloader = new DownloadUsingVolley(getActivity());
downloader.retrieveData(new ConfigListener() {
#Override
public void onConfigReceived(List<ofSomething> list, boolean error, String message) {
//Show your required activity here
}
});
}
private void retrieveData(String url, final ConfigListener configListener){
final JsonObjectRequest request = new JsonObjectRequest(url, null, new Response.Listener<JSONObject>(){
#Override
public void onResponse(JSONObject response) {
try {
//parse
configListener.onConfigReceived(result,false,null);
}catch (JSONException e){
configListener.onConfigReceived(0,true,e.getMessage());
}
}
},new Response.ErrorListener(){
#Override
public void onErrorResponse(VolleyError volleyError) {
configListener.onConfigReceived(0,true,volleyError.getMessage());
}
});
//adding request into the queue
ApplicationClass.getInstance().addToRequestQueue(request,"aTag");
}
I am trying to join a MultiUserChat using Smack on Android. Currently I can chat 1-on-1 perfectly fine, and I am connected to the server as I show online. I followed the examples provided here.
I have the following code to join a MultiUserChat (MUC).
final XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
.setUsernameAndPassword(user.getUsername(), user.getJabberPassword())
.setServiceName("app.buur.nu")
.setHost("app.buur.nu")
.setPort(5222)
.build();
AbstractXMPPConnection connection = new XMPPTCPConnection(config);
String room = "testroom";
MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
MultiUserChat muc = manager.getMultiUserChat(room + "#groups.app.buur.nu");
try {
muc.join(user.getUsername(), null, null, connection.getPacketReplyTimeout());
} catch (SmackException.NoResponseException e) {
e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
But this gives me
org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout. Timeout was 5000ms (~5s). Used filter: AndFilter: (FromMatchesFilter (full): testroom#groups.app.buur.nu/test, StanzaTypeFilter: org.jivesoftware.smack.packet.Presence).
I tried increasing the timeout to 10000 ms, but I still get a timeout. What could be wrong here? Creating 1-on-1 chats works fine and connection.isConnected()) returns True...
So it turns out that I get an error
<presence to="app.buur.nu/7c65be6" id="lgcSp-4" type="error"><x xmlns="http://jabber.org/protocol/muc"/><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="http://www.igniterealtime.org/projects/smack" ver="os2Kusj3WEOivn5n4iFr/ZEO8ls="/><error code="401" type="auth"><not-authorized xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error></presence>
Basically, the authentication is not completed when I am attempting to join the room. Can a listener be added to receive an update when the authentication has been completed? I saw https://www.igniterealtime.org/builds/smack/docs/latest/javadoc/org/jivesoftware/smack/SASLAuthentication.html#authenticate%28java.lang.String,%20javax.security.auth.callback.CallbackHandler%29 but implementing my own authentication mechanism seems a little overkill...
Isn't there a onAuthenticationCompletedListener or something?
It turns out there is no need to implement the SASLMechanism, you can do the following:
connection.addConnectionListener(new ConnectionListener() {
#Override
public void connected(XMPPConnection connection) {
}
#Override
public void authenticated(XMPPConnection connection, boolean resumed) {
joinMUCRooms();
}
#Override
public void connectionClosed() {
}
#Override
public void connectionClosedOnError(Exception e) {
}
#Override
public void reconnectionSuccessful() {
}
#Override
public void reconnectingIn(int seconds) {
}
#Override
public void reconnectionFailed(Exception e) {
}
});
The error no longer shows now, while keeping the code "fairly" clean.
Does the room exist? If not then you need to create it first, using create() and sending a instant form. You should also report to the openfire developers that the MUC error presence is missing the 'from' attribute.
I've searched all over but haven't found an answer to this.
In my Android application, the user can use the app offline, and some events generate http GET requests to my server. I am using Volley, and when the user is online the requests work properly, but offline they fail immediately and are removed from the request queue.
I wanted Volley to store these requests, and try again when the server is accessible, or at least keep trying. Is this behaviour possible?
Here's how I'm doing things:
StringRequest request = new StringRequest(Request.Method.GET, url, listener, listener);
request.setRetryPolicy(new DefaultRetryPolicy(8000, 2, 1.5f));
postToDefaultQueue(request);
private void postToDefaultQueue (StringRequest request) {
if (sQueue == null) {
sQueue = Volley.newRequestQueue(mContext.get());
}
sQueue.add(request);
}
Thanks so much, any help appreciated
Edit
So I managed to make the request go back to the queue after it fails. The code is below:
private class DummyListener implements Response.Listener<String>, Response.ErrorListener {
String mUrl;
public DummyListener (String url){
mUrl = url;
}
#Override
public void onErrorResponse(final VolleyError error) {
new Timer().schedule(new TimerTask() {
#Override
public void run() {
Log.v(DummyListener.class.getSimpleName(), "ErrorResponse", error);
offlineStringGetRequest(mUrl);
}
}, 5000);
}
#Override
public void onResponse(String response) {
Log.d(DummyListener.class.getSimpleName(), "Response: " + response);
}
}
The problem that remains is that if I kill the app, the queue gets destroyed, and the request is never made.
Edit2
Noticed some people liked this question. I ended up using Path (https://github.com/path/android-priority-jobqueue) with some modifications for the job. It worked perfectly. Just wish Volley had a native way for doing this
Since I found no way to do this with Volley, I ended up using Path
And it worked wonders
I am developing a communication's system between an Android App and a Server.
I am using Retrofit API for the Android's communication with the Server.
When I do a GET (from Android side) to get info from the Server, I use a CallBackTask method like this:
public void testGet()
{
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(UserApi.SERVER)
.build();
final UserApi svc = restAdapter.create(UserApi.class);
if (svc != null) {
CallableTask.invoke(new Callable<Test>() {
#Override
public Test call() throws Exception {
Test g = svc.getTest();
System.out.println("getVdd() = "+g.getVdd()+"+ getResp() = "+g.getResp());
return g;
}
}, new TaskCallback<Test>() {
#Override
public void success(Test result) {
Intent i = new Intent(getApplicationContext(),SplashRapidoActivity.class);
startActivity(i);
}
#Override
public void error(Exception e) {
Toast.makeText(
getApplicationContext(),
"Unable to connect, please try again.",
Toast.LENGTH_SHORT).show();
}
});
}
}
Where the Test.class is a POJO class with variables and his getters and setters:
public class Test {
String vdd;
String resp;
public Test()
{
}
public void setVdd(String vdd) {
this.vdd = vdd;
}
public String getVdd() {
return vdd;
}
public void setResp(String resp)
{}
public String getResp()
{
return resp;
}
}
So, my question is, which is the best ERROR RESPONSE i could send from the server if there aren't valid values for the Test.class in the server?
Actually there is no "the best error response". It depends on your requirements. But there is widely used architecture called REST and Retrofit was designed in according with REST interaction. REST basically is just a set of rules which clients and servers understand without any documentation.
So if you want to retrieve(GET) some object/data from server by REST you can either receive it with status 200 or receive status 404 with appropriate description of error(or without it) inside body.
Here some more to read.
The best error response is one that make sense to you as a developer. I wouldn't mess with the default HTTP status/error codes. Instead I would send a specific response from the server. For example, keep the HTTP response code at 200 but in the data you send to the app set it to "ERROR: no values." or whatever you prefer. Then, in your Android app, check the response to see if it contains values or an error. Something like
if(resp.startsWith("ERROR:")){
// Do error handling //
} else {
// Normal code //
}
I'm using WiFi P2P for network service discovery, and I'm following the instructions as outlined on the developer guide. Here's the relevant code in my service class:
public void onCreate() {
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(this, getMainLooper(), null);
registerP2pService();
lookForServices();
}
private void registerP2pService() {
WifiP2pDnsSdServiceInfo serviceInfo =
WifiP2pDnsSdServiceInfo.newInstance("_service.name", "_presence._tcp", new HashMap<String, String>());
manager.addLocalService(channel, serviceInfo, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.i("tag", "REGISTERED SERVICE");
}
#Override
public void onFailure(int arg0) {
Log.e("tag", "FAILED to register service");
}
});
}
private void setServiceListeners() {
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel, serviceRequest,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.d("SCOPE", "Added a service request.");
discoverServices();
}
#Override
public void onFailure(int code) {
Log.e("tag", "Error adding service request.");
}
});
}
public void discoverServices() {
manager.discoverServices(channel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.d("tag", "Service discovery was initiated");
}
#Override
public void onFailure(int code) {
// This is where it keeps failing with error code 3 (NO_SERVICE_REQUESTS)
Log.d("SCOPE", "Service discovery failure code " + code);
}
});
}
The first time I run my service after rebooting the phone, service discovery is initiated just fine, but if I kill the service by stopping it from the app settings page, then open it again, it always fails with error code 3. If I reboot my phone and run the app again it works just fine. I am confused because I am explicitly calling discoverServices only when the service request has been successfully added.
My hunch is that it may be due to some code that is unrelated to service discovery because the service discovery code seems extremely straightforward, but if you see anything wrong with what I've posted, let me know. I'm grasping at straws here.
I'm running this on a Nexus 5 with Android 4.4.2.
I'm seeing this same problem on a second generation Nexus 7. It works fine the first time, subsequent attempts error out. Specifically, the addServiceRequest action listener reports success, but then discoverServices reports NO_SERVICE_REQUESTS.
(Teardown removeLocalService and removeServiceRequest succeed before exiting the app after the initial successful use.)
While it isn't an ideal answer, toggling wifi off then on again appears to reset whatever is stuck. That can be done programatically.
WifiDirect/NSD on Android has been a thorn in my side for the last couple of weeks.
I spent half of last week trying to figure out why my peer discovery calls would fail without any consistency with NO_SERVICE_REQUESTS and finally found a solution that works fairly well. It does seem to be a bug in the OS, and luckily the fine folks of P2Feed figured out a workaround:
if (code == WifiP2pManager.NO_SERVICE_REQUESTS) {
// initiate a stop on service discovery
manager.stopPeerDiscovery(channel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
// initiate clearing of the all service requests
manager.clearServiceRequests(channel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
// reset the service listeners, service requests, and discovery
setServiceListeners();
}
#Override
public void onFailure(int i) {
Log.d(TAG, "FAILED to clear service requests ");
}
});
}
#Override
public void onFailure(int i) {
Log.d(TAG, "FAILED to stop discovery");
}
});
}