Progress Dialog is shown only after Thread terminates - java

I'm trying to connect to a TCP/IP socket in a thread the moment my app is opened, and would like to show a progress dialog while connecting. The problem is that the thread is always executed before the progress dialog is shown, which means that it is shown only after the socket connection has actually happened (or failed).
public static boolean startConnection (Context c) {
boolean[] ret = new boolean[1];
ProgressDialog progressDialog = new ProgressDialog(c);
progressDialog.setMessage("Connecting...");
progressDialog.show();
Thread t = new Thread() {
#Override
public void run() {
try {
clientSocket = new Socket();
clientSocket.connect(new InetSocketAddress(SERVER_IP, SERVER_PORT), 5000);
ret[0] = true;
}
catch (IOException e) {
e.printStackTrace();
ret[0] = false;
}
((Activity)c).runOnUiThread(progressDialog::dismiss);
}
};
t.start();
try {
t.join();
}
catch (InterruptedException e) {
e.printStackTrace();
}
return ret[0];
}
And I'm invoking startConnection in the onStart() method:
protected void onStart() {
super.onStart();
if (ConnectionHandler.startConnection(this)) {
goToMainActivity();
}
else {
Toast.makeText(this, "Connection error.", Toast.LENGTH_LONG).show();
}
}
How can I make it so that the progress dialog is shown before the thread actually starts?

t.join(); waits on the UI main thread until second thread t finishes, that's the reason your code is blocking the UI thread and the dialog doesn't appear.
In addition you can't call progressDialog.dismiss(); on the t thread, all code that interacts with the UI must be called on the main thread, you can try tom call it using runOnUIThread() activity method

Related

Threads at onCreate() method execute before setting the view

I'm creating my splash screen for app. While loading it executes 4 methods. First one checks if Internet permission is granted, second one sends request to API to check if it is Online, third one is getting Token from Firebase and the fourth one is checking if user is already logged-in. I'm doing it using 4 threads. Each method in case of error sets the flag as false. Then when all the threads end their work (I used .join()) The last method checks the state of flag and launch new activity or just display Error and try everything once again.
The problem I have is that I'm getting the view after all the threads finish their work. For example I have black screen, then message ("Error occured") and only after that I can see UI. But on Error the UI is refreshed, so one more time I have black screen, then result and UI for 1sec until another restart.
My question is, can I in some way stop these Threads until my UI is ready ?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
setContentView(R.layout.activity_splash);
checkProgress = findViewById(R.id.checkProgressText);
auth = FirebaseAuth.getInstance();
tokenUtils = new TokenUtils();
requestQueue = Volley.newRequestQueue(getApplicationContext());
animatedCircleLoadingView = findViewById(R.id.circle_loading_view);
//starting the animation
startLoading();
Thread[] checkers = new Thread[4];
checkers[0] = new Thread(this::checkInternetPermissions);
checkers[1] = new Thread(this::checkConnection);
checkers[2] = new Thread(this::getUserAuth);
checkers[3] = new Thread(this::getUserToken);
for (Thread t : checkers) {
try {
t.start();
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
changeActivity();
}
Check internet permission method:
private void checkInternetPermissions() {
checkProgress.setText(getString(R.string.check_internet_permissions_text));
if (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET)
!= PackageManager.PERMISSION_GRANTED)
requestPermissions(new String[]{Manifest.permission.INTERNET}, 1);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode != 1) {
connectionFlag = false;
}
}
Check connection method:
private void checkConnection() {
checkProgress.setText(getString(R.string.checking_api_connection));
RequestFuture<String> requestFuture = RequestFuture.newFuture();
StringRequest request = new StringRequest
(Request.Method.GET, API_CHECK,
requestFuture,
requestFuture);
requestQueue.add(request);
String response = null;
try {
response = requestFuture.get(5, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
this.connectionFlag = false;
}
if (!Objects.equals(response, "ok"))
this.connectionFlag = false;
}
Get user token method:
private void getUserToken() {
checkProgress.setText(getString(R.string.getting_user_auth_token));
String token = null;
try {
token = tokenUtils.getFirebaseToken();
} catch (ExecutionException | InterruptedException e) {
this.connectionFlag = false;
}
if (Objects.isNull(token) || Objects.requireNonNull(token).isEmpty())
this.connectionFlag = false;
}
And finally get user auth method:
private void getUserAuth() {
checkProgress.setText(getString(R.string.checking_user_auth));
authStateListener = firebaseAuth -> {
firebaseUser = firebaseAuth.getCurrentUser();
if (Objects.isNull(firebaseUser) || Objects.requireNonNull(firebaseUser.getEmail()).isEmpty()) {
this.authFlag = false;
}
};
}
Last method which handle the states of flags:
private void changeActivity() {
checkProgress.setText(getString(R.string.finalizing_text_progress));
if (connectionFlag && authFlag) {
startActivity(new Intent(SplashActivity.this, MapActivity.class));
} else if (!connectionFlag) {
Toast.makeText(getApplicationContext(), "Error occurred.", Toast.LENGTH_LONG).show();
finish();
startActivity(getIntent());
} else {
startActivity(new Intent(SplashActivity.this, LoginActivity.class));
}
}
Yes, You can try it with handler thread with some delay then it will work fine or you can start your thread on onResume() method at the time of onResume your view will have been created
I think, your way wrong. Because, API request working on asynchronous. Your app should run like this;
Check Internet connection.
API Request.
Get token in API Request onSuccess method.
Get User Auth.
I think, you shouldn't use Thread.

Toasts are shown not simultaneously

I have a part of code in which I firstly setText, then make a Toast and after that I'm trying to connect via Bluetooth. The problem is that my setText and Toasts appear only after connection has been made.
I tried to put Log.i instead of Toasts and they were shown simultaneously.
Can somebody explain me why and how to make Toasts simultaneously?
Code:
........
else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
tvDevices.setText("");
Toast.makeText(getApplicationContext(), "Lost connection!", Toast.LENGTH_SHORT).show();
connect(btDevice, ConstantsVariables.reconnectionAttempts);
}
public void connect(BluetoothDevice bt, int attempts){
Toast.makeText(getApplicationContext(), "Trying to connect...", Toast.LENGTH_SHORT).show();
if(attempts > 0){
for(int i = 1; i <= ConstantsVariables.reconnectionAttempts; i++){
ConnectThread thread = new ConnectThread(bt);
boolean connectVar = thread.connect();
if(connectVar){
break;
}
}
}
}
.......
public boolean connect() {
BA.cancelDiscovery();
try {
mSocket.connect();
} catch (IOException e) {
Log.d("CONNECTTHREAD","Could not connect: " + e.toString());
try {
mSocket.close();
} catch (IOException exception){}
return false;
}
return true;
}
It is possible that you're blocking the UI Thread while connection is being attempted. Try to move the connection code to a background thread, or an AsyncTask, and handle the UI Changes in the AsyncTask's callbacks.
Edit: Also the context getApplicationContext() passed to Toast is ambiguous. Are you in an activity? In that case it should simply point to the Activity's context i.e. this and not the Application's context

