Reshow a progress dialog from Async Task if it gets dismissed - android

I have a progress dialog that shows how many files are left for uploading in my Async Task and the user can dismiss this dialog if he wants to. However I want to have a button that will be able to show again that progress dialog at its current stage and I don't know how to do that since you I can't just create a function in the Async Task and call it from a different activity. Any thoughts?

You can make a singleton class to handle the Async Task progress which holds only one listener (the Activity who wants to listen for the progress of your AsyncTask).
Your Singleton class can be like below:
public class ProgressDialogUtil {
public interface ProgressDialogUtilListener{
void showProgressDialog();
void dismissProgressDialog();
void updateProgressDialog(int value);
void setProgressDialogMessage(String message);
}
private ProgressDialogUtilListener listener;
private static ProgressDialogUtil mInstance;
public static ProgressDialogUtil getInstance() {
if (mInstance == null) {
synchronized (ProgressDialogUtil.class) {
if (mInstance == null) {
mInstance = new ProgressDialogUtil();
}
}
}
return mInstance;
}
public void setListener(ProgressDialogUtilListener listener) {
this.listener = listener;
}
public void showProgressDialog(){
if(listener!=null)
listener.showProgressDialog();
}
public void dismissProgressDialog(){
if(listener!=null)
listener.dismissProgressDialog();
}
public void updateProgressDialog(int value){
setProgressDialogMessage("Files Downloaded: "+ value);
if(listener!=null)
listener.updateProgressDialog(value);
}
public void setProgressDialogMessage(String message){
if(listener!=null)
listener.setProgressDialogMessage(message);
}
}
Then you can use this Singleton class (ProgressDialogUtil) in your AsyncTask like below to inform for any update occurred:
public class MyAsyncTask extends AsyncTask<Void, Integer, Boolean> {
public final ProgressDialogUtil progressDialogUtil;
public MyAsyncTask(ProgressDialogUtil progressDialogUtil){
this.progressDialogUtil = progressDialogUtil;
}
#MainThread
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialogUtil.setProgressDialogMessage("Start Download files..");
progressDialogUtil.showProgressDialog();
}
#WorkerThread
#Override
protected Boolean doInBackground(Void... params) {
//download your files here in the Background Thread...
//below is a sample loop
for (int i=0; i <= 50; i++) {
try {
Thread.sleep(1000);
publishProgress(i);
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
}
return true;
}
#MainThread
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
progressDialogUtil.updateProgressDialog(values[0]);
}
#MainThread
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
progressDialogUtil.setProgressDialogMessage("Finished Download!");
progressDialogUtil.dismissProgressDialog();
}
}
Then in your first Activity where you start the AsyncTask you can create a new instance of your Progress Dialog and set a listener ProgressDialogUtilListener to listen for any AsyncTask progress to show/hide/update the Progress Dialog like below:
ProgressDialog pd = new ProgressDialog(this);
ProgressDialogUtil progressDialogUtil = ProgressDialogUtil.getInstance();
progressDialogUtil.setListener(new ProgressDialogUtil.ProgressDialogUtilListener()
{
#Override
public void showProgressDialog() {
if (!pd.isShowing())
pd.show();
}
#Override
public void dismissProgressDialog() {
if (pd.isShowing())
pd.dismiss();
}
#Override
public void updateProgressDialog(int value) {
pd.setProgress(value);
}
#Override
public void setProgressDialogMessage(String message) {
pd.setMessage(message);
}
});
new MyAsyncTask(progressDialogUtil).execute();
Finally when you navigate to a new Activity you can use the same Singleton Instance ProgressDialogUtil and change the listener to the new Activity now all AsyncTask events will be handled to the new Activity and the dialog can be opened/closed via a button through this singleton class like below:
ProgressDialog pd = new ProgressDialog(this);
ProgressDialogUtil progressDialogUtil = ProgressDialogUtil.getInstance();
progressDialogUtil.setListener(new ProgressDialogUtil.ProgressDialogUtilListener()
{
#Override
public void showProgressDialog() {
if (!pd.isShowing())
pd.show();
}
#Override
public void dismissProgressDialog() {
if (pd.isShowing())
pd.dismiss();
}
#Override
public void updateProgressDialog(int value) {
pd.setProgress(value);
}
#Override
public void setProgressDialogMessage(String message) {
pd.setMessage(message);
}
});
//Show Progress Dialog from a Button Click
showButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
progressDialogUtil.showProgressDialog();
}
});
//Dismiss Progress Dialog from a Button Click
dismissButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
progressDialogUtil.dismissProgressDialog();
}
});

