Recall a function - java

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.

Related

Subscribe Conditionally to rxJava2 Observable

I have a rxJava2 Observable to which I want to subscribe conditionally.
The scenario i will make a network call and the subscribe() is called only when the device is connected to network.I want to do something like below
observable.
subsribeWhenConditionIsMet(
if (connected to internet) {
mPresentation.showNetworkError();
return;
}
subscribe();
}
)
Any suggestions on how to do this? Any better approaches available?
For now there is no such method is available in RxJava2. But if you are using kotlin you can do it using extension function. Declare it like below.
fun <T> Observable<T>.subscribeIf(predicate: () -> Boolean) {
if (predicate()) {
subscribe()
}
}
At the time of call :
anyObservable()
.subscribeIf { isConnectedToInternet() }
Extra
In case if you want to handle fallback situation you can write your extension like below and make fallback lambda optional so that we can omit it if not required.
fun <T> Observable<T>.subscribeIf(predicate: () -> Boolean, fallback: () -> Unit = {}) {
if (predicate()) {
subscribe()
} else {
fallback()
}
}
At the time of call:
anyObservable()
.subscribeIf(
predicate = { isConnectedToInternet() },
fallback = { showError() }
)
}
Note: You can also call it from Java, refer this link https://stackoverflow.com/a/28364983/3544839
Having internet access is more than a simple condition, if you think about it it's more like a stream of booleans, sometimes it's true, sometimes it's false.
What you want is to create an Observable that fires true when an internet connection becomes available.
If you're on Android, you can have a BehaviourSubject in a broadcast receiver
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
final ConnectivityManager connMgr = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
final android.net.NetworkInfo wifi = connMgr
.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
final android.net.NetworkInfo mobile = connMgr
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
boolean hasInternet = wifi.isAvailable() || mobile.isAvailable()
subject.onNext(hasInternet);
}
}
You still need to somehow pass the subject to your broadcast receiver but it shouldn't be a big deal.
Then, in order to subscribe to your observable only when this subject returns true, you can do it like so:
subject
.filter(hasInternet ->
hasInternet // Don't continue if hasInternet is false
)
.flatMap(o ->
yourObservable // At this point, return the observable cause we have internet
)
.subscribe() // subscribe

Android Wait until Text to Speech OnInit is called