Alarm ringing stops when cleared from ram

I am making an alarm clock which asks user to do a particular work in order to close the alarm when it rings. It is working fine but the problem is that if the user closes the alarm app from the recent activities while the alarm is ringing, the alarm stops ringing. I want that even if the user clears the app while its ringing, it should not stop ringing. It should only stop once the task given is completed. How can I implement this?
Edit #1: Activity that is called when alarm rings
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(LOG_TAG, "in AlarmAlert");
unlockScreen();
setContentView(R.layout.activity_alarm_alert);
Bundle bundle = this.getIntent().getExtras();
alarm = (Alarm) bundle.getSerializable("alarm");
alarmDatabase = new AlarmDatabase(this);
//Uri uri = alarm.getRingtonePath();
question = (TextView)findViewById(R.id.question);
answer = (TextView) findViewById(R.id.answer);
oldColors = answer.getTextColors();
diff = alarm.getDifficulty().toString();
questionString = GenerateMathsQuestion.generateQuestion(diff);
question.setText(questionString);
actualAnswer = EvaluateString.evaluate(questionString);
AudioManager am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
int result = am.requestAudioFocus(focusChangeListener,
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
mediaPlayer = new MediaPlayer();
mediaPlayer.setVolume(1.0f, 1.0f);
mediaPlayer.setLooping(true);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
try {
mediaPlayer.setDataSource(this, Uri.parse(alarm.getRingtonePath()));
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.start();
}
if(alarm.getIsVibrate()) {
vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
long[] pattern = {1000, 200, 200, 200};
vibrator.vibrate(pattern, 0);
}
}
public void closeAlarm(){
Log.v(LOG_TAG, "will now stop");
mediaPlayer.stop();
if(vibrator!=null)
vibrator.cancel();
Log.v(LOG_TAG, "will now release");
mediaPlayer.release();
Log.v(LOG_TAG, "id of ringing alarm: " + alarm.getAlarmId());
alarm.setIsActive(false);
alarmDatabase.updateData(alarm);
cursor = alarmDatabase.sortQuery();
while(cursor.moveToNext()){
int id = cursor.getInt(cursor.getColumnIndex(AlarmDatabase.COLUMN_UID));
currentAlarm = alarmDatabase.getAlarm(id);
Log.v(LOG_TAG, "id of next alarm " + id);
if(currentAlarm != null) {
if (currentAlarm.getIsActive() == true) {
currentAlarm.scheduleAlarm(this, true);
break;
}
}
}
this.finish();
}
You should use Services. Take a look at it, that is what you want it. Generally you can make it to run an operation, and a service wont return any result. But it runs indefinitely even when you kill the app from task manager or free RAM.
I suggest this tutorial for reading about services.
UPDATE
Implement your activity with the service in the following way so it can talk with the layout and stops the alarm when required.
public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
#Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}

Android Studio Error: Can't create handler inside thread that has not called Looper.prepare()