You can have a Live data in any singleton class like below to share the progress between activities.
object ProgressHelper {
val progress = MutableLiveData<Int>()
}
Then update the progress values from the AsyncTask like below:
override fun onProgressUpdate(vararg values: Int?) {
super.onProgressUpdate(*values)
ProgressHelper.progress.value = 100
}
In your activity you can observe the progress like below:
ProgressHelper.progress.observe(this, Observer {
val progress = it
})

Related

AsyncTask to update ui counter which is invoked in other class in android

I need to update file upload count dynamically into Ui progressbar which is invoked in other class method. How can communicate between AsyncTask doInBackground() and myClass.uploadFiles(). please help me
this is activity
public class MyActivity extends AppCompatActivity {
private ProgressDialog dialog = null;
String status;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file);
CounteTask task = new CounteTask();
task.execute();
}
private class CounteTask extends AsyncTask<String, Integer, Void> {
#Override
protected Void doInBackground(String... params) {
try {
status = myClass.uploadFiles(MyActivity.this);
} catch (Exception e) {
dialog.dismiss();
}
return null;
}
#Override
protected void onPostExecute(Void resultGetlogin) {
dialog.dismiss();
}
protected void onPreExecute() {
dialog = ProgressDialog.show(Sync_Records.this, "", "Please wait, file count..");
}
protected void onProgressUpdate(Integer... values) {
}
}
}
MyClass.java from here need to update ui thread.
public void MyClass{
public static String uploadFiles(Context context) {
for (count=0 ; count <= 10; count++) {
try {
upload(count); //need to show each count of file which is currently uploading
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return status;
}

Android, showProgress() and hideProgress() properly

I'm new on android development, so decided to learn simple login using MVP architectural pattern, in general everything is working fine, as checking user credentials, calling repository...etc.
However, only the implementations of showProgress() & hideProgress() that works in a weird way, for me at least.
Note that the showProgress() only works if the user inter valid credentials.
Thanks.
// Presenter Class
package com.example.mvp.login;
import android.util.Log;
import com.example.mvp.login.LoginContract;
import com.example.mvp.utils.SharedPrefManager;
public class LoginPresenterImpl implements LoginContract.Presenter{
SharedPrefManager sharedPrefManager;
private LoginContract.View view;
private LoginContract.Service service;
public LoginPresenterImpl(LoginContract.View view, LoginContract.Service service) {
this.view = view;
this.service = service;
sharedPrefManager = SharedPrefManager.getInstance(view.getContext());
}
#Override
public void onLoginClicked() {
String username = view.getUsername();
if (username.isEmpty()){
view.showUsernameError();
view.hideProgress();
return;
}
String password = view.getPassword();
if (password.isEmpty()){
view.showPasswordError();
view.hideProgress();
return;
}
view.showProgress(); // this method is called, but doesn't show in the UI Thread
boolean loginSucceeded = service.login(username, password);
if (loginSucceeded){
sharedPrefManager.userLogin(username);
view.navigateHome();
return;
}
view.hideProgress();
view.showLoginError();
}
#Override
public void isUserLoggedIn() {
if(sharedPrefManager.isLoggedIn())
view.navigateHome();
}
}
// View Class
public class LoginActivity extends AppCompatActivity implements LoginContract.View{
private EditText ed_username, ed_password;
private Button login;
private TextView signUp;
private ProgressBar progressBar;
LoginContract.Presenter presenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView(this);
presenter = new LoginPresenterImpl(this, new LoignServiceImpl());
presenter.isUserLoggedIn();
login.setOnClickListener(click);
}
View.OnClickListener click = new View.OnClickListener() {
#Override
public void onClick(View v) {
switch(v.getId()){
case R.id.login:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
presenter.onLoginClicked();
}
}, 1200);
}
}
};
public void initView(LoginActivity view){
ed_username = view.findViewById(R.id.username);
ed_password = view.findViewById(R.id.password);
login = view.findViewById(R.id.login);
signUp = view.findViewById(R.id.sign_up);
progressBar = view.findViewById(R.id.progressBar);
}
#Override
public String getUsername() {
return ed_username.getText().toString();
}
#Override
public String getPassword() {
return ed_password.getText().toString();
}
#Override
public void showProgress() {
progressBar.setVisibility(View.VISIBLE);
}
#Override
public void hideProgress() {
progressBar.setVisibility(View.GONE);
}
#Override
public void showUsernameError() {
ed_username.setError("Must not be empty");
}
#Override
public void showPasswordError() {
ed_password.setError("Must not be empty");
}
#Override
public void navigateHome() {
Intent intent = new Intent(this, HomeActivity.class);
startActivity(intent);
finish();
}
#Override
public void showLoginError() {
Toast.makeText(this,
"User not Found",
Toast.LENGTH_SHORT).show();
}
#Override
public Context getContext() {
return this;
}
}
Thanks to h4rd4r7c0r3 and Ionut J. Bejan, for highlighting several aspects i wasn't a ware of, in particular Working Thread(UI THREAD) and Another Thread(Background Thread).
Although i don't know yet how to implement them very well, i found way after searching the internet.
The main scenario are:
When the user enter username and password, UI should show indication
(Progress Bar) checking credentialiy of the user, implementing
showProgress().
When the checking is finished, UI should stop the indication.
implementing hideProgress().
An action to be taken based on the result, for example: Navigate to
new Activity or Toast "Wrong Username/Passowrd".
//LoginActivity
#Override
public void showProgress() {
progressBar.setVisibility(View.VISIBLE);
}
#Override
public void hideProgress() {
progressBar.setVisibility(View.GONE);
}
// LoginPresenter
public void onLoginClicked() {
String username = view.getUsername();
if (username.isEmpty()){
view.showUsernameError();
view.hideProgress();
return;
}
String password = view.getPassword();
if (password.isEmpty()){
view.showPasswordError();
view.hideProgress();
return;
}
view.showProgress();
service.login(username,password, this);
}
#Override
public void isUserLoggedIn() {
if(sharedPrefManager.isLoggedIn())
view.navigateHome();
}
// implementing onFinished from FinishedListiner interface, to capture the result
#Override
public void onFinished(boolean bool) {
view.hideProgress();
if (bool){
sharedPrefManager.userLogin(view.getUsername());
view.navigateHome();
return;
}
view.showLoginError();
}
// Service, which will connect to the datasource
public class LoginServiceImpl implements LoginContract.Service {
UserRepository userRepository;
#Override
public void login(final String username, final String password, final FinishedListiner listener) {
userRepository = UserRepositoryImpl.getInstance();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// The method which will be used in the presenter class.
listener.onFinished(userRepository.checkUser(username, password));
}
}, 1200);
}
Try this below snippet :
Step 1:- Create BaseActivity extend to AppCompactActivity
Step 2:-Setting BaseActivity as per your requirement
Step 3:-Create Instance of your Progress Dialog
Step 4:-Create function showProgress()
Like:-
private fun showProgress(){
if(!progress.isShowing){
progress.show()
}
}
Step 5:- Create function HideProgress()
Like:-
private fun hideProgress(){
if(progress.isShowing){
progress.dismiss()
}
}
And use as per your requirement.
Your View just run presenter on another thread. See your Handler. Then it update the view and can not access to the UI. To fix this, just make sure your showProgress() is doing work on UI thread.
runOnUiThread(new Runnable() {
public void run() {
//show your proress here.
}
});