I had an issue where Text to Speech would not speak anything. I realised this was due to the fact that I was attempting to call 'Speak()' before TTS had initialised.
I need to wait until TTS has initialised, so that I can call 'Speak()' successfully. I thought doing something along the lines of this would work:
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
mTTSInitialised = true;
} else {
Log.e("TTS", "Initialisation Failed!");
}
}
...
while(!mTTSInitialised){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
But this fails to initialise at all. Is there a way to do this effectively?
The initialisation of the Text to Speech engine is asynchronous, which is why you realised you have to 'wait' for it to complete, before requesting that it processes an utterance.
Even when it eventually initialises successfully, it can be subsequently killed by the system, or it can of course fail to initialise, so you always need to be ready to handle a request to speak, where the engine isn't prepared.
Add the following helper class
public class PendingTTS {
private String pendingUtterance;
private int pendingQueueType;
public String getPendingUtterance() {
return this.pendingUtterance;
}
public void setPendingUtterance(#NonNull final String pendingUtterance) {
this.pendingUtterance = pendingUtterance;
}
public int getPendingQueueType() {
return this.pendingQueueType;
}
public void setPendingQueueType(final int pendingQueueType) {
this.pendingQueueType = pendingQueueType;
}
}
Assuming you're using an Activity, you need to declare the following variables:
private volatile PendingTTS pendingTTS;
private static final int MAX_INIT_ATTEMPTS = 4;
private volatile int initCount;
and initialise the Text to Speech object in onCreate()
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
In your onInitListener you would check if there is any pending speech:
#Override
public void onInit(final int status) {
switch (status) {
case TextToSpeech.SUCCESS:
initCount = 0;
// Set up tts stuff
tts.setOnUtteranceProgressListener(YOURprogressListener);
if (pendingTTS != null) {
// We have pending speech, process it and check the result
int speechResult = tts.speak(pendingTTS.getPendingUtterance(),pendingTTS.getPendingQueueType(),
// remaining tts variables here)
switch (speechResult){
case TextToSpeech.SUCCESS:
// Result was successful
pendingTTS = null;
break;
case TextToSpeech.ERROR:
// Speech failed
// Check if it has repeatedly failed up to the max attempts
if(initCount < MAX_INIT_ATTEMPTS){
initCount ++;
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
} else {
// Totally broken - let the user know it's not working
}
break;
}
} else {
// there was nothing to process
}
break;
case TextToSpeech.ERROR:
// Check if it has repeatedly failed up to the max attempts
if(initCount < MAX_INIT_ATTEMPTS){
initCount ++;
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
} else {
// Totally broken - let the user know it's not working
}
break;
}
I've glued the above together from my code - where the speech and initialisation methods are all separated, but I tried to give you an overview above of everything you need to handle.
Elsewhere in your code, when you make a tts.speak(//stuff here) request, you need to check the result as demonstrated above, to make sure it was successful. Again, in my code, this is separated into one single method. If it does fail, you need to set the PendingTTS parameters prior to attempting to initialise again:
pendingTTS = new PendingTTS();
pendingTTS.setPendingQueueType(// your queue type);
pendingTTS.setPendingUtterance(// your utterance);
It is is successful, make sure pendingTTS is set to null.
The overall design is that if the initialisation failed, it will attempt to initialise again, up to the maximum allowed attempts. If the speech fails, it will attempt to initialise the engine again, firstly setting the PendingTTS parameters.
Hope you managed to follow that.
Hmm..
Not a very good idea.
You can try to add the text to the TTS queue and let it do it's work. This snippet can be inside button click, etc as:
tts.speak(toSpeak, TextToSpeech.QUEUE_ADD, null);
Small tutorial that would help.

Implementing Repository Pattern With RxJava

I'm trying to figure out a better way to achieve something like repository pattern in RxJava in Android.
Here's what I have so far: (took some code from here)
public Subscription getData(Observer<Data> observer, boolean refresh) {
Subscription sub = null;
Data cached = getCachedData();
if(cached != null) {
observer.onNext(cached);
if(refresh) {
sub = requestNetwork().subscribe(observer);
} else {
observer.onCompleted();
}
} else {
sub = requestNetwork().subscribe(observer);
}
return sub;
}
Basically it check if there's cached data stored, if not it'll make a network request. It also have refresh boolean parameter force it always make a network request.
The problem (or not) is, the caller of this function needs to call it will receive Subscription instead of Observable, which I can't chain anymore.
Is there a way to make the function return Observable but still have the repository pattern?
Thanks to akarnokd pointing me out to this article by Dan Lew.
My final code:
public Observable<Data> getData(boolean refresh) {
Observable<Data> obs = Observable.concat(getCache(), requestNetwork());
if(!refresh) {
obs = obs.first(data -> data != null);
}
return obs;
}

MediaPlayer or SoundPool for multiple short sounds?

The app basically allows the user to play an animal sound, voice or other sound when clicking various items. I'm trying to figure out if I'm doing this in the right way because I'm seeing some issues like this error, when the user mutes>unmutes>plays a sound:
java.lang.IllegalStateException at
android.media.MediaPlayer.isPlaying(Native Method)
public class GuessActivity extends Activity implements PopupMenu.OnMenuItemClickListener {
public static int[] ssSoundsArray = {R.raw.sbuffalo, R.raw.scamel, R.raw.scat, R.raw.schicken};
public static int[] ssVoicesArray = {R.raw.buffalo, R.raw.camel, R.raw.cat, R.raw.chicken};
MediaPlayer mMediaPlayer;
Context context;
...
}
Here's an example of how I am using MediaPlayer:
if(audio_all) {
if(mMediaPlayer != null) {
if(mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
}
mMediaPlayer = MediaPlayer.create(this, R.raw.whatever);
mMediaPlayer.start();
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mediaPlayer) {
mMediaPlayer.release();
mMediaPlayer = null;
}
});
}
I'm doing this multiple times for different buttons etc, making sure to release() after they are done since I ran into mem issues before. So the exception is telling above is telling me isPlaying() isn't valid since MediaPlayer does not exist but for some reason it ignores if(mMediaPlayer != null)
It is necessary to stop if anything is playing since the user is free to click randomly and of course I do not want any sounds overlaying eachother.
Here's how the user mutes:
case R.id.action_toggle_sounds:
if(audio_all) {
if(mMediaPlayer != null) {
if(mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
}
Toast.makeText(this,"All sounds disabled",Toast.LENGTH_LONG).show();
audio_all = false;
} else {
Toast.makeText(this,"All sounds enabled",Toast.LENGTH_LONG).show();
audio_all = true;
}
return true;
I very much appreciate any help with this, thanks a lot!
If you has not so much tracks to play (not more than 32) you can try to initialize multiple MediaPlayer instances and release() them only when app onPause()/onStop() called.
Then you will have pool of ready to use MediaPlayer's. You just have to remember which one is in use right now.
Also if you use MediaPlayer in multiple threads (not only UI thread) then you MUST use mutex (thread blocking) to avoid issues.
MediaPlayer based state machine - IllegalStateException basicly means player instance is in state when calling isPlaying() not allowed. For isPlaying() documented not allowed state is only Error state, but assume state after calling release() may be also not appropriate for this.

How to handle ConnectTimeoutException Android

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;
}

Categories

Resources