I am trying to run a section of code every X seconds in an AsyncTask Activity and it is crashing before getting into any print statements. I am not sure why it is crashing, but I also posted the error I am getting. Anyone have any ideas? Thank you so much!
public class AppListener extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... uri) {
final Handler h = new Handler();
final int delay = 5000; //milliseconds
h.postDelayed(new Runnable() {
public void run() {
try {
String msg_received = null;
System.out.println("LISTENING FOR LAST INSTALLED APP");
System.out.println("TRY");
Socket socket = new Socket("85.190.178.23", 5050);
// Get data sent through socket
DataInputStream DIS = new DataInputStream(socket.getInputStream());
System.out.println("DataInputStream Started");
// read data that got sent
msg_received = DIS.readUTF();
System.out.println("Message from server" + msg_received);
// Might not want to close socket, or only the first string will be sent and none after
socket.close();
}
catch (Exception e) {
System.out.println("Did not receive string");
}
h.postDelayed(this, delay);
}
}, delay);
String msg_received = null;
return msg_received;
}
}
MY ERROR
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Here is how I got my loop to execute every X seconds without interfering with my GUI if it is helpful to anyone else: instead of having a separate class, I just posted my code in my main activity right when my app starts
public class MainActivity extends FragmentActivity{
private Thread repeatTaskThread;
// called when the activity is first created
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Go into loop that is repeated every X seconds
RepeatTask();
}
private void RepeatTask()
{
repeatTaskThread = new Thread()
{
public void run()
{
while (true)
{
//Post your code here that you want repeated every X seconds
// My "try" and "catch" statements from above got inserted here
try
{
// Sleep for 5 seconds
Thread.sleep(5000);
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
};
repeatTaskThread.start();
}
}
Updated: When you're launching AsyncTasks doInBackground, you're launching a background thread. If you want to post AsyncTask's doInBackground with a delay, then you should not use an AsyncTask at all. You should only need to use a Handler with postDelayed, which will create a background thread for you. It looks like in your code, you tried launch a new Thread with a Handler while in AsyncTask's background thread.
Get rid of the AsyncTask altogether, and include this code in your Activity:
final Handler h = new Handler();
final int delay = 5000; //milliseconds
h.postDelayed(new Runnable() {
public void run() {
try {
String msg_received = null;
System.out.println("LISTENING FOR LAST INSTALLED APP");
System.out.println("TRY");
Socket socket = new Socket("85.190.178.23", 5050);
// Get data sent through socket
DataInputStream DIS = new DataInputStream(socket.getInputStream());
System.out.println("DataInputStream Started");
// read data that got sent
msg_received = DIS.readUTF();
System.out.println("Message from server" + msg_received);
// Might not want to close socket, or only the first string will be sent and none after
socket.close();
}
catch (Exception e) {
System.out.println("Did not receive string");
}
h.postDelayed(this, delay);
}
}, delay);
String msg_received = null;
return msg_received;
}

How to set time limit for waiting internet Connection in android AsyncTask?

I have use The AsyncTask For connecting Internet. a Progress dialog can show at onPreExecute() and i check is Online of that mobile if yes means it will execute the http connections code also dismiss the progress dialog at onPostExecute() and its work as good.
But i have problem if net connection is available at time of Request and connection closed before get Response means the Progress dialog showing always.
Now i want solve this if interconnect disconnect before get Response mean it's alert me as No internet connection and dismiss the progress dialog (may set loading time limit for 30 seconds).
below is my code.
can any one help?
public class SubjectTask extends AsyncTask<Void, Void, Integer> {
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(Login.this, "Loading",
"Please wait...");
//checkConnection();
}
#Override
protected Integer doInBackground(Void... arg0) {
if (isOnline()) { //using ConnectivityManager And Network Info
try {
//Http Request connections
} catch (Exception e) {
e.printStackTrace();
}
return 1;
} else {
alert("Check your internet connection");
return 0;
}
}
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
if (progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
}
You can use broadcast receiver to get the event of network connect or disconnect. register this receiver in doInbackground method and unregister it in onPostExecute method.
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivity = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = connectivity.getActiveNetworkInfo();
//Play with the info about current network state
if(info.getState()== NetworkInfo.State.DISCONNECTED) {
// hide loader and show alert here
}
}
}
};
intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(broadcastReceiver, intentFilter);
If the connection will be closed before or while the http request an IOException will be thrown. Catch that exception and close your Dialog there and inform the user about this event.
if (isOnline()) { //using ConnectivityManager And Network Info
try {
//Http Request connections
} catch (IOException e) {
e.printStackTrace();
// Do the error handling here
} catch (ClientProtocolException e) {
e.printStackTrace();
}
}
I don't know if you really need a return value to your onPostExecute(). If yes consder to make the logic aware that an exception could occur.
i thank to Steve Benettand Bhawna Raheja,
sorry for the late reply,
Simply i have solve this error by set Timeout via HttpRequest.TimeOut .
i dont know how i forgot to set time out.
One again thank to You both.

Categories