Use the same AsyncTask to update different views

I have a button on 6 different Activities. Clicking on that button does almost the same task with different params depending on the Activity.
This will be done using an AsyncTask and in onPostExecute() the button state will be changed.
someButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Task().execute("param1", "param2");
}
}
private class Task extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
//background task using params[0], params[1]
return "success" or "error";
}
#Override
protected void onPostExecute(String result) {
if (result == "success") {
//change the someButton state
}else{
//show an error message
}
}
Instead of having the same AsyncTask in all the 6 Activities, how can I use a single Asynctask from all the Activities and change the respective view?
You should create Task, with methods onSuccess, onFailure and override them.
public class Task extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
//background task using params[0], params[1]
return "success" or "error";
}
#Override
protected void onPostExecute(String result) {
if (result == "success") {
onSuccess(result);
}else{
onFailure(result);
}
}
protected void onSuccess(String result) {};
protected void onFailure(String result) {};
}
and then in activity use it like this:
someButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Task(){
#Override
protected void onSuccess(String result){
// do what you want
}
#Override
protected void onFailure(String result){
// do what you want
}
}.execute("param1", "param2");
}
}
Put your Task in its own file and make it public.
Create a callback interface:
public interface TaskCallback {
public void onSuccess(String result);
public void onFailure(String errorMessage);
}
Give such a callback to your Task:
public class Task extends AsyncTask<String, Void, String> {
private TaskCallback callback;
public Task(TaskCallback callback) {
this.callback = callback;
}
#Override
protected String doInBackground(String... params) {
//background task using params[0], params[1]
return "success" or "error";
}
#Override
protected void onPostExecute(String result) {
if (result == "success") {
callback.onSuccess(result);
} else{
callback.onFailure(errorMessage);
}
}
}
And then implement the callback when creating the Task instance in your activity:
someButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
private TaskCallback callback = new TaskCallback() {
#Override
public void onSuccess(String result) {
//change the someButton state
}
#Override
public void onFailure(String errorMessage) {
//show an error message
}
}
new Task(callback).execute("param1", "param2");
}
}

