For a few days a have some problem.
I need to show simple ProgressBar (not dialog) while doing some stuff in main thread...
I thought its a very simple question, but i cant do this, help me please.
First i tried simple setVisibility(View.VISIBLE) before and setVisibility(View.GONE) after.
But this is doing in the same thread, and ProgressBar freezed while my function working.
Now i have this code, but i have some error, and i dont know whats wrong..
my simple layout :
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ProgressBar
android:id="#+id/loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" />
</FrameLayout>
i have a base activity :
public class BaseActivity extends Activity {
public ProgressBar loading;
public class ProgressBarShow extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... unused) {
return(null);
}
protected void onProgressUpdate() {
}
protected void onPreExecute() {
loading.setVisibility(View.VISIBLE);
}
protected void onPostExecute() {
}
}
}
and finally my working activity , which extends BaseActivity
public class SearchActivity extends BaseActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loading = (ProgressBar) findViewById(R.id.loading);
new ProgressBarShow().execute();
//doing long stuff
//new ProgressBarHide().execute(); there isnt, but sense the same
}
}
I have many activities, which need progress bar, thats why i have created BaseActivity,
to not to dublicate code.
I need to do long work (stuff function) in main thread, because i want to freeze main window and not to allow user do anything (click button etc..), just show working ProgressBar.
Whats wrong in my example? Or give me some advice how can i do this better
class ProgressTask extends AsyncTask<Integer, Integer, Void>{
ProgressBar progress;
Context context;
public ProgressTask(ProgressBar progress, Context context) {
this.progress = progress;
this.context = context;
}
#Override
protected void onPreExecute() {
// initialize the progress bar
// set maximum progress to 100.
progress.setMax(100);
}
#Override
protected Void doInBackground(Integer... params) {
// get the initial starting value
int start=params[0];
// increment the progress
for(int i=start;i<=100;i+=5){
try {
boolean cancelled=isCancelled();
//if async task is not cancelled, update the progress
if(!cancelled){
publishProgress(i);
SystemClock.sleep(1000);
}
} catch (Exception e) {
Log.e("Error", e.toString());
}
}
return null;
}
//Has direct connection to UI Main thread
//Called everytime publishProgress(int) is called in doInBackground
#Override
protected void onProgressUpdate(Integer... values) {
progress.setProgress(values[0]);
Toast.makeText(context, "test"+values[0], Toast.LENGTH_SHORT).show();
}
#Override
protected void onPostExecute(Void result) {
// async task finished
Log.v("Progress", "Finished");
}
#Override
protected void onCancelled() {
progress.setMax(0);
}
}
Use AsyncTask http://developer.android.com/guide/topics/fundamentals/processes-and-threads.html Put your ProgressBar in it, while all work is doing in main thread
Related
I am using this code, everything are working fine, but progressbar is not showing. I want to block my ui during the method implementation and want to show progressbar. I want to get behaviour like progressDialog.
Here is my method
public void effct(int effectNo) {
final int finalEffectNO = effectNo;
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
progressLayout.setVisibility(View.VISIBLE);
progressLayoutLinear.setVisibility(View.VISIBLE);
Thread thread = new Thread(){
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
imageViewFragment.applyEffect(finalEffectNO);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
progressLayout.setVisibility(View.GONE);
progressLayoutLinear.setVisibility(View.GONE);
}
});
}
};
thread.start();
}
My xml code for progressLayout
<LinearLayout
android:id="#+id/progressBarLinearLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/colorPrimaryDark"
android:gravity="center"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:padding="12dp"
android:visibility="gone"
android:orientation="horizontal">
<ProgressBar
android:id="#+id/progressBar"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginRight="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Loading"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:textSize="18sp"/>
</LinearLayout>
For above your requirement you must use ProgressDialog for same, here is an example
Example
Try using an AsyncTask instead of Thread, something like this :
new AsyncTask<Void, Void, Void>() {
#Override
protected void onPreExecute() {
progressLayoutLinear.setVisibility(View.VISIBLE);
}
#Override
protected Void doInBackground(final Void ... params ) {
runOnUiThread(new Runnable() {
#Override
public void run() {
imageViewFragment.applyEffect(finalEffectNO);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}
});
return null;
}
#Override
protected void onPostExecute( final Void result ) {
progressLayoutLinear.setVisibility(View.GONE);
}
}.execute();
Hope this helps
There’s a few ways to solve your problem - check this video for more information. The most basic approach might be an AsyncTask, which could look like this:
public class DummyAsyncTask extends AsyncTask<Void, Void, Void> {
private final Window window;
private final ProgressBar progressBar;
public DummyAsyncTask(Window window, ProgressBar progressBar) {
this.window = window;
this.progressBar = progressBar;
}
#Override protected void onPreExecute() {
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
progressBar.setVisibility(View.VISIBLE);
}
#Override protected Void doInBackground(Void... voids) {
// Do the heavy lifting.
}
#Override protected void onPostExecute(Void aVoid) {
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
progressBar.setVisibility(View.GONE);
}
}
You execute it by running new DummyAsyncTask(/* params */).execute();.
Do note that AsyncTask does not adhere to the lifecycle and holding a reference to a Context aware instance is just asking for trouble. A safer alternative might be using LiveData:
public void effect(int effectNo) {
// Show progress and disable user interaction here.
final ListData<Content> data = model.applyEffect(effectNo);
data.observe(this, (Observer<Content>) c -> {
// Apply results, hide progress & enable user interaction.
});
}
Given the above, you should be careful how you handle showing & hiding progress, so you don’t accidentally disable user interaction forever.
I have a progress bar and I do not want to incorporate a numerical value to show the loading of some content. I just want that the ProgressBar should appear, animate and then go away.
I used:
public void buttonClick(View v){
ProgressBar mProgress=(ProgressBar)findViewById(R.id.my_progress);
mProgress.setVisibility(VISIBLE); //line 1..
//loading data from web... takes time
mProgress.setVisibility(INVISIBLE); //line 2..
}
but when I run this code, both line 1 and line 2 executes, but the UI changes afterwards, which is not desired. I want that when the button is clicked, the progress bar should appear and when the data is downloaded from the web the progress bar should disappear.
I tried setting the visibility from another thread, but it didn't work as UI changes are not allowed in other threads.
You download your data in AsyncTask right? Put this code
private class DownloadData extends AsyncTask<Void, Void, Void>{
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgress.setVisibility(View.VISIBLE);
}
#Override
protected Void doInBackground(Void... params) {
// download your data here
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
mProgress.setVisibility(View.GONE);
}
}
The best way implement it by using an AsyncTask
MyTask.java
class MyTask extends AsyncTask<Void, Void, Void> {
ProgressDialog dialog;
Context context;
MyTask(Context context){
this.context=context;
}
#Override
protected void onPreExecute() {
dialog=new ProgressDialog(context);
dialog.setMessage("Please wait...");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.show();
}
#Override
protected Void doInBackground(Void... params) {
//do your task here
}
#Override
protected void onPostExecute(Void result) {
if(dialog.isShowing()){
dialog.dismiss();
}
}
}
You can start the task like this:
public void buttonClick(View v){
new MyTask(YourActivity.this).execute();
}
You can modify the AsyncTask accordingly to retrieve the result.
Hope it helps. :)
I seem to be going round in circles.
I have some code that even on a Galaxy S3 takes a few seconds to run. Drags data from database.
I want to add a progress bar popup (spinning circle) around this to give the user that the app is doing something.
I have tried Asyntasks elsewhere in app and work fine but for this type the main UI is not waiting for the Asyntask to finish before moving on and so the new activity that is called does not have all the data it needs and crashes.
Is AsyncTask the best way round this or is there an easier way to Puase the main Activity, show a progress bar and then move on once the long deley has been completed.
Thanks for time
UPDATE
public class UpdateDetailsAsyncTask extends AsyncTask<Void, Void, Boolean> {
private Context context;
private TaskCallback callback;
private ArrayList<Object> object;
private ProgressDialog progress;
public UpdateDetailsAsyncTask (
Context pContext,
ArrayList<Object> pObject,
TaskCallback pCallback) {
context = pContext;
callback = pCallback;
object = pObject;
}
#Override
protected void onPreExecute() {
Log.i("AsyncTask", "onPreExecuted");
progress = new ProgressDialog(context);
progress.setMessage(context.getResources().getString(R.string.loading));
progress.show();
}
#Override
protected Boolean doInBackground(Void... params) {
Log.i("Archery", "AsyncTask Excuted");
Log.i("Archery Scorepad", "Building Continue Round Details");
// Save Data to Database
return true;
}
protected void onPostExecute(Boolean result) {
Log.i("AsyncTask", "onPostExuted");
progress.dismiss();
callback.startNewActivity();
}
}
Task is called from main Activity
new UpdateDetailsAsyncTask(this, ArrayListOfObjects, this).exute();
UPDATE 2
..
UPDATE 3
The Code that does some work calls an a method within a Util Class which in calls a database class. I have log messages showing for all the rows of data I am saving to the database. It starts correctly and runs through it but the onPostExecute() appears to be called before the database method has completed.
Is my issue that I have nested classes within the activity and the task appears to have completed when the class below it has not?
Thanks
You must change to the next activity in onPostExecute from Asyntask
Yes!
Here is a simple code of AsuncTask
private class LoadImageAction extends AsyncTask<String, String, String>{
private Course course;
private ProgressBar pb;
public LoadImageAction(Course course, ProgressBar pb){
this.course = course;
this.pb = pb;
}
#Override
protected void onPreExecute(){
}
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
protected void onProgressUpdate(String... string){
}
#Override
protected void onPostExecute(String result){
}
}
You can run the action by
new LoadImageAction().execute();
In one of my app, I have a scenario where I need to do some background task. For doing that I am using Async Task. Also I am using custom progress dialog. Below is the layout of the custom progress dialog
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical|center_horizontal"
android:orientation="vertical" >
<ProgressBar
android:layout_width="60dp"
android:layout_height="60dp"
android:indeterminateDrawable="#drawable/progressloader"
android:layout_gravity="center"/>
<TextView
android:id="#+id/progressMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/black"
android:textSize="18sp"
android:text="Please wait...." />
</LinearLayout>
Everything works fine but when I try to set text to TextView then I am getting java NullPointerException.
AsyncTask code
private class InitialSetup extends AsyncTask<String, Integer, Long> {
ProgressDialog dialog = new ProgressDialog(getParent(),R.style.progressdialog);
#Override
protected void onPreExecute() {
dialog.show();
dialog.setContentView(R.layout.progressbar);
}
#Override
protected Long doInBackground(String... urls) {
// txtView.setText("Testing"); here I am getting the error
fetchDetails();
return 0;
}
#Override
protected void onPostExecute(Long result) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
populateUI(getApplicationContext());
}
}
MainActivity
public class SummaryActivity extends Activity {
final TextView txtView = (TextView)findbyid(R.id.progressMessage);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.accountsummary);
new InitialSetup().execute("");
}
}
If I understand correctly, your TextView of which you want to set the text can be found in the xml file progressbar.xml (i.e. R.layout.progressbar). This TextView can be obtained once the content view has been set (using setContentView()). In your code you set it before this call is been and the code of mussharapp, he is calling it to early. Namely, he calls it after the setContentView(R.layout.accountsummary) call which does not contain the TextView. Consequently, the variable txtView will be NULL and you will get a NullPointerException.
What you should do is the following:
Set the variable txtView in onPreExecute, after setContentView is called.
Based on Paresh Mayani's explanation: Use the runOnUiThread method.
For the code look down below:
private class InitialSetup extends AsyncTask<String, Integer, Long> {
ProgressDialog dialog = new ProgressDialog(getParent(),R.style.progressdialog);
// The variable is moved here, we only need it here while displaying the
// progress dialog.
TextView txtView;
#Override
protected void onPreExecute() {
dialog.show();
dialog.setContentView(R.layout.progressbar);
// Set the variable txtView here, after setContentView on the dialog
// has been called! use dialog.findViewById().
txtView = dialog.findViewById(R.id.progressMessage);
}
#Override
protected Long doInBackground(String... urls) {
// Already suggested by Paresh Mayani:
// Use the runOnUiThread method.
// See his explanation.
runOnUiThread(new Runnable() {
#Override
public void run() {
txtView.setText("Testing");
}
});
fetchDetails();
return 0;
}
#Override
protected void onPostExecute(Long result) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
populateUI(getApplicationContext());
}
}
Yes, because you are trying to set the TextView inside the doInBackground() method, and this is not allowed,
Why not allowed? Because There is a only one Thread running which is UI Main Thread, and it doesn't allowed to update UI from thread process. read more info here: Painless Threading
So there is a solution if you want to set the TextView inside the doInBackground() method, do the UI updating operations inside the runOnUiThread method.
Otherwise, suggestion is to do all the UI display/update related operations inside the onPostExecute() method instead of doInBackground() method of your AsyncTask class.
(TextView)findViewByid(R.id.progressMessage);
should only be executed after the command setContentView().
TextView txtView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.accountsummary);
**txtView = (TextView)findbyid(R.id.progressMessage);**
new InitialSetup().execute("");
}
Also you can only change UI elements in the main UI thread. doInBackground() is not in the main UI thread. Make UI changes in onPostExecute
public class InitialSetup extends AsyncTask<String, Integer, Long> {
private Activity activity;
ProgressDialog progressDialog;
public InitialSetup(Activity activity) {
this.activity = activity;
}
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(activity);
progressDialog.setMessage("Starting task....");
progressDialog.show();
}
#Override
protected Long doInBackground(String... urls) {
// do something
//
return 0;
}
#Override
protected void onPostExecute(Long result) {
progressDialog.dismiss();
//Perform all UI changes here
**textView.setText("Text#2");**
}
}
The explanations are correct: You are not to make UI changes in any thread except the thread which create the UI. But AsyncTask has a method called
onProgressUpdate()
which always will run in the UI Thread. So based on the modifications by dennisg your code should look like this:
private class InitialSetup extends AsyncTask<String, String, Long> {
ProgressDialog dialog = new ProgressDialog(getParent(),R.style.progressdialog);
// The variable is moved here, we only need it here while displaying the
// progress dialog.
TextView txtView;
#Override
protected void onPreExecute() {
dialog.show();
dialog.setContentView(R.layout.progressbar);
// Set the variable txtView here, after setContentView on the dialog
// has been called! use dialog.findViewById().
txtView = dialog.findViewById(R.id.progressMessage);
}
#Override
protected Long doInBackground(String... urls) {
publishProgress("Testing");
fetchDetails();
return 0;
}
#Override
protected void onPostExecute(Long result) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
populateUI(getApplicationContext());
}
#Override
protected void onProgressUpdate(String... update) {
if (update.length > 0)
txtView.setText(update[0]);
}
}
Note that the type of the parameter of onProgressUpdate is the second type given in AsyncTask!
Extra: To make your code more robust you should check if the progress dialog still exists before setting the text.
I have a function that dynamically creates all my user interface.
What can I do to show a dialog progress while my function is executing, and then dismiss the dialog when my function has finished the user interface?
This is an example of my code:
Sorry, I'm new to android, it is hard for me to understand some code... I will write my code here...
I have this function:
public void principal() {
//CODE TO CREATE ALL THE USER INTERFACE DYNAMICALLY
}
and I have the asyncTask like this:
public class EjecutarTarea extends AsyncTask<Void, Void, Void>
{
protected void onPreExecute() {
dialog = new ProgressDialog(StadioNenaActivity.this);
dialog.setMessage("Cargando..");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.show();
}
protected Void doInBackground(Void... unused) {
Principal();
return null;
}
#Override
protected void onProgressUpdate(Void... unused) {
}
#Override
protected void onPostExecute(Void unused) {
dialog.dismiss();
}
}
When I execute the asynctask in the onCreate, it crashes:
new EjecutarTarea().execute();
Use an AsyncTask. It gives a fantastic and easy way to load stuff in the background and them paste views in the main thread.
Here is an example of my AsyncTask:
private class LoadingTask extends AsyncTask<Void, Integer, Void> {
private ProgressBar mProg;
private TextView mLoadingText;
#Override protected void onPreExecute() {
mProg = (ProgressBar)findViewById(R.id.launcherbar_loadprogress);
mProg.setTouchDelegate(null);
mProg.setClickable(false);
mProg.setLongClickable(false);
mProg.setOnTouchListener(null);
mProg.setMax(100);
mLoadingText = (TextView) findViewById(R.id.launcheractivity_loadingwhat);
}
#Override protected Void doInBackground(Void... voids) {
try { Thread.sleep(1000); } catch (InterruptedException e) { }
setProgressAndSleep(R.string.loading_log, 29, 250);
LOG.setContext(LauncherActivity.this);
LOG.setDebug(true);
setProgressAndSleep(R.string.loading_database, 43, 250);
AppionDatabase.setContext(LauncherActivity.this);
setProgressAndSleep(R.string.loading_sensors, 57, 250);
Sensor.init(LauncherActivity.this);
setProgressAndSleep(R.string.loading_jobs, 71, 250);
Job.init(LauncherActivity.this);
setProgressAndSleep(R.string.loading_workbenches, 86, 250);
WorkbenchState.init(LauncherActivity.this);
setProgressAndSleep(R.string.loading_application_state, 100, 250);
ApplicationState.setContext(LauncherActivity.this);
startService(new Intent(LauncherActivity.this, BluetoothConnectionService.class));
return null;
}
#Override public void onProgressUpdate(Integer... prog) {
mLoadingText.setText(prog[0]);
mProg.setProgress(prog[1]);
}
#Override public void onPostExecute(Void voids) {
startActivity(new Intent(LauncherActivity.this, HomescreenActivity.class));
}
private void setProgressAndSleep(int text, int progress, int duration) {
try {
publishProgress(new Integer[] {text, progress});
Thread.sleep(duration);
} catch (InterruptedException e) {
LOG.e(TAG, "Failed to sleep thread while loading Application Contexts!", e);
}
}
}
Edit NOTE I recommend not keeping the setProgressAndSleep(int, int int) method. I only use it cause it loads too fast and I really wanted the loading bar. :-P
All changes in Android UI will makes in UI Thread. To run your function in UI thread you need to use mathos runOnUIThread() from activity http://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable)
Hope it help you!
Your best shot is, probably, to use ViewSwitcher to have temporary view with progress bar while you construct other view. Do operations that take time in doInBackground() of AsyncTask but actual operations on UI such as flipping the view must be done in postExecute() or via runOnUIThread(). Progress updates may be done in onProgressUpdate()