My expected result is in the first launch there will display a progress dialog to wait for the background thread loading the content. The dialog dismisses after worker thread is done the job. I did search and got this solution How to display progress dialog before starting an activity in Android?
This is my complete code:
private ManagerApplication app;
private ImageAdapter adapter;
private GridView gridview;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setupView();
}
private void setupView() {
gridview = (GridView) findViewById(R.id.gridview);
app = (ManagerApplication) getApplication();
ProgressDialog progress = new ProgressDialog(this);
progress.setMessage("Loading...");
new LoadImageTask(progress, this).execute();
}
private class LoadImageTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog progress;
private Context context;
public LoadImageTask(ProgressDialog progress, Context context) {
this.progress = progress;
this.context = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progress.show();
}
#Override
protected Void doInBackground(Void... params) {
adapter = new ImageAdapter(app.getShoes(), context);
gridview.setAdapter(adapter);
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
progress.dismiss();
}
}
However, my application crashes with the reason that "Only the original thread that created a view hierarchy can touch its views". I suppose there are something blocked the main UI thread, but its still very unclear. So could anyone point me to the problem ? Thanks
Funnily enough there's an article entitled Painless Threading that you should read. You shouldn't try to manipulate views in doInBackground. In your case, you can call app.getShoes() but don't do the adapter setup in there.
doinBackground is non UI Thread ,So never update any UI(View) in this
method...
and use OnPostExecute or OnProgressUpdate for update UI
#Override
protected Void doInBackground(Void... params) {
//here just background task ,
//its non UI Thread so dont set ant view here set it in OnPostExecute,...
return null;
}
call asynctask from setupview
private void setupView() {
gridview = (GridView) findViewById(R.id.gridview);
app = (ManagerApplication) getApplication();
new LoadImageTask(progress, this).execute();
}
and create ProgressDilog in OnPreExecute method
ProgressDialog progress;
#Override
protected void onPreExecute() {
super.onPreExecute();
progress = new ProgressDialog(this);
progress.setMessage("Loading...");
progress.show();
}
and in onPostExecute dismiss it
Related
I add an asynctask in my app since it has many data to search but i got error in protected Void doInBackground and it says Method getText() must be called from the UI thread, currently inferred thread is worker. My app composed of dialog that has editText and Spinner. Please help me and thanks in advance.
doctorLocationEditText = (EditText)dialog.findViewById(R.id.doctorlocation);
doctorHospital = (Spinner) dialog.findViewById(R.id.spinnerdoctorhospital);
ArrayAdapter<String> hospitalAdapter = new ArrayAdapter<String>(Doctor.this,R.layout.spinner_layout, db.getAllHospitalName());
hospitalAdapter.setDropDownViewResource(R.layout.spinner_layout);
doctorHospital.setAdapter(hospitalAdapter);
Button button = (Button) dialog.findViewById(R.id.btndoctorsearch);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new DoctorSearch().execute();
dialog.dismiss();
This is my asynctask that has error
class DoctorSearch extends AsyncTask<Void, Void, Void> {
ProgressDialog Asycdialog = new ProgressDialog(Doctor.this);
#Override
protected void onPreExecute() {
super.onPreExecute();
Asycdialog.setMessage("Loading...");
Asycdialog.show();
}
#Override
protected Void doInBackground(Void... arg0) {
GetSearchDoctor = dbhelper.getDoctorSearch(index2, doctorLocationEditText.getText().toString(), doctorHospital.getSelectedItem().toString());
return null;
}
#Override
protected void onPostExecute(Void result) {
lv3 = (ListView) findViewById(R.id.searchdoctor_list);
lv3.setAdapter(new ViewAdapterSearchDoctor());
super.onPostExecute(result);
Asycdialog.dismiss();
}
}
You are not supposed to access a UI thread from a Background Thread.
Get text in onPreExecute() or AsyncTask constructor & pass it to doInBackground.
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 my code I load a spinner adapter by using Async Task
In My case The ProgressDialog is Not dismissing
This is My code.
I want to show the item after adapter load and the progressDialog is to dismiss
Please Help me, Thanks
private class LoadMoreVehicals extends AsyncTask<Object, Integer, Object> {
#Override
protected void onPreExecute() {
progressBar = ProgressDialog.show(RegistrationScreen.this, "",
"Loading...");
progressBar.setIndeterminate(true);
progressBar.setIndeterminateDrawable(getResources().getDrawable(
R.anim.progressbar_handler));
super.onPreExecute();
}
#Override
protected Object doInBackground(Object... params) {
String countryUrl = ConstantURL.COUNTRY_URL;
getCounty(countryUrl);
countrySpinner
.setAdapter(new MyCustomSpinnerAdapter(
RegistrationScreen.this,
R.layout.spinner_dropdown,
countyList));
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
progressBar.getProgress();
}
#Override
protected void onPostExecute(Object result) {
progressBar.dismiss();
Log.e("Im in onPostExecute", "");
super.onPostExecute(result);
}
}
While programming in Android you should remember one thing that any task which draws something on the screen should be executed on the main thread. When you set the adapter then android calls the getView() method of the adapter and draws views on the screen. So you should set the adapter in the postExecute() method instead in doInBackground() method.
Here is a small sample to clear my point:
class MyTask extends AsyncTask<Void, Void, Void> {
ProgressDialog pd = new ProgressDialog(MainActivity.this);
#Override
protected void onPreExecute ( )
{
//starting the progress dialogue
pd.show();
}
#Override
protected Void doInBackground (Void... params)
{
//fetch data here
...
...
return null;
}
#Override
protected void onPostExecute (Void result)
{
//set adapter here
...
...
//dismissing the progress dialogue
pd.dismiss();
}
}
In my experience i have so many problems with async runs and UI so now always separate the stuff trying to place the "responsibilities" in each place. So i do something like this:
Create my Async class with the process i want to do and nothing that transform the UI in it
Create a function in UI thread that modify the UI when async task finish, something like OnAsyncTaskComplete(Object response)
Keep communicated the threads
public class MyActivity extends Activity {
private static MyAsyncClass backgroundTask;
private static ProgressDialog pleaseWaitDialog;
//......activity stuff.......
#Override
public void onPause()
{
super.onPause();
//Get rid of progress dialog in the event of a screen rotation or other state change. Prevents a crash.
if (pleaseWaitDialog != null)
pleaseWaitDialog.dismiss();
}
//Function to avoid lose the async thread if the app interrupts (phone rotation, incoming call, etc) RECOMENDED TO HANDLE THIS!!
//Sets the current state after app resume
#Override
public void onResume()
{
super.onResume();
//If there is a background task set it to the new activity
if ((backgroundTask != null) && (backgroundTask.getStatus() == Status.RUNNING))
{
if (pleaseWaitDialog != null)
pleaseWaitDialog.show();
backgroundTask.setActivity(this);
}
}
}
//Logic business after the web service complete here
//Do the thing that modify the UI in a function like this
private void onTaskCompleted(Object _response)
{
//For example _response can be a new adapter
MyList.setAdapter((BaseAdapter)_response);
//or can be a list to create the new adapter
MyList.setAdapter(new MyAdapter(this, (ArrayList<String>)_response));
//or can be anything you want, just try to make here the things that you need to change the UI
}
/**
* Class that handle the async task
*/
public class MyAsyncClass extends AsyncTask<Void, Void, Object>
{
//Maintain attached activity for states change propose
private MyActivity activity;
//Keep the response of the async task
private Object _response;
//Flag that keep async task completed status
private boolean completed;
//Constructor
private MyAsyncClass(MyActivity activity) {
this.activity = activity;
}
//Pre execution actions
#Override
protected void onPreExecute() {
//Start the splash screen dialog
if (pleaseWaitDialog == null)
pleaseWaitDialog= ProgressDialog.show(activity.this,
"PLEASE WAIT",
"Getting results...",
false);
}
//Execution of the async task
protected Object doInBackground(Object...params)
{
//return the thing you want or do want you want
return new ArrayList();
}
//Post execution actions
#Override
protected void onPostExecute(Object response)
{
//Set task completed and notify the activity
completed = true;
_response = response;
notifyActivityTaskCompleted();
//Close the splash screen
if (pleaseWaitDialog != null)
{
pleaseWaitDialog.dismiss();
pleaseWaitDialog = null;
}
}
//Notify activity of async task completion
private void notifyActivityTaskCompleted()
{
if ( null != activity ) {
activity.onTaskCompleted(_response);
}
}
//for maintain attached the async task to the activity in phone states changes
//Sets the current activity to the async task
public void setActivity(MyActivity activity)
{
this.activity = activity;
if ( completed ) {
notifyActivityTaskCompleted();
}
}
}
}
Hope its help you
First of all you cannot set the adapter in the doInBackground
follow this design:
private class LoadMoreVehicals extends AsyncTask<Object, Integer, Object>
{
private ArrayList<Country> countries;
#Override
protected void onPreExecute() {
progressBar = ProgressDialog.show(RegistrationScreen.this, "","Loading...");
progressBar.setIndeterminate(true);
progressBar.setIndeterminateDrawable(getResources().getDrawable(R.anim.progressbar_handler));
super.onPreExecute();
}
#Override
protected Object doInBackground(Object... params) {
String countryUrl = ConstantURL.COUNTRY_URL;
countries = getCounty(countryUrl);
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
progressBar.getProgress();
}
#Override
protected void onPostExecute(Object result) {
countrySpinner.setAdapter(new MyCustomSpinnerAdapter(RegistrationScreen.this,R.layout.spinner_dropdown,countries));
progressBar.dismiss();
Log.e("Im in onPostExecute", "");
super.onPostExecute(result);
}
}
What I want: I want to show a progress dialog while adding views dynamically to my ViewFlipper.
What I have: I have used an AsyncTask to achieve this. The ViewFlipper is declared in my Main Activity, I am adding views to ViewFlipper in the doInBackground() of AsyncTask.
What is the problem: I am getting an exception on the viewFlipper.addView() statement and the exception is " Main has leaked window com.android.internal.policy.impl ..... that was originally added here. " , something like this.
Here is the code:
public class Main extends Activity
{
private ViewFlipper viewFlipper;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main_flipper);
viewFlipper = (ViewFlipper)findViewById(R.id.id_vf_main);
new LoadData().execute();
// Some other tasks.
}
class LoadData extends AsyncTask<Object, Void, String>
{
protected ProgressDialog progressDialog;
#Override
protected void onPreExecute()
{
super.onPreExecute();
progressDialog = ProgressDialog.show(Main.this,"Loading", "Loading Data...", true, false);
}
#Override
protected String doInBackground(Object... parametros)
{
for (int i = 0; i < Login.data_Channel_Name.size(); i++)
{
LayoutInflater inflater = getLayoutInflater();
RelativeLayout rl_main = (RelativeLayout) inflater.inflate(R.layout.main,null);
TextView tv_channelNumber = (TextView)rl_main.findViewById(R.id.id_tv_ChannelNumber);
if(tv_channelNumber != null)
{
tv_channelNumber.setText("Some Number");
}
TextView tv_channelName = (TextView)rl_main.findViewById(R.id.id_tv_ChannelName);
if(tv_channelName != null)
{
tv_channelName.setText("Some name");
}
viewFlipper.addView(rl_main);
}
return null;
}
#Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
progressDialog.dismiss();
}
}
}
You are trying to interact with the UI from the background thread which isn't allowed. You are allowed to mess with the UI in your onPostExecute() and onPreExecute() methods. There is another method; onProgressUpdate() you can use like so:
protected void onProgressUpdate(Integer... progress) {
// on UI thread!
viewFlipper.addView(rl_main);
}
Obviously you'll need to handle passing the view to this method by creating a field or something. You can call this within your doInBackground() with the following:
publishProgress(0);
The function is typically used for updating the percentage on a loading bar or similar (hence passing the integer) but should work fine your your purposes.