AsyncTask ProgressDialog stopped, after callback

this my task:
public class GetTask extends AsyncTask<String, Void, JSONObject> {
// callback
private Activity activity;
private AsyncTaskCompleteListener callback;
private AppUtils appUtils;
private ProgressDialog dialog;
private String object;
public GetTask(Activity act){
this.activity = act;
this.callback = (AsyncTaskCompleteListener)act;
}
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(activity);
dialog.setTitle("Load...");
dialog.setMessage("Data...");
dialog.setCancelable(true);
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
cancel(false);
}
});
dialog.show();
}
protected JSONObject doInBackground(String... url) {
String link = url[0];
object = AppUtils.cutStringAfter(link);
link = AppUtils.cutStringBefore(link);
return AppUtils.getJSONData(link);
}
protected void onPostExecute(JSONObject result) {
if (null != dialog && dialog.isShowing()) {
dialog.dismiss();
}
super.onPostExecute(result);
callback.onTaskComplete(result, object);
}
#Override
protected void onCancelled()
{
if (this.dialog != null) {
this.dialog.dismiss();
}
}
}
onTaskComplete call other procedure for parse data:
#Override
public void onTaskComplete(JSONObject result, String object) {
try {
setDBDATA(result, object);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Dialog dismissed after complete procedure setDBDATA(result, object);, while works setDBDATA, ProgressDialog freezes.
How close ProgressDialog before callback procedure, or prevent freeze him?
in opPostExecute() set an onDismissListener() on your ProgressDialog and call the call back method from onDismiss()
Something like this:-
dialog.setOnDismissListener(new OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
callback.onTaskComplete(result, object);
}
});
Hope this helps.
If setDBDATA will take long time, then move it to doInBackground.

ProgressDialog does not disappear in android app

