Does anyone know how to handle a ConnectTimeoutException? i'm posting variables to a url using AsyncTask but my internet connection is shocking so i'm recieving null data back because of a ConnectTimeoutException. What are the best ways to handle this for example if time out occurs try run again etc i have not had this problem before so don't have a clue how to handle but i feel it needs handling to improve user experience. so any ideas?
You could use an Handler to let your Activity know you got a ConnectTimeoutException
Catch this exception in your AsyncTask and send a message to your Handler (then do whatever you want)
Just for information, AsyncTask aren't designed for long running operation, if so you should use a Thread
this is how you shoud check for the network status
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
//execute your AsyncTask method
} else {
//maketoast..."No network connection available"
}
Make a separate class called Activity helper, and implement it in your async task for any class that you make in which requires a webservice call.
public class ActivityHelper {
public static final String NETWORK_CONNECTION_MESSAGE = "No Network Connection. Please make sure you have a Network Connection.";
public static boolean isNetworkPresent(Context applicationContext){
boolean hasService = false;
NetworkInfo info=(NetworkInfo)( (ConnectivityManager)applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
hasService = (info==null || !info.isConnected())?false:true;
return hasService;
}
}
call Activity Helper in "doInBackground" Method kinda like this..
private class YourAsyncTask extends AsyncTask<String, Void, String> {
Message message = new Message();
String type = "";
protected void onPreExecute() {
ActivityHelper.onUserInteraction(getApplicationContext());
dialog = ProgressDialog.show(LocationType.this,
"Connecting to server", "Please wait...", true, true);
dialog.setCancelable(false);
}
protected String doInBackground(final String... args) {
try {
if(!ActivityHelper.isNetworkPresent(getApplicationContext())){
message.what = ActivityHelper.NONETWORKCONNECTION;
return null;
}
} catch (Exception e) {
Log.e(this.getClass().getName(),
"Exception Message");
}
return null;
}
Related
I have been working on an android application.For one of the feature, I need the active network information(i.e. whether it's connected with Wi-Fi or mobile data). I got this piece of code from the internet.
NetworkInfo activeNetworkInfo = context.getSystemService(ConnectivityManager.class).getActiveNetworkInfo();
But this API is deprecated and I don't want to use any deprecated API.
After some more googling, I found that we should use ConnectivityManager.NetworkCallback instead. But I am not able to get an example of it. How can I use this?. Please help me if anyone having an idea about using ConnectivityManager.NetworkCallback
Check out this function in Kotlin
fun networkConnection(): Boolean {
var networkAvailable = false
val connectivityManager: ConnectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val network: Network = connectivityManager.activeNetwork!!
val networkCapabilities: NetworkCapabilities = connectivityManager.getNetworkCapabilities(network)!!
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
networkAvailable = true
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
networkAvailable = true
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
networkAvailable = true
}
return networkAvailable
}
try the following code:
private void registerNetworkCallback(Context context) {
final ConnectivityManager manager =
(ConnectivityManager) context.getSystemService(CONNECTIVITY_SERVICE);
manager.registerNetworkCallback(
new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
.build(),
new NetworkCallback() {
#Override
public void onAvailable(Network network) {
/** here to get the available info
this ternary operation is not quite true, because non-metered
doesn't yet mean, that it's wifi
nevertheless, for simplicity let's assume that's true
*/
Log.i("vvv", "connected to " + (manager.isActiveNetworkMetered() ? "LTE" : "WIFI"));
}
#Override
public void onCapabilitiesChanged(Network network,
NetworkCapabilities networkCapabilities){
/**here to get the change network info
Value is TRANSPORT_CELLULAR, TRANSPORT_WIFI,
TRANSPORT_BLUETOOTH, TRANSPORT_ETHERNET, TRANSPORT_VPN
*/
if(networkCapabilities.hasTransport("type")){
}
}
});
}
connectivityManager = (ConnectivityManager)
context.getSystemService(ConnectivityManager.class);
#RequiresApi(api = Build.VERSION_CODES.M)
private void getActiveNet() {
Network currentNetwork = connectivityManager.getActiveNetwork();
}
Note that "active network" is synonymous in android with "default network".
ConnectivityManager#getActiveNetworkInfo()
Returns details about the currently active default data network...
ConnectivityManager#registerDefaultNetworkCallback(NetworkCallback)
Registers to receive notifications about changes in the application's
default network...
Therefore using ConnectivityManager#registerDefaultNetworkCallback(NetworkCallback) you can listen for default (aka "active") network changes. Unfortunately, this only returns the Network object which does not have information regarding transport (Wi-Fi vs Cellular) in which case you'll need to make an additional call to ConnectivityManager#getNetworkCapabilities(Network) to get that info.
Here is an example:
final ConnectivityManager connectivityManager = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkCallback networkCallback = new NetworkCallback() {
#Override
void onAvailable(Network network) {
// Triggers when a default network is available.
NetworkCapabilities nc = connectivityManager.getNetworkCapabilities(network);
boolean isWifi = nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
boolean isCellular = nc.hasTransport(NetworkCapabilities. TRANSPORT_CELLULAR);
}
};
connectivityManager.registerDefaultNetworkCallback(networkCallback);
i'm having trouble implementing rxJava in order to check if there is internet connection on android i'm doing it like this:
on my launcher activity i have this in onCreate:
AndroidObservable.bindActivity(this,
Observable.just(Utils.isActiveInternetConnection(Launcher.this)))
.subscribeOn(Schedulers.newThread())
.subscribe(new Action1<Boolean>() {
#Override
public void call(Boolean aBoolean) {
if (aBoolean) {
Toast.makeText(Launcher.this, "There is internet connection", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(Launcher.this, "There is no internet connection", Toast.LENGTH_SHORT).show();
}
}
});
i have an Utils class it is a final class with static methods the methods in that the observable is using are this ones:
public static boolean isActiveInternetConnection(Context context) {
if (isNetworkAvailable(context)) {
try {
HttpURLConnection urlc = (HttpURLConnection) (new URL("http://www.google.com").openConnection());
urlc.setRequestProperty("User-Agent", "Test");
urlc.setRequestProperty("Connection", "close");
urlc.setConnectTimeout(1500);
urlc.connect();
return (urlc.getResponseCode() == 200);
} catch (IOException e) {
Log.e("network", "Error checking internet connection", e);
}
} else {
Log.d("network", "No network available!");
}
return false;
}
private static boolean isNetworkAvailable(Context context){
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
if (null != activeNetwork) {
return true;
}
else {
return false;
}
}
i'm receiving android.os.NetworkOnMainThreadException and i can't find why, thanks in advance.
Observable.just(...) is called immediately on the calling thread (the main thread, in this case). Your code is effectively just an inlined version of this:
boolean activeConn = Utils.isActiveInternetConnection(Launcher.this);
AndroidObservable.bindActivity(this,
Observable.just(activeConn))
.subscribeOn(...)
...
You've tried to move it off the main thread by calling subscribeOn() - but the call has already happened.
The way we handle this (and I'm not sure that this is the best way, but it works) is to defer the network or blocking call until subscription happens, set up the observable to run on the correct threads, and then subscribe:
AndroidObservable.bindActivity(this,
Observable.defer(new Func0<Boolean>() {
#Override
public Observable<Observable<Boolean>> call() {
return Observable.just(Utils.isActiveInternetConnection(Launcher.this));
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Boolean>() {
#Override
public void call(Boolean aBoolean) {
if (aBoolean) {
Toast.makeText(Launcher.this, "There is internet connection", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(Launcher.this, "There is no internet connection", Toast.LENGTH_SHORT).show();
}
}
});
AdamS is correct, however RxJava 2 now offers Observable.fromCallable() to defer an observable operation till subscription.
A good reference:
https://caster.io/lessons/fromcallable-converting-slow-methods-into-an-observable/
Some example code from my use-case:
Single.fromCallable(new Callable<Response>() {
#Override
public Response call() throws Exception {
return NetworkGateway.networkRequest();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
I guess just just calls the method synchronously as it expects the boolean value and it tries to get it.
I am rather bad at RxJava but you may try something like this:
Observable<Boolean> onlineObservable = Observable.create(new Observable.OnSubscribe<Boolean>() {
#Override
public void call(Subscriber subscriber) {
subscriber.onNext(Utils.isActiveInternetConnection(context));
}
});
onlineObservable.subscribeOn(Schedulers.newThread()).subscribe(result -> {...});
this is my retrieve data from DataBase by RXAndroid code:
Observable.create(new Observable.OnSubscribe<List<GRO_VO>>() {
#Override
public void call(Subscriber<? super List<GRO_VO>> subscriber) {
String jsonIn;
jsonIn =retrieveDataFromDB();
Gson gson = new Gson();
Type listType = new TypeToken<List<GRO_VO>>() {
}.getType();
eventJoinList = gson.fromJson(jsonIn, listType);
Log.d("RX",jsonIn);
subscriber.onNext(eventJoinList);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<List<GRO_VO>>() {
#Override
public void call(List<GRO_VO> eventJoinList) {
Log.d("RX", ".subscribe");
recyclerView.setAdapter(new EventJoinAdapter(eventJoinList));
}
});
I think the just operator will emit data immediately, so it's is not useful to retrieve data from a database via network. It is very easy to use, but it can only be used for data that's already in the ram of the device.
I also had that problem, like #Baniares had, but after I use the create operator, all the problem gone...
From the RXJava documentation:
static <T> Observable<T> create(Observable.OnSubscribe<T> f)
Returns an Observable that will execute the specified function when a Subscriber subscribes to it.
Using the create operator can establish the standard process:
1 .subscribe(...) Subscriber(the sub class of class Observer) start the connection to Observable.
2 .subscribeOn(Schedulers.io()) collect a backGround Thread from the RX-ThreadPool
3 .create(...) retrieve data from server...during some netWork..etc
4 .observeOn(AndroidSchedulers.mainThread()) this means data will be set by the UI-Thread
5 Once we get the data , we can set the data in the onNext( ) method in the .subscribe( ) , the data will be set on the UI by UI-Thread since we make UI-thread do the work on the .observerOn(AndroidSchedulers.mainThread())
And note that if you use .create( ) operator,you must finished your observable in the .create( ) , others operator such like map,flatMap will not be executed after the .create( ) operator.
A very important concept we must need to know before start to use RXJava/RXAndroid. RX is a callback-based library, you tell RX what it should to do in what condition, it invoke your pass-in function(or in JAVA I may should to call them anonymous inner class... ) to achieve what you want.
I am currently trying to handle a situation in a demo application I'm writing where I have an expired access token, and I need to use a refresh token to get a new access token. Now for background tasks like this, I'd normally use an AsyncTask like my app currently does for login (which works fine), but I'm not sure how to do this - if it can even be done (I'm sure it can, but I'm just not seeing it right now).
Below is my current flow - the call to get() blocks the UI thread, which isn't what I'm supposed to be doing here. Our access ticket class contains both the access token and refresh token.
public boolean isLoggedIn() {
if (isFreshAccessToken())
return true;
// If the access token is expired, we'll need to use the
// refresh token to get another one. Use a background task
// to do this.
String refreshToken = preferences.getString(REFRESH_TOKEN_KEY, null);
if (StringUtils.isNotBlank(refreshToken)) {
RefreshAccessTokenAsyncTask refreshLogin = new RefreshAccessTokenAsyncTask();
refreshLogin.execute(refreshToken);
try {
return refreshLogin.get();
} catch (Exception e) {
Log.d(TAG, "isLoggedIn() : Exception in async task. Returning false.");
return false;
}
} else
return false;
}
Here is what my AsyncTask implementation currently looks like. The refreshAccessTicket() method simply makes the REST call to get the AccessTicket response.
private class RefreshAccessTokenAsyncTask extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
String refreshToken = params[0];
try {
// Get a new access token using the refresh token
// in the background ...
AccessTicket accessTicket = refreshAccessTicket(refreshToken);
// ... and save the updated information to the shared
// preferences
saveAccessTicket(accessTicket);
return true;
} catch (Exception ex) {
// If the call for a new access token fails for any reason,
// return FALSE. We'll force the user to log in again to
// get a completely new access ticket.
return false;
}
}
#Override
protected void onPostExecute(Boolean isLoggedIn) {
super.onPostExecute(isLoggedIn);
Log.d(TAG, "RefreshAccessTokenAsyncTask.onPostExecute() : " +
"Returning isLoggedIn value of " + isLoggedIn);
}
}
What am I missing here? As I mentioned above, I want this process to be silent - if the access token has expired, I want to use the refresh token to automatically get a new access token without the user having to do anything or have the app jump out of the current flow (such as getting a friends list, etc.) - it will happen in the background. Should I be using something other than AsyncTask?
AsyncTask should work fine, but you can't get the result like that. Try something like this instead.
private interface Callback {
void done(boolean result);
}
private class RefreshAccessTokenAsyncTask extends AsyncTask<String, Void, Boolean> {
private Callback cb;
private RefreshAccessTokenAsyncTask(Callback callback)
cb = callback;
}
#Override
protected Boolean doInBackground(String... params) {
String refreshToken = params[0];
try {
// Get a new access token using the refresh token
// in the background ...
AccessTicket accessTicket = refreshAccessTicket(refreshToken);
// ... and save the updated information to the shared
// preferences
saveAccessTicket(accessTicket);
return true;
} catch (Exception ex) {
// If the call for a new access token fails for any reason,
// return FALSE. We'll force the user to log in again to
// get a completely new access ticket.
return false;
}
}
#Override
protected void onPostExecute(Boolean isLoggedIn) {
super.onPostExecute(isLoggedIn);
Log.d(TAG, "RefreshAccessTokenAsyncTask.onPostExecute() : " +
"Returning isLoggedIn value of " + isLoggedIn);
cb.done(isLoggedIn);
}
}
Then use the AsyncTask like so:
public boolean isLoggedIn() {
if (isFreshAccessToken())
return true;
// If the access token is expired, we'll need to use the
// refresh token to get another one. Use a background task
// to do this.
String refreshToken = preferences.getString(REFRESH_TOKEN_KEY, null);
if (StringUtils.isNotBlank(refreshToken)) {
Callback callback = new Callback() {
public void done(boolean result){
// whatever you need to do here
}
}
RefreshAccessTokenAsyncTask refreshLogin = new RefreshAccessTokenAsyncTask(callback);
refreshLogin.execute(refreshToken);
} else
return false;
}
I'm performing a check of internet access in a program. I'd like to do a function to that cause this checking need to often happens... But my original function have to return while it because the screen need to refresh. This is what I have:
public void isOnline(Runnable Rcallback, Ccallback) {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
boolean checkState = cm.getActiveNetworkInfo().isConnectedOrConnecting();
if(checkState) {
isOnline = true;
if(Rcallback != null) Rcallback.run();
if(Ccallback != null) set;}
else {
isOnline = false;
Toast.makeText(gMain.this, R.string.nointernet, Toast.LENGTH_LONG).show();
Handler reTry = new Handler();
reTry.postDelayed(new Runnable() {
#Override
public void run() {
isOnline(callback) ;
}
},3000);
}
}
My really problem is in Ccallback that it's a function to call back when the program turns online. I don't know how to declare a function as a "variable". Any ideas?
You should setup a listener using the Observer Pattern. This will allow you to tell anyone marked as a listener (likely your UI) that you have done something. In this case, something is connected.
One thing to keep in mind while doing this is to ensure that while doing things on the UI, you are on the Event Thread.
is there a possiblity to explicitely use the wifi connection for doing Http Url requests?
In fact i just need to know if an internet connection (access to google.com for example) is possible via wifi.
(not via 2g / 3g / ..)
As far as I know, no. This is all abstracted from us by the platform.
But you can check to see if WIFI is available:
ConnectivityManager conMan = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
if(conMan!=null){
try {
NetworkInfo[] networkInfos = conMan.getAllNetworkInfo();
for(NetworkInfo ni : networkInfos){
if(ni.isAvailable() && ni.isConnected() && ni.getTypeName().equals("WIFI")){
result = true;
break;
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
You may find this useful:
public class ConnectivityHelper {
public static boolean isWiFiNetworkConnected(Context context) {
return getWiFiNetworkInfo(context).isConnected();
}
private static NetworkInfo getWiFiNetworkInfo(Context context) {
return getConnectivityManager(context).getNetworkInfo(ConnectivityManager.TYPE_WIFI);
}
private static ConnectivityManager getConnectivityManager(Context context) {
return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
}
}
I havent done this, so i'm not sure, but I found this looking through the documentation.
public boolean wifiAvailable() {
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = connMgr.getActiveNetworkInfo();
if((info.isAvailable() && info.isConnected() && (info.getType()==ConnectivityManager.TYPE_WIFI))) return true;
return false;
}
Where you are going to fire a request, evaluate this method, if it returns true the system will automatically use WiFi, android will always use wifi over 3G/2G when available AFAIK.