Using threads to apply UI changes in android - java

I ran into a problem and need some help. I want to remove some user's files after a button click and also show the files removing progress (in progressbar) and also show some Fancy UI. First i changed the layout after button click and hide some elements and visible the others. after that i called methods to remove files. The problem is that i can not see any UI changes and system hangs until all user file removed and after that based on my scenario it go to another activity. I've google around and found that i should use thread or UI thread but exactly don't know how. Here is my code :
new Thread() {
public void run() {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
ProgressBar spinner;
spinner = (ProgressBar) findViewById(R.id.progressBar);
listview.setVisibility(View.GONE);
spinner.setVisibility(View.VISIBLE);
preresult.setVisibility(View.VISIBLE);
resulttxt.setVisibility(View.VISIBLE);
wv.setVisibility(View.VISIBLE);
btnClear.setVisibility(View.GONE);
wv.loadUrl("file:///android_asset/rocket.gif");
resulttxt.setText("");
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
Thread b = new Thread() {
#Override
public void run() {
Long TotalJunk = 0L;
for (Apps social : checkedSocial) {
if (social.getName() == "Telegram") {
preresult.setText("Calculating Files :");
resulttxt.setText("Telegram");
preresult.setText("Removing Files...");
clearMediashistory(social.path);
TotalJunk = TotalJunk + social.junksize;
}
}
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor editor = pref.edit();
editor.putString("FreeUp", formatSize(TotalJunk));
//commits your edits
editor.commit();
}
};
b.start();
What is wrong with my code. Is there any better method to do that?

Use AsyncTask instead of Thread
https://developer.android.com/reference/android/os/AsyncTask.html
Android AsyncTask example and explanation

Try
new AsyncTask<String, String, String> () {
#Override
protected void onPreExecute() {
//show loader if requried
}
#Override
protected String doInBackground(String... params) {
Long TotalJunk = 0L;
for (Apps social : checkedSocial) {
if (social.getName() == "Telegram") {
preresult.setText("Calculating Files :");
resulttxt.setText("Telegram");
preresult.setText("Removing Files...");
clearMediashistory(social.path);
TotalJunk = TotalJunk + social.junksize;
}
}
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor editor = pref.edit();
editor.putString("FreeUp", formatSize(TotalJunk));
//commits your edits
editor.commit();
}
#Override
protected void onPostExecute(String result){
ProgressBar spinner;
spinner = (ProgressBar) findViewById(R.id.progressBar);
listview.setVisibility(View.GONE);
spinner.setVisibility(View.VISIBLE);
preresult.setVisibility(View.VISIBLE);
resulttxt.setVisibility(View.VISIBLE);
wv.setVisibility(View.VISIBLE);
btnClear.setVisibility(View.GONE);
wv.loadUrl("file:///android_asset/rocket.gif");
resulttxt.setText("");
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTER);

Related

ProgressDialog in another AsyncTask class not showing when called from Activity

I have a class called RestClient that gets some information from my webService and then return and I'm trying to make a Progress dialog run while it is accessing the internet. And as I use this class in more than one place I won't make in the Activity itself. Here is my RestClient class:
public class RestClient extends AsyncTask<URL, String, String> {
private Context context;
private String string;
public RestClient(Context context, String string)
{
this.context = context;
this.string = string;
}
#Override
protected void onPreExecute() {
dialog = ProgressDialog.show(context, "Buscando seu Produto","Por favor, espere um momento...",true ,false);
//I've already tried:
/*ProgressDialog dialog = new ProgressDialog(context);
dialog.setTitle("Buscando seu Produto");
dialog.setMessage("Por favor, espere um momento...");
dialog.setIndeterminate(true);
dialog.setCancelable(false);*/
dialog.show();
super.onPreExecute();
}
#Override
protected String doInBackground(URL... params) {
try {
//Some WebService gets and Json conversions using my string variable
//and some Thread.sleep that counts 2000 miliseconds to do all the queries
dialog.dismiss();
} catch (IOException | InterruptedException |JSONException e) {
e.printStackTrace();
dialog.dismiss();
return e.getMessage();
}
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
}
And in my activity I call the class RestClient when I click a button like this:
--- EDIT : I forgot to mention that I have an AlertDialog in this same activity that CAN be shown sometimes before and after the ProgressDialog ---
private Button buttonConfirm;
private EditView evString;
private String theString;
private String returnFromExecute;
private RestClient restClient;
private AlertDialog.Builder dialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_access_webservice);
evString = (EditText) findViewById(R.id.editViewMyString);
buttonConfirm = (Button) findViewById(R.id.buttonConfirm);
dialog = new ProgressDialog(IdentificacaoDeProdutoActivity.this);
dialog.setTitle("Error");
dialog.setMessage("Please try again");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
buttonConfirmar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
theString = evString.getText().toString();
if(!(theString!=null && theString.trim().length()>0)) //To check if theString is not null
{
dialog.show();
}
restClient = new RestClient(AccessWebserviceActivity.this, theString);
//Then I call execute and put a Thread.sleep a bit longer to compensate the ones I have in my doInBackground
restClient.execute();
try {
Thread.sleep(2050);
} catch (Exception e) {
dialog.show();
return;
}
}
}
}
The problem is that my ProgressDialog never shows. I've already tried getParent(), getApplication() and getApplicationContext() instead of AccessWebserviceActivity.this but none have worked. Someone Have any idea what is happening and what should I do?
you have not created progress dialog try this.
ProgressDialog dialog;
#Override
protected void onPreExecute() {
dialog= new ProgressDialog(context);
dialog.setMessage("on Progress");
dialog.show();
super.onPreExecute();
}
returnFromExecute = restClient.get();
Remove that statement. You have already:
restClient.execute();
That should do.
The result of doInBackground() you should handle in onPostExecute(). It cannot be handled or retrieved in onCreate().
You need to call
dialog = ProgressDialog.show(context, "Buscando seu Produto","Por favor, espere um momento...",true ,false);
and remove
dialog.show();
Also put your dialog.dismiss(); method in onPostExecute(). This dialog.dismiss() method is good in catch block but what's its purpose if you are calling this method in try block. It will remove progress dialog as soon as you call this AsyncTask.
After a lot of researches about Threads and Process I found out that I had to encapsulate the all the code I have after my
RestClient.execute in a
new Thread(new Runnable() { public void run() { // My code } });
so that the execution of the code happened in background as well as the WebService query.
EDIT:
Even if creating a new Thread works, it is not recommended! The right thing to do would be to create another class that extends AsyncTask to do job.

Android move from one activity to another

I was having some problem for Android activity transition. Basically what I am trying to do is share text to Twitter. However, when I open up the twitter content, it took quite a few seconds to load up the content and resulting in the white blank activity for a few seconds.
And here is my codes, when my button onClick, I am executing the loading dialog:
ivTwitterShare.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Thread newThread = new Thread() {
#Override
public void run() {
try {
super.run();
sleep(10000);
} catch (Exception e) {
} finally {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri
.parse(tweetUrl));
startActivity(intent);
progressDialog.dismiss();
}
}
};
newThread.start();
new LoadTwitterTask().execute();
}
});
private class LoadTwitterTask extends AsyncTask<Void, Integer, Void> {
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(context, "Loading Twitter...",
"Retrieving Twitter information, please wait...", false,
false);
EventDialogueBox.customizeDialogueBox(context, progressDialog);
}
#Override
protected Void doInBackground(Void... params) {
try {
synchronized (this) {
int counter = 0;
while (counter <= 4) {
this.wait(50);
counter++;
publishProgress(counter * 25);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
progressDialog.setProgress(values[0]);
}
#Override
protected void onPostExecute(Void result) {
}
}
However, my problem now is the white blank page before the content is loaded up still there. What I wanted is firstly, the loading dialog will show. Then, at the same time, the twitter intent is loading. Once finish loaded up the content, then dialog will be dismissed.
Any ideas?
Thanks in advance.

How can I effectively display a progress bar while my app pastes a file? Android

I am working on a small file manager for school and I am trying to get it to display the progress while pasting the file into the new location. How can I get it to do this? I understand how to set progress in a dialog, but what would you use for the file? I currently have it so the max of the progress bar is the number of files the user is trying to paste, but that only works well when the user is pasting multiple files and not just one. Is there a way to update the number of the progress bar with the number of bytes pasted or something similar?
Code:
new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < mClipboard.size(); i++) {
final int index = i;
// Copy, or cut, each file or directory into the destination directory
final File newFile = copy(getFile(i), dest, false);
scanImage(newFile, context);
context.runOnUiThread(new Runnable() {
#Override
public void run() {
// Update the adapter and increment the progress dialog
if (newFile != null) adapter.add(newFile);
// Increment the progress dialog
dialog.setProgress(index);
}
});
}
context.runOnUiThread(new Runnable() {
#Override
public void run() {
// Remove paste option from action bar
context.invalidateOptionsMenu();
// Clear the clipboard
clear();
// Close the dialog
dialog.dismiss();
}
});
}
}).start();
I think you are relatively new to android, there is a class called the async task. You can use i to run any background operation. And displaying a dialog while its running in the background is as simple as:
public static final int DIALOG_DOWNLOAD_PROGRESS = 0;
private ProgressDialog mProgressDialog;
#Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_DOWNLOAD_PROGRESS:
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setMessage("Loading..");
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(false);
mProgressDialog.show();
return mProgressDialog;
default:
return null;
}
}
Then write an async task to update progress..
private class DownloadZipFileTask extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
showDialog(DIALOG_DOWNLOAD_PROGRESS);
}
#Override
protected String doInBackground(String... urls) {
//Your background task code here.
publishProgress("" + progress);
}
protected void onProgressUpdate(String... progress) {
mProgressDialog.setProgress(Integer.parseInt(progress[0]));
}
#Override
protected void onPostExecute(String result) {
dismissDialog(DIALOG_DOWNLOAD_PROGRESS);
}
}
You have to use async task to paste the file in the background.
Here is the good code exaple for you: http://www.vogella.com/tutorials/AndroidBackgroundProcessing/article.html
Android dowumenation:
http://developer.android.com/reference/android/os/AsyncTask.html