I have an android application which in its main activity, data are adapted from sqlite db and shown in list view. I tried to use Progress dialog to show 'loading' message to user during fetching data from db. But the dialog does not disappear.
Here is the code :
public class BirthdayAlarmActivity extends ListActivity {
List<BirthdayContact> listofAvailableBirthdays;
ProgressDialog pDialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.birthday_list);
listofAvailableBirthdays=new ArrayList<BirthdayContact>();
ReinitializeList();
}
#Override
protected void onResume() {
ReinitializeList();
}
void ReinitializeList()
{
new LoadListView().execute();
if(listofAvailableBirthdays.size()>0)
{
//get ready the adapter
ArrayAdapter<BirthdayContact> ara=
new MyArrayAdapter(BirthdayAlarmActivity.this,listofAvailableBirthdays);
//set the adapter
setListAdapter(ara);
}
}
public class LoadListView extends AsyncTask<Void, Void, Void>
{
//ProgressDialog pDialog;
#Override
protected void onPreExecute() {
// Showing progress dialog before sending http request
pDialog = new ProgressDialog(
BirthdayAlarmActivity.this);
pDialog.setMessage("Please wait..");
pDialog.setIndeterminate(true);
pDialog.setCancelable(false);
pDialog.show();
}
protected Void doInBackground(Void... unused) {
runOnUiThread(new Runnable() {
public void run() {
// increment current page
listofAvailableBirthdays.clear();
listofAvailableBirthdays=BirthdayHandler.GetTenBirthDays(BirthdayAlarmActivity.this);
}
});
return (null);
}
protected void onPostExecute(Void unused) {
// closing progress dialog
pDialog.dismiss();
}
}
I'm not familiar with the technique you're using, but I'll share what works for me:
final ProgressDialog progress = ProgressDialog.show(activity, "",
activity.getString(R.string.please_wait), true);
new Thread(new Runnable() {
#Override
public void run()
{
try {
--- network activity to retrieve information ---
}
finally {
activity.runOnUiThread(new Runnable() {
#Override
public void run()
{
if ((progress != null) && progress.isShowing())
progress.dismiss();
}
});
}
}
}).start();
I think the problem here is that you're referring to your pDialog and trying to create it in a different class than the one you've declared it in.
You should try using showDialog, dismissDialog and onCreateDialog methods to add a layer of abstraction and that the dialog is being called in the correct class/thread. You can use a Handler aswell as an alternative.
try something like this:
public class BirthdayAlarmActivity extends ListActivity {
List<BirthdayContact> listofAvailableBirthdays;
ProgressDialog pDialog;
static final int LOADING_DIALOG = 1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.birthday_list);
listofAvailableBirthdays=new ArrayList<BirthdayContact>();
ReinitializeList();
}
#Override
protected void onResume() {
ReinitializeList();
}
void ReinitializeList()
{
new LoadListView().execute();
if(listofAvailableBirthdays.size()>0)
{
//get ready the adapter
ArrayAdapter<BirthdayContact> ara=
new MyArrayAdapter(BirthdayAlarmActivity.this,listofAvailableBirthdays);
//set the adapter
setListAdapter(ara);
}
}
#Override
protected Dialog onCreateDialog(int id)
{
switch(id)
{
case LOADING_DIALOG:
// Showing progress dialog before sending http request
pDialog = new ProgressDialog(
BirthdayAlarmActivity.this);
pDialog.setMessage("Please wait..");
pDialog.setIndeterminate(true);
pDialog.setCancelable(false);
return pDialog;
}
}
public class LoadListView extends AsyncTask<Void, Void, Void>
{
#Override
protected void onPreExecute() {
showDialog(LOADING_DIALOG);
}
protected Void doInBackground(Void... unused) {
runOnUiThread(new Runnable() {
public void run() {
// increment current page
listofAvailableBirthdays.clear();
listofAvailableBirthdays=BirthdayHandler.GetTenBirthDays(BirthdayAlarmActivity.this);
}
});
return (null);
}
protected void onPostExecute(Void unused) {
dismissDialog(LOADING_DIALOG);
}
}
If this fails, you should look int using messaging via the Handler class.

Categories

Resources