I've seen some of the answers to similar questions on here but they aren't working for me.
What I want to do is start a Thread and run some code in it, but before I start the thread, I want to display a loading dialog, and as soon as the thread is finished running, close the loading dialog.
So something like this:
LoadingDialog dialog = new LoadingDialog(MainActivity.this);
class MyThread {
...
void send() {
dialog.displayDialog();
// DO THINGS HERE
new Thread((Runnable) () -> {
try{
...
} catch (...) {
}
}).start();
// Close the dialog with dialog.closeDialog();
}
}
(displayDialog() and closeDialog() are just methods I created in my LoadingDialog class to start and dismiss the dialogs)
I'm not sure exactly how to do this, I've seen some uses of handler on this site but they're all different and not working for me so I'm a little stuck.
Thanks
Solution
public class MainActivity extends AppCompatActivity {
LoadingDialog dialog;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dialog = new LoadingDialog(MainActivity.this);
MyThread myThread = new MyThread(MainActivity.this);
myThread.start();
}
static class MyThread extends Thread {
private WeakReference<MainActivity> activityRef;
public MyThread(MainActivity activity) {
activityRef = new WeakReference<>(activity);
}
#Override
public void run() {
send();
}
void send() {
// Display dialog
if (getActivity() != null) {
getActivity().dialog.displayDialog();
}
// DO THINGS HERE
// TODO: Write your code that execute in a background here
// Close dialog
if (getActivity() != null) {
getActivity().dialog.closeDialog();
}
}
private MainActivity getActivity() {
return activityRef.get();
}
}
}
Related
I am having a situation that my dialog doesn't show up in my asyncTask.
The codes below are my asyncTask
private class AsyncCallListWS extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
Log.i(TAG, "--------------------------------------------------");
Log.i(TAG, "pending ws: onPreExecute");
showLoadingDialog();
}
#Override
protected Void doInBackground(Void... params) {
Log.i(TAG, "pending ws: doInBackground");
//listDataParent = new ArrayList<Tn_Parent>();
listPending();
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Log.i(TAG, "Call pending ws: onPostExecute");
dismissLoadingDialog();
//Log.i(TAG, "I am not up there "+status.toString());
if(getContext()!=null) {
//adapter = new Tn_ListViewAdapter(getActivity(), newList, selectAll);
//listView.setAdapter(adapter);
lvAdapter = new Tn_ListViewAdapter(getActivity(), lvList, selectAll);
listView.setAdapter(lvAdapter);
// .............. below is not needed .....................
//listAdapter = new Tn_ExpandableAdapter(listDataParent,getContext(), selectAll);
//expListView.setAdapter(listAdapter);
}
}
}
And below is my dialogbox codes. The dialog work well in other class.
public void showLoadingDialog() {
if (bar == null) {
bar = new ProgressDialog(getActivity());
bar.setMessage(getString(R.string.loading_message));
//bar.setCanceledOnTouchOutside(getRetainInstance());
bar.setCanceledOnTouchOutside(false);
}
bar.show();
}
public void dismissLoadingDialog() {
if (bar != null && bar.isShowing()) {
bar.dismiss();
}
}
I really wish to know what are the problems. The dialog show up when I put showLoadingDialog() in the onCreateView(), but the problem is that the dialog will not dismiss if i put it inside the onCreateView(). Please help.
For your dismiss() problem inside onCreate, try to change
public void dismissLoadingDialog() {
if (bar != null && bar.isShowing()) {
bar.dismiss();
}
}
to
public void dismissLoadingDialog() {
if (bar != null) {
bar.dismiss();
bar = null;
}
}
The problem to not showing up your dialog inside AsynTask might be your if (bar == null) { condition, because at that time your bar object will not be null. So that the time when you are dismissing the dialog you have to initialize it to null. And please write bar.show(); this line of code inside if(...) condition.
As Preetika Kaur suggested you should pass a Context object to you showLoadingDialog() and call bar = new ProgressDialog(yourContextObject); cause otherwise the bar would always be null.
I have designed a splash screen with a button. The Java code is as below. The layout of the splash contains some texts with animation and button named skipped splash screen. When the user presses the button, the splash screen has to stop immediately and open the next activity. But when I open the splash screen and press skip button, the next activity opens but after the duration for which splash screen has to run gets over, again the activity opens. How to stop the splash screen when a user presses the skip button?
public class Qz1 extends Activity {
TextView a;
TextView b;
TextView c;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qz1);
a =(TextView)findViewById(R.id.roundOnea22);
a.startAnimation(AnimationUtils.loadAnimation(Qz1.this, R.anim.anim_slide_in_left));
b =(TextView)findViewById(R.id.roundOneb);
b.startAnimation(AnimationUtils.loadAnimation(Qz1.this, R.anim.anim_slide_in_right));
c =(TextView)findViewById(R.id.roundme);
c.startAnimation(AnimationUtils.loadAnimation(Qz1.this, R.anim.anim_slide_in_left));
Thread thread = new Thread(){
#Override
public void run() {
// TODO Auto-generated method stub
try{
sleep(3200);
startActivity(new Intent(getApplicationContext(), Qone.class));
} catch (InterruptedException e){
e.printStackTrace();
}
}
};
thread.start();
}
public void round1(View v){
Intent i = new Intent(Qz1.this, Qone.class);
startActivity(i);
}
}
Let's suppose you want to keep your first activity in the background, but you do not want the thread to re-open the second activity as soon as it has finished sleeping.
In order to achieve that, you can make your "thread" a global variable of a custom Thread class. You can define this as an inner class of your activity:
MyThread thread;
and the class definition:
private class MyThread extends Thread
{
public boolean bRun = true;
#Override
public void run()
{
try
{
sleep(3200);
if (bRun)
{
startActivity(new Intent(getApplicationContext(), Activity2.class));
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
In onCreate(), you write
thread = new MyThread();
thread.start();
Then you can change your "onClick" method like this:
public void round1(View v){
if (thread != null && thread.isAlive())
{
thread.bRun = false;
}
Intent i = new Intent(Qz1.this, Qone.class);
startActivity(i);
}
This will keep the thread from starting the second activity, if it has been started by clicking the button.
Shouldn't be using sleep(2000)
use an animationlistener (http://developer.android.com/reference/android/view/animation/Animation.AnimationListener.html)
when onAnimationEnd is triggered call startActivity.
I think best practice here would be to use a Handler.
You can do it like this:
public class Test extends AppCompatActivity{
private Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Settign the splashscreen with the button i suppose
setContentView(R.id.splashcreen);
}
#Override
protected void onStart() {
super.onStart();
handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
startNextActivity();
}
}, 2000);
}
public void startNextActivity(){
startActivity(new Intent(getApplicationContext(), Qone.class));
}
public void skipSplashScreen(){
if (handler != null)
handler.removeCallbacksAndMessages(null);
startNextActivity();
}
#Override
protected void onStop() {
super.onStop();
// clear handler on stop
if (handler != null)
handler.removeCallbacksAndMessages(null);
}
}
CAll skipSplashScreen() when user press the button and the handler will stop so the timer stops and you go to next activity manually by calling method startNextActivity().
It's best practice to use Async Tasks for wait/sleep scenarios, such as for splash screens, but requirements can differ.
Anyway this is my way to call a splash screen:
Create the AsyncTask first.
private class SplashTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
finish();
Intent intent = new Intent(SplashActivity.this,
MainActivity.class);
startActivity(intent);
}
}
}
Then call this where ever you want: on button click, on start, or on create:
new SplashTask().execute();
try this in the splash activity
Button button = (Button)findViewById(R.id.buttonLayout);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(this,TargetActivity.class));
finish();
}
});
I am new to android programming. I am developing a web crawler for which i am using a Async Task and it is working well.In order to keep user informed,i am using progress dialog. My problem is,if i use a Progress Dialog my program takes more time to execute and when i won`t use the progress dialog,it executes faster.
Done Work
OnCreate Method
protected void onCreate(Bundle savedInstanceState) {
try {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_results);
Intent intent = getIntent();
s1 = intent.getStringExtra("Number1");
s2 = intent.getStringExtra("Number2");
s3=intent.getIntExtra("selectedItem",0);
HttpAsyncTask asyncTask = new HttpAsyncTask();
asyncTask.execute();
}catch (Exception e)
{
messageBox("Exception",e.getMessage());
}
}
Async Task Class
private class HttpAsyncTask extends AsyncTask<List<String>, Integer, List<String>> {
private ProgressDialog dialog;
#Override
protected void onPreExecute()
{
dialog = new ProgressDialog(Results.this);
dialog.setIndeterminate(true);
dialog.setMessage("Please Wait");
dialog.setCancelable(true);
dialog.show();
super.onPreExecute();
}
#Override
protected List<String> doInBackground(List<String>... urls) {
//android.os.Debug.waitForDebugger();
// spinner.setVisibility(View.VISIBLE);
List<String>resultList=new ArrayList<String>();
try
{
if(isCancelled())
return resultList;
resultList=WebCrawlerClass.GetPost(s1,s2,s3);
}catch (Exception e)
{
messageBoxs("Error", e.getMessage());
}
return resultList;
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(List<String> result)
{
if(dialog.isShowing())
{
dialog.dismiss();
}
if(s3 == 2)
{
docListAdapter=new ListViewData(Results.this,result);
}
else {
docListAdapter = new NameNumListData(Results.this, result);
}
docList=(ListView)findViewById(R.id.listView2);
docList.setAdapter(docListAdapter);
super.onPostExecute(result);
}
#Override
protected void onCancelled() {
super.onCancelled();
this.cancel(true);
}
}
Am I missing something? Need help..
Thanks and Regards,
Abhinav
In you activity
// Start the progress dialog
..
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// dismiss the progress dialog
}
};
HttpAsyncTask asyncTask = new HttpAsyncTask(handler);
asyncTask.execute();
In your asynctask class
private class HttpAsyncTask extends AsyncTask<List<String>, Integer, List<String>> {
private Handler handler = null;
public HttpAsyncTask (Handler handler) {
this.handler = handler;
}
protected Void doInBackground(Void... params) {
//Perform your task
// When you know that task is finished , fire following code
if (null != handler) {
Message message = handler.obtainMessage();
message.obj = Any data you want to sent to the activity
message.what = 1 ; ( Optional )
handler.sendMessage(message);
}
}
Thus when sendMessage function is called from doInbackground.. your handleMessage in your activity will get triggered and then you should dismiss the progress dialog
Hope this will improve the performance issue what you are facing
Remove super.onPreExecute(); in onPreExecute() method and check .It might Help
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.
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});