This question already has answers here:
Running code in main thread from another thread
(17 answers)
Closed 5 years ago.
I'm trying to dynamically update an android LinearLayout in the main thread.
Unfortunately I'm having a lot of trouble ascertaining anything from the tutorials online. None of them seem to provide a complete picture of how to communicate between threads.
My idea is something like this:
public class MainActivity extends AppCompatActivity {
private LinearLayout layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
layout = new LinearLayout(this);
setContentView(layout);
Updater updater = new Updater();
Thread workerThread = new Thread(updater);
//somehow update layout
The updater class would look something like this:
public class Updater implements Runnable {
private int count = 0;
public Updater() {}
#Override
public void run()
{
for (int i = 0; i < 10; i ++){
try {
count++;
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
I know I need a Handler in order to communicate messages between the threads, but I don't know how to set that up.
I would like to avoid anonymous classes, and dynamically create new TextViews whenever Updater has a new message.
create WorkerThreadListener interface:
public interface WorkerThreadListener {
void onUpdate(int counter);
}
Change your Updater class:
public class Updater implements Runnable {
private final WorkerThreadListener mWorkerThreadListener;
private final Handler mHandler;
private int count = 0;
public Updater(final WorkerThreadListener workerThreadListener) {
this.mWorkerThreadListener = workerThreadListener;
this.mHandler = new Handler();
}
#Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
count++;
mHandler.post(new Runnable() {
#Override
public void run() {
mWorkerThreadListener.onUpdate(count);
}
});
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Change MainActivity class:
public class MainActivity extends AppCompatActivity {
private LinearLayout layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
layout = new LinearLayout(this);
setContentView(layout);
Updater updater = new Updater(new WorkerThreadListener() {
#Override
public void onUpdate(int counter) {
//update layout here
}
});
Thread workerThread = new Thread(updater);
workerThread.start();
}
}
Hi please check my below answer hope it helps you.
public class ProgressTestActivity extends Activity {
private ProgressBar progress;
private TextView text;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
progress = (ProgressBar) findViewById(R.id.progressBar1);
text = (TextView) findViewById(R.id.textView1);
}
public void startProgress(View view) {
// do something long
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
final int value = i;
doFakeWork();
progress.post(new Runnable() {
#Override
public void run() {
// here you can add any view or anyof your logic which is related to UI put it into here.
text.setText("Updating");
progress.setProgress(value);
}
});
}
}
};
new Thread(runnable).start();
}
// Simulating something timeconsuming
private void doFakeWork() {
SystemClock.sleep(5000);e.printStackTrace();
}
}
Other ways are also possible.if you have any doubt please comment below post i will explain you in details.
If you just want to use a tick timer and set progress to ui thread . You can use CountDownTimer.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView textView;
private CountDownTimer countDownTimer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new);
textView = (TextView) findViewById(R.id.textView);
findViewById(R.id.b2).setOnClickListener(this);
}
public void processData() {
countDownTimer = new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
textView.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
textView.setText("done!");
}
}.start();
}
#Override
protected void onStop() {
super.onStop();
if (countDownTimer != null) {
countDownTimer.cancel();
}
}
#Override
public void onClick(View v) {
processData();
}
}
Apart from that to post a callback on UI thread you can use Handler .
Handler mainThreadHandler = new Handler(Looper.getMainLooper());
mainThreadHandler.post(new Runnable() {
#Override
public void run() {
}
});
Related
I want a delay for two seconds. and every 2 seconds I want to change the text, and for that, I am using handler like this, but it's not working it's only showing hello. it's not changing at all it only shows what I write second. The code is like this,
private Handler handler = new Handler();
int i=5;
private TextView textView ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.hello);
textView.setText("Android Things !!");
hello_first.run();
}
private Runnable hello_first = new Runnable() {
#Override
public void run() {
textView.setText("Nice Work");
handler.postDelayed(this,5000);
textView.setText("Hello");
handler.postDelayed(this,2000);
i = i+1;
if(i==5)
handler.removeCallbacks(this);
}
};
You are using postDelayed incorrectly. It looks like you expect it to work the same way Thread.sleep would work. However that is not the case.
Here is a correct implementation of what you are trying to achieve:
private Handler handler = new Handler();
private TextView textView;
private int i = 0;
private boolean flip;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.hello);
handler.post(hello_first);
}
private Runnable hello_first = new Runnable() {
#Override
public void run() {
if(++i == 5) {
handler.removeCallbacks(this);
return;
}
if(flip) {
textView.setText("Nice Work");
} else {
textView.setText("Hello");
}
flip = !flip;
handler.postDelayed(this, TimeUnit.SECONDS.toMillis(2));
}
};
I Hope this will work for you.
Handler handler = new Handler();
Runnable task = new Runnable() {
#Override
public void run() {
textView.setText("Nice Work");
handler.postDelayed(this,2000);
textView.setText("Hello");
handler.postDelayed(this,2000);
}
};
task.run();
For Stopping task
handler.removeCallbacks(task);
Its easy to use like
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
textView.setText("Hello");
},2000);
handler.postDelayed(new Runnable() {
#Override
public void run() {
textView.setText("Nice Work");},5000);
A Handler allows you to send and process Message and Runnable objects
associated with a thread's MessageQueue.
Rectify your postDelayed method.
Causes the Runnable r to be added to the message queue, to be run
after the specified amount of time elapses.
DEMO STRUCTURE
textView.setText("Nice Work");
final Handler handlerOBJ = new Handler();
handlerOBJ.postDelayed(new Runnable() {
#Override
public void run() {
// YOUR WORK
textView.setText("Hello");
}
}, 5000); // 5S delay
You can Log and see what happened actually...
Every time you call handler.postDelayed(this, 5000);
it will create two Runnable instance and send them to the handler. So the number of runnable in the queue increase very quickly.
You can set a text list and index, and then throw the runnable to the handler and postDealyed as 2000 milliseconds. Use the text list and index to see what text should be set to the textview.
try this code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.hello);
textView.setText("Android Things !!");
handler.postDelayed(hello_first,5000);
handler.postDelayed(hello_second,2000);
}
private Runnable hello_first = new Runnable() {
#Override
public void run() {
textView.setText("Nice Work");
}
};
private Runnable hello_second = new Runnable() {
#Override
public void run() {
textView.setText("Hello");
}
};
This below code to start activity "welcome1" and execute Thread() Then start another activity called "gps"
but when it executes the gps activity running without running activity welcome1
how can to start welcome1 and wait some time then start activity gps
Code
public class welcome1 extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads().detectDiskWrites().detectNetwork()
.penaltyLog().build());
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome1);
final TextView welcome = (TextView) findViewById(R.id.textView7);
final TextView person = (TextView) findViewById(R.id.textView9);
final Intent v = getIntent();
final String abt = v.getStringExtra("frist_name");
Runnable myRun=new Runnable() {
#Override
public void run() {
for (int s=0;s<2;s++){
final int finalI =s;
runOnUiThread(new Runnable() {
#Override
public void run() {
if (finalI==0)
{
welcome.setText(welcome2);
person.setText(abt);
}
if (finalI==1)
welcome.setText(steps);
}
});
synchronized (this) {
try {
wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
Thread T=new Thread(myRun);
T.start();
String number = v.getStringExtra("mobile_number");
String pwd = v.getStringExtra("pass");
Intent d = new Intent(getBaseContext(),gps.class);
d.putExtra("mobile_number",number);
d.putExtra("pass", pwd);
startActivity(d);
}
Have you tried with a Handler?
Just create a Runnable which starts the next activity and run like this:
new Handler().postDelayed(yourRunnable,timeinmillis)
startActivity(Intent) is called right after the Thread T starts. Thus it ignores the Thread T you created and just runs in the UI thread.
Correct code to do what you want is this:
public class welcome1 extends Activity {
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads().detectDiskWrites().detectNetwork()
.penaltyLog().build());
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome1);
final TextView welcome = (TextView) findViewById(R.id.textView7);
final TextView person = (TextView) findViewById(R.id.textView9);
final Intent v = getIntent(); final String abt = v.getStringExtra("frist_name");
Runnable myRun=new Runnable() {
#Override
public void run() {
for (int s=0;s<2;s++){
final int finalI =s;
runOnUiThread(new Runnable() {
#Override
public void run() {
if (finalI==0)
{
welcome.setText(welcome2);
person.setText(abt);
}
if (finalI==1)
welcome.setText(steps);
}
});
try {
wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
String number = v.getStringExtra("mobile_number");
String pwd = v.getStringExtra("pass");
Intent d = new Intent(getBaseContext(),gps.class);
d.putExtra("mobile_number",number);
d.putExtra("pass", pwd);
startActivity(d);
}
});
}
}
};
Thread T=new Thread(myRun);
T.start();
}
Copy and paste this code into your oncreate() method:
//This will wait for 10secs before launching the gps activity
Handler h = new Handler();
h.postDelayed(new Runnable() {
#Override
public void run() {
startActivity(new Intent(welcome1.this, Gps.class));
}
}, 10000);
Then run your code, it should work now.
I have an text view (Text1) that updates fine when i set the text in the oncreate but when i try to update it in the onEvent method it doesn't update I have searched similar posts but cant narrow down whats causing my specific problem
public class MainActivity extends Activity implements ProximityManager.ProximityListener {
private static final String TAG = MainActivity.class.getSimpleName();
private ProximityManagerContract proximityManager;
private ScanContext scanContext;
private TextView Text1;
private TextView Text2;
private TextView Text3;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
KontaktSDK.initialize("").setDebugLoggingEnabled(BuildConfig.DEBUG)
.setLogLevelEnabled(LogLevel.DEBUG, true);
;
proximityManager = new KontaktProximityManager(this);
Text1 = (TextView) findViewById(R.id.textView);
Text2 = (TextView) findViewById(R.id.textView2);
}
#Override
protected void onStart() {
super.onStart();
proximityManager.initializeScan(getScanContext(), new OnServiceReadyListener() {
#Override
public void onServiceReady() {
proximityManager.attachListener(MainActivity.this);
EddystoneScanContext eddystoneScanContext = new EddystoneScanContext.Builder()
.setEventTypes(Arrays.asList(
EventType.SPACE_ENTERED,
EventType.DEVICES_UPDATE,
EventType.SPACE_ABANDONED))
.build();
ScanContext scanContext = new ScanContext.Builder()
.setEddystoneScanContext(eddystoneScanContext)
.build();
}
#Override
public void onConnectionFailure() {
}
});
}
#Override
protected void onStop() {
super.onStop();
proximityManager.detachListener(this);
proximityManager.disconnect();
}
#Override
public void onEvent(BluetoothDeviceEvent bluetoothDeviceEvent) {
final List<? extends RemoteBluetoothDevice> deviceList = bluetoothDeviceEvent.getDeviceList();
long timestamp = bluetoothDeviceEvent.getTimestamp();
DeviceProfile deviceProfile = bluetoothDeviceEvent.getDeviceProfile();
switch (bluetoothDeviceEvent.getEventType()) {
case SPACE_ENTERED:
Log.d(TAG, "namespace or region entered");
break;
case DEVICE_DISCOVERED:
Log.d(TAG, "found new beacon");
break;
case DEVICES_UPDATE:
Log.d(TAG, "updated beacons");
Log.d("Scan", String.valueOf(deviceProfile.toString()));
Log.d("List", deviceList.toString());
//Log.d("List", deviceProfile.name(deviceList.get(1)));
Log.d("distance", String.valueOf(deviceList.get(1).getDistance()));
Text1.setText("Is Updated");
break;
case DEVICE_LOST:
Log.d(TAG, "lost device");
break;
case SPACE_ABANDONED:
Log.d(TAG, "namespace or region abandoned");
break;
}
}
#Override
public void onScanStart() {
Log.d(TAG, "scan started");
}
#Override
public void onScanStop() {
Log.d(TAG, "scan stopped");
}
private ScanContext getScanContext() {
if (scanContext == null) {
scanContext = new ScanContext.Builder()
.setScanPeriod(ScanPeriod.RANGING) // or for monitoring for 15 seconds scan and 10 seconds waiting:
//.setScanPeriod(new ScanPeriod(TimeUnit.SECONDS.toMillis(15), TimeUnit.SECONDS.toMillis(10)))
.setScanMode(ProximityManager.SCAN_MODE_LOW_LATENCY)
.setActivityCheckConfiguration(ActivityCheckConfiguration.MINIMAL)
.setForceScanConfiguration(ForceScanConfiguration.MINIMAL)
.setIBeaconScanContext(new IBeaconScanContext.Builder().build())
.setEddystoneScanContext(new EddystoneScanContext.Builder().build())
.setForceScanConfiguration(ForceScanConfiguration.MINIMAL)
.build();
}
return scanContext;
}
}
You cannot update view outside the main thread (UI thread). Try to wrap your method with runOnUiThread.
runOnUiThread(new Runnable() {
public void run() {
Text1.setText("Is Updated");
}
});
new Handler(new Runnable() {
public void run() {
Text1.setText("Is Updated");
}
});
you have to use Handler or runOnUIThread because you cant edit on a component in main thread from outside
I am extending the Application class to do 2 things. 1) Make onPause() stop the CounterThread until onResume() is pressed. 2) To make the threads continue working while I change orientation of the phone from portrait mode to landscape. Both of the above statements work, however the MakingFileThread when it returns a string value to set the TextView does not persist the orientation changes. Help!!
public class MainActivity extends Activity {
private TextView mText;
private EditText mUserInput;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mText = (TextView)findViewById(R.id.text);
mUserInput = (EditText)findViewById(R.id.userInput);
}
#Override
public void onPause(){
super.onPause();
MyApplication app = (MyApplication)getApplication();
app.pause(null);
}
#Override
public void onResume(){
super.onResume();
MyApplication app = (MyApplication)getApplication();
app.resume(this);
}
public void button_handler(View v){
String val = mUserInput.getText().toString();
String file = "myfile.txt";
MyApplication app = (MyApplication)getApplication();
app.MakeFileThread(val,file);
app.startCounterThread();
}
public void updateCountDown(final int seconds){
String secondText = String.valueOf(seconds);
mText.setText(secondText);
}
public void updateFileOutput(final String userText){
mText.setText(userText);
}
}
public class CounterApplication extends Application {
private MainActivity currentActivity = null;
private CounterThread myThread;
public synchronized void resume(MainActivity update){
this.currentActivity = update;
myThread.interrupt();
}
public synchronized void pause(MainActivity update){
this.currentActivity = update;
myThread.interrupt();
}
public synchronized void update(final long seconds){
Runnable notifyAction = new Runnable(){
public void run(){
if(currentActivity != null){
currentActivity.updateResult(seconds);
}
}
};
currentActivity.runOnUiThread(notifyAction);
}
public void onCreate(){
super.onCreate();
myThread = new CounterThread();
myThread.start();
}
private class CounterThread extends Thread{
private long seconds = 0;
private boolean running = false;
#Override
public void run(){
while(true){
try{
Thread.sleep(running?1000:100000);
}
catch(InterruptedException e){
running = !running;
}
if(interrupted()){
running = !running;
}
if(running){
update(++seconds);
}
}
}
}
}
I am not sure, this might help you, add the following line in your manifest file for the activities you need to work in both portrait and landscape:
android:configChanges="orientation|screenSize"
In my app I have three buttons and when one button is clicked it calls a thread to start thing is i want to be able to input in edittext string in to the threads and the do some work to it then have it returned to the UI Thread where i can display it or put it into an opengl to display an Object. I've read up on Handles and im not sure i fully understand them and maybe if anyone knows a way to make my own handler code. Also I've read up on Async and I dont think it would benifit my app.(personal opion if it would benifit my app let me know) My question is how would i get the info from UI edittext when enter is pressed to the line thread in DrawingUtils class then work is done to it then it comes back to the UI to be ethier displayed or inputed in an openGl program?
Here is MainActivity class:
public class MainActivity extends Activity implements OnClickListener {
EditText cl;
TextView info;
Button enter;
Button line;
Button arc;
Line callLine = new DrawingUtils.Line();
Enter callEnter = new DrawingUtils.Enter();
Arc callArc = new DrawingUtils.Arc();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
info = (TextView) findViewById(R.id.info);
enter = (Button) findViewById(R.id.enter);
line = (Button) findViewById(R.id.line);
arc = (Button) findViewById(R.id.arc);
Handler UIhandler = new Handler() {
#Override
public void handleMessage(Message msg) {
Bundle bundle = msg.getData();
String string = bundle.getString("myKey");
}
};
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.enter:
callEnter.start();
break;
case R.id.line:
callLine.start();
break;
case R.id.arc:
callArc.start();
break;
}
};
}
Here is DrawingUtils class:
public class DrawingUtils {
MainActivity handle = new MainActivity();
// Thread classes for buttons
public static class Enter extends Thread {
Thread enter = new Thread() {
public void run() {
}
};
public static class Line extends Thread {
Thread line = new Thread() {
public void run() {
}
};
}
public static class Arc extends Thread {
Thread arc = new Thread() {
public void run() {
}
};
}
}
}
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstance) {
// ....
Handler myHandler = new Handler() {
#Override
public void handleMessage (Message msg) {
doCoolStuffWhenMessageReceived();
}
}
MySecondClass secondClass = new MySecondClass(myHandler);
// ....
}
}
public class MySecondClass {
private handler;
public MySecondClass(Handler handler){
this.handler = handler;
}
private void someMethodToCallActivity() {
handler.sendEmptyMessage(0);
}
}