Why I can't start a thread 2x in my Activity?

I push a web service call in my activity to a thread (shown below). The first time I do this in the activity it works fine (gets the text from my edittext and loads the service to get lat/lng data)
But when I click the back button (emulator) and try to fire off this thread a second time it blows up after the .start(); in my click handler. What might I be doing wrong here? thanks
private Thread getLocationByZip = new Thread() {
public void run() {
try {
EditText filterText = (EditText) findViewById(R.id.zipcode);
Editable zip = filterText.getText();
LocationLookupService locationLookupService = new LocationLookupService();
selectedLocation = locationLookupService.getLocationByZip(zip.toString());
locationHandler.post(launchFindWithLocationInfo);
} catch (Exception e) {
}
}
};
private Runnable launchFindWithLocationInfo = new Runnable() {
#Override
public void run() {
try {
Intent abc = new Intent(LocationLookup.this, FindWithLocation.class);
startActivity(abc);
} catch (Exception e) {
}
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.location);
locationHandler = new Handler();
findViewById(R.id.findbyzip).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getLocationByZip.start();
}
});
}
Update
After the great advice I went with an AsyncTask so if anyone finds this going forward the above thread/handler model looks something like the below as an asynctask
private class LocationLookupTask extends AsyncTask<String, Void, Location> {
private ProgressDialog dialog;
#Override
protected void onPreExecute() {
this.dialog = ProgressDialog.show(LocationLookup.this, "", "Loading...");
}
#Override
protected Location doInBackground(String... zips) {
Location selectedLocation = null;
for (String zip : zips) {
LocationLookupService locationLookupService = new LocationLookupService();
selectedLocation = locationLookupService.getLocationByZip(zip);
}
return selectedLocation;
}
#Override
protected void onPostExecute(Location location) {
this.dialog.dismiss();
((AppDelegate) getApplicationContext()).setSelectedLocation(location);
Intent abc = new Intent(LocationLookup.this, FindWithLocation.class);
startActivity(abc);
}
}
Now to call this in the onclick you would do this
findViewById(R.id.findbyzip).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
EditText filterText = (EditText) findViewById(R.id.zipcode);
Editable zip = filterText.getText();
LocationLookupTask task = new LocationLookupTask();
task.execute(new String[]{zip.toString()});
}
});
You can't start a thread twice:
It is never legal to start a thread more than once.
Taken from Thread.start().
So, you need to create a new thread and start that one.
You can not call twice the start method of the Thread class, I suggest you also control the logic within the method onCreate since according to the life cycle of an Activity that method may be called by Android lifecycle Activity Manager.
Furthermore i suggest you to avoid this approach and consider to use the AsyncTask provided by the Android SDK.
http://developer.android.com/reference/android/os/AsyncTask.html
If you really want to do this without creating a new class or using AsyncTask, you could just make a method to get a new Thread on each call:
private Thread getLocationByZip;
private void getLocation() {
getLocationByZip = new Thread() {
public void run() {
try {
EditText filterText = (EditText) findViewById(R.id.zipcode);
Editable zip = filterText.getText();
LocationLookupService locationLookupService = new LocationLookupService();
selectedLocation = locationLookupService.getLocationByZip(zip.toString());
locationHandler.post(launchFindWithLocationInfo);
} catch (Exception e) {
}
}
};
getLocationByZip.start();
}
Then replace getLocationByZip.start() in your code with getLocation(). However, I agree that an AsyncTask would be a better way to go, though this would work for you.

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

