I am updating progress bar with the help of handler of MainActivity
but it gives the error :Can't create handler inside thread that has not called Looper.prepare()
Error
public class MainActivity extends AppCompatActivity {
ProgressBar progressBar;
Handler handler;
Thread thread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
thread = new Thread(new MyThread());
thread.start();
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
progressBar.setProgress(msg.arg1);
}
};
}
class MyThread implements Runnable {
#Override
public void run() {
Message message = Message.obtain();
for (int i = 0; i < 100; i++) {
message.arg1 = i;
handler.sendMessage(message);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
The error is because you are updating your UI from a different thread. So what you should be doing is like call the update method on main ui thread
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
runOnUiThread(new Runnable() {
#Override
public void run() {
// Do something on UiThread
// update progress
}
});
};
You should run progress bar only on Main Looper.
Add
handler = new Handler(context.getMainLooper()) {
.....
}
Should work.
Related
I can't find a none blocking way to invoke my callback method from the main thread as my second thread exits.
I tried to use the loading.isAlive() in a while loop but it freeze the screen.
public class MainActivity extends AppCompatActivity {
private ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar = findViewById(R.id.load_opening_screen);
Thread loading = new LoadingBarThread();
loading.start();
}
private class LoadingBarThread extends Thread {
#Override
public void run() {
for (int i=0;i<=100;i++) {
progressBar.setProgress(i);
try {
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private void callback(){
// start a new activity for example
}
}
I would like to start a new activity as the ProgressBar reaches 100.
Use a Handler object and at the end of your run() function, post a Runnable to that Handler. Have the Runnable call the callback method. Handler will execute it on the thread its attached to (whatever thread it was created on).
So your new class looks like:
private class LoadingBarThread extends Thread {
Handler handler = new Handler();
#Override
public void run() {
for (int i=0;i<=100;i++) {
progressBar.setProgress(i);
try {
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
handler.post(new Runnable() {
public void run() {
callback();
}
});
}
}
I am running a recursive handler which runs some code. I am posting the handler using a HandlerThread. I want to run the next recursive call only after the completion of the previous call.
Is it possible to do so? If not what are the alternatives.
HandlerThread ht = new HandlerThread();
ht.start();
Handler h = new Handler(ht.getLooper());
h.post(new Runnable() {
#override
public void run(){
//Some code
h.postDelay(this,1000);
}
});
Your code should work, but if you want a complete example how to run something recursively using HandlerThread, here it is:
public class Main2Activity extends AppCompatActivity {
private MyWorkerThread mWorkerThread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
mWorkerThread = new MyWorkerThread("myWorkerThread");
final Runnable task = new Runnable() {
#Override
public void run() {
Log.d("TAG", "Done.");
mWorkerThread.postTask(this);
}
};
mWorkerThread.start();
mWorkerThread.prepareHandler();
mWorkerThread.postTask(task);
}
#Override
protected void onDestroy() {
mWorkerThread.quit();
super.onDestroy();
}
}
class MyWorkerThread extends HandlerThread {
private Handler mWorkerHandler;
public MyWorkerThread(String name) {
super(name);
}
public void postTask(Runnable task){
mWorkerHandler.postDelayed(task, 1000); // set timeout which needed
}
public void prepareHandler(){
mWorkerHandler = new Handler(getLooper());
}
}
Don't forget to call handlerThread.quit() in onDestroy
I am trying to put a progressDialog in my fragment so my app feels smoother between each actions. The problem that I have is that the main thread is returning the view before the async thread has modified it. I was doing a Thread.join() before switching to this methode.
public class MyFragment extends Fragment {
public View onCreateView(LayoutInflater inflater,ViewGroup container, Bundle args) {
mLLayout = new LinearLayout(getActivity());
mLLayout.setPadding(0, 0, 0, 0);
mLLayout.setOrientation(LinearLayout.VERTICAL);
mScroll = new ScrollView(getActivity().getApplicationContext());
mScroll.setVerticalScrollBarEnabled(true);
mScroll.addView(mLLayout);
new AsyncCaller().execute();
return mScroll;
}
private class AsyncCaller extends AsyncTask<Void, Void, Void>
{
ProgressDialog nDialog = new ProgressDialog(getActivity());
#Override
protected void onPreExecute()
{
super.onPreExecute();
//this method will be running on UI thread
nDialog = new ProgressDialog(getActivity());
nDialog.setMessage("Loading..");
nDialog.setTitle("Checking Network");
nDialog.setIndeterminate(false);
nDialog.setCancelable(true);
nDialog.show();
}
#Override
protected Void doInBackground(Void... params)
{
//Doing http requests and modifying views
return null;
}
#Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
//this method will be running on UI thread
nDialog.dismiss();
}
}
...
}
I cant find a solution without blocking the main thread and by the same way not seeing the progressDialog at all and having a big lag instead. Also, I never saw my code go into "onPostExecute()".
Thanks in advance for your help!
Striaght from an app i've done, this code should help:
ProgressBar mProgress = (ProgressBar) findViewById(R.id.progressBar);
private float mProgressStatus = 0;
private Handler mHandler = new Handler();
private void startProgressBar()
{
new Thread(new Runnable()
{
#Override
public void run()
{
while (mProgressStatus < 100)
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
mProgressStatus += 1.3;
mHandler.post(new Runnable()
{
#Override
public void run()
{
mProgress.setProgress((int) mProgressStatus);
}
});
}
}
}).start();
}
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});
I am trying to update a textview after 3 seconds, and i want to do that in a loop for which i am using thread .....what should i do in order to start background thread so that exactly after 3 seconds background1 thread starts ... and it should be done in a loop ?
package com.edu.math;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.TextView;
public class EduMath extends Activity {
TextView txt;
TextView tv;
TextView num;
String x;
int time = 3000;
float z ;
int random;
int random1;
int random_operator =1;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txt=(TextView)findViewById(R.id.txt);
tv = (TextView)findViewById(R.id.randomNumber);
background.start();
}
// our handler
Handler handler = new Handler() {
public void handleMessage(Message msg) {//display each item in a single line
random = (int)Math.ceil(Math.random()*10);
random1 = (int)Math.ceil(Math.random()*10);
if(random1>random)
{
txt.setText(/*txt.getText()+*/""+random1+" "+>+" "+random+" "+
System.getProperty("line.separator"));
}
else
{
txt.setText(/*txt.getText()+*/""+random+" "+>+" "+random1+
System.getProperty("line.separator"));
}
}
};
Handler handler1 = new Handler() {
#Override
public void handleMessage(Message msg) {//display each item in a single line
txt.setText(/*txt.getText()+*/""+random1+" "+x+" "+random+System.getProperty("line.separator"));
}
};
Thread background1 =new Thread(new Runnable() {
#Override
public void run() {
for(int i=0;i<10;i++)
{
try {
Thread.sleep(time);
// send message to the handler with the current message handler
handler1.sendMessage(handler1.obtainMessage());
background.stop();
Log.d("EduMath-enclosing_method", "thread started");
} catch (Exception e) {
Log.v("Error", e.toString());
}
}
}
});
Thread background=new Thread(new Runnable() {
#Override
public void run() {
for(int i=0;i<10;i++)
{
try {
Thread.sleep(time);
// send message to the handler with the current message handler
handler.sendMessage(handler.obtainMessage());
background1.start();
} catch (Exception e) {
Log.v("Error", e.toString());
}
}
}
});
}
You must use AsyncTask for changing any views in layout, but at now I have very little experience with AsyncTask.
Try to use a java.util.Timer ( http://download.oracle.com/javase/1.4.2/docs/api/java/util/Timer.html )
public class HandlerDemo extends Activity {
ProgressBar bar;
Handler handler=new Handler() {
#Override
public void handleMessage(Message msg) {
//add your text
}
};
AtomicBoolean isRunning=new AtomicBoolean(false);
public void onStart() {
super.onStart();
Thread background=new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(3000);
handler.sendMessage(handler.obtainMessage());
}
catch (Throwable t) {
// just end the background thread
}
}
});
isRunning.set(true);
background.start();
}
public void onStop() {
super.onStop();
isRunning.set(false);
}
}
Try the solution on this post...seems to be what you looking for http://androidgenuine.com/?p=707