I get this error "Can't create handler inside thread that has not called Looper.prepare()"
Can you tell me how to fix it?
public class PaymentActivity extends BaseActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.payment);
final Button buttonBank = (Button) findViewById(R.id.buttonBank);
buttonBank.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
progressDialog = ProgressDialog.show(PaymentActivity.this, "",
"Redirecting to payment gateway...", true, true);
new Thread() {
public void run() {
try {
startPayment("Bank");
} catch (Exception e) {
alertDialog.setMessage(e.getMessage());
handler.sendEmptyMessage(1);
progressDialog.cancel();
}
}
}.start();
}
});
StartPayment Method:
private void startPayment(String id) {
Bundle b = getIntent().getExtras();
final Sail sail = b.getParcelable(Constant.SAIL);
final Intent bankIntent = new Intent(this, BankActivity.class);
try {
Reservation reservation = RestService.createReservation(
sail.getId(),
getSharedPreferences(Constant.PREF_NAME_CONTACT, 0));
bankIntent.putExtra(Constant.RESERVATION, reservation);
// <workingWithDB> Storing Reservation info in Database
DBAdapter db = new DBAdapter(this);
db.open();
#SuppressWarnings("unused")
long rowid;
rowid = db.insertRow(sail.getId(), sail.getFrom(),
sail.getTo(), sail.getShip(), sail.getDateFrom().getTime(),
sail.getPrice().toString(), reservation.getId().floatValue());
db.close();
// </workingWithDB>
String html = PaymentService.getRedirectHTML(id, reservation);
bankIntent.putExtra(Constant.BANK, html);
} catch (Exception e) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog alertDialog = builder.create();
alertDialog.setMessage(e.getMessage());
alertDialog.show();
}
startActivity(bankIntent);
}
You should know that when you try to modify your UI , the only thread who can do that is the UiThread.
So if you want to modify your UI in another thread, try to use the method: Activity.runOnUiThread(new Runnable);
Your code should be like this :
new Thread() {
public void run() {
YourActivity.this.runOnUiThread(new Runnable(){
#Override
public void run(){
try {
startPayment("Bank");//Edit,integrate this on the runOnUiThread
} catch (Exception e) {
alertDialog.setMessage(e.getMessage());
handler.sendEmptyMessage(1);
progressDialog.cancel();
}
});
}
}
}.start();
I assume you create a Handler in startPayment() method. You can't do that, as handlers can be created on th UI thread only. Just create it in your activity class.
Instead of new Thread() line, try giving
this.runOnUiThread(new Runnable() {
you cant change any UI in thread you can use runOnUIThread or AsyncTask for more detail about this click here
I've found that most thread handling can be replaced by AsyncTasks like this:
public class TestStuff extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonBank = (Button) findViewById(R.id.button);
buttonBank.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
new StartPaymentAsyncTask(TestStuff.this).execute((Void []) null);
}
});
}
private class StartPaymentAsyncTask extends AsyncTask<Void, Void, String> {
private ProgressDialog dialog;
private final Context context;
public StartPaymentAsyncTask(Context context) {
this.context = context;
}
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(context);
// setup your dialog here
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setMessage(context.getString(R.string.doing_db_work));
dialog.setCancelable(false);
dialog.show();
}
#Override
protected String doInBackground(Void... ignored) {
String returnMessage = null;
try {
startPayment("Bank");
} catch (Exception e) {
returnMessage = e.getMessage();
}
return returnMessage;
}
#Override
protected void onPostExecute(String message) {
dialog.dismiss();
if (message != null) {
// process the error (show alert etc)
Log.e("StartPaymentAsyncTask", String.format("I received an error: %s", message));
} else {
Log.i("StartPaymentAsyncTask", "No problems");
}
}
}
public void startPayment(String string) throws Exception {
SystemClock.sleep(2000); // pause for 2 seconds for dialog
Log.i("PaymentStuff", "I am pretending to do some work");
throw new Exception("Oh dear, database error");
}
}
I pass in the Application Context to the Async so it can create dialogs from it.
The advantage of doing it this way is you know exactly which methods are run in your UI and which are in a separate background thread. Your main UI thread isn't delayed, and the separation into small async tasks is quite nice.
The code assumes your startPayment() method does nothing with the UI, and if it does, move it into the onPostExecute of the AsyncTask so it's done in the UI thread.
Try
final Handler handlerTimer = new Handler(Looper.getMainLooper());
handlerTimer.postDelayed(new Runnable() {
public void run() {
......
}
}, time_interval});

Categories