I want to make a thread which will change the layout of my activity ... I have 2 layouts : welcomepage and activity_main ...
The goal of thread: when I launch my application , the welcomepage layout will be visible in only 5 sec and after that the layout again will be activity_main ...
I wrote the code as below:
package com.example.tripolimazad;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
public class MainActivity extends Activity {
public TextView counter = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.welcomepage);
counter = (TextView) findViewById(R.id.Counter);
Thread th=new Thread(){
#Override
public void run(){
try
{
Thread.sleep(10000);
setContentView(R.layout.activity_main);
}catch (InterruptedException e) {
}
}
};
th.start();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
but it doesnt work !!! have anyone any solution plz !
You cannot change the UI on a non-UI thread, however in an Activity, you can use the runOnUiThread method:
runOnUiThread(new Runnable() {
#Override
public void run() {
setContentView(R.layout.activity_main);
}
});
This seems very strange though, to have this in your onCreate.
You may also try to use CountDownTimer something like:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.welcomepage);
//display the logo during 5 secondes,
new CountDownTimer(5000,1000){
#Override
public void onTick(long millisUntilFinished){}
#Override
public void onFinish(){
//set the new Content of your activity
MainActivity.this.setContentView(R.layout.main);
}
}.start();
//...
}
See Displaying logo for few seconds at application start for more.
Alternatively you can use a handler to avoid creating a new thread as following:
getWindow().getDecorView().getHandler().postDelayed(new Runnable() {
#Override public void run() {
setContentView(R.layout.activity_main);
}
}, 10000);
UI related operations must be done on UI thread only and must not be done in non-UI thread as you are doing. But you can update UI from non-UI thread as follows:
activityContext.runOnUiThread(new Runnable() {
#Override
public void run() {
setContentView(R.layout.activity_main);
}
});
However a better approach for the situation you mentioned is to use an Async task, provided by the Android.You can try following :
/*
* Activity/Thread to display the **welcomepage**
* when the app is started.
*/
public class SplashActivity extends Activity {
// how long until we go to the next activity
protected int _splashTime = 5000; // 5 seconds
// thread to display welcome page
private Thread splashTread;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_welcome_page_layout);
// thread for displaying the WelcomeScreen
splashTread = new Thread() {
#Override
public void run() {
try {
synchronized (this) {
// wait 5 sec
wait(_splashTime);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// finish the current splashactivity
finish();
// start MainActivity as next activity
startActivity(new Intent(SplashActivity.this, MainActivity.class));
}
}
};
// start the thread.
splashTread.start();
}
}
Related
I am trying to show progress dialog and update it inside runOnUiThread
but the progress bar never shown. when I replace the runOnUiThread with "new Thread" it work fine. But I want it to work with runOnUiThread
here is my code , I have deleted unnecessary codes
public class test extends Activity {
private ProgressDialog progress;
Handler progressBarHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
testing();
}
public void testing() {
progress=new ProgressDialog(this);
progress.setMessage("Saving Progress");
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setProgress(0);
progress.setMax(100);
progress.setCancelable(false);
progress.show();
runOnUiThread(new Runnable() {
#Override
public void run() {
//do some work
for (int i =0; i<100;i++){
//some work
progressBarHandler.post(new Runnable() {
#Override
public void run() {
progress.setProgress(finalCount);
}
});
}
}
}
Try this
public class MainActivity extends AppCompatActivity {
private ProgressDialog progress;
Handler workHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progress=new ProgressDialog(this);
progress.setMessage("Saving Progress");
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setProgress(0);
progress.setMax(100);
progress.setCancelable(false);
progress.show();
workHandler = new Handler(new HandlerThread("workHandlerThread").getLooper());
workHandler.post(new Runnable() {
#Override
public void run() {
//Do some work
runOnUiThread(new Runnable() {
#Override
public void run() {
progress.setProgress(/*work result*/);
}
});
}
});
}
}
The idea is you do the work on the HandlerThread bound to workHandler, and post the results back the the UI using runOnUiThread()
when I Swipe to Refresh the animation of SwipeRefreshLayout shows, but it is froze while onRefresh() runs, and only starts to spin when onRefresh() is finished.
MainActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myFAB = (FloatingActionButton) findViewById(R.id.myFAB);
recyclerView = (RecyclerView) findViewById(R.id.rv);
recyclerView.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(this);
recyclerView.setLayoutManager(llm);
recyclerView.addItemDecoration(new SimpleDividerItemDecoration(this));
callCadastroEncoemnda();
callPackageList();
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
swipeRefreshLayout.setOnRefreshListener(this);
swipeRefreshLayout.setColorSchemeResources(
android.R.color.holo_blue_bright,
android.R.color.holo_green_light,
android.R.color.holo_orange_light,
android.R.color.holo_red_light);
}
onRefresh:
#Override
public void onRefresh() {
swipeRefreshLayout.setRefreshing(true);
Update.updateAll(MainActivity.this);
//Check if the data change
if (!packages.equals(dao.getPackages())) {
adapter.updateList(dao.getPackages());
}
swipeRefreshLayout.setRefreshing(false);
}
SOLVED!
I've put the refresh code on a Runnable:
(I've changed my refresh too)
#Override
public void onRefresh() {
new Thread(new Runnable() {
#Override
public void run() {
try {
if (Update.updateAll(MainActivity.this)) {
packages = dao.getPackages(config.getFilter());
packagesAux = dao.getPackages(config.getFilter());
runOnUiThread(new Runnable() {
#Override
public void run() {
adapter.animateTo(packages);
}
});
}
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
swipeRefreshLayout.setRefreshing(false);
}
});
}
}).start();
}
You don't need to have setRefreshing(true) statement in onRefresh() method.
When we drag the Ui downward, the spinning things starts itself automatically.
You just need to setRefreshing(false) to stop the spinner at the place where your desired result is achieved, but not in onRefresh().
For example, if you are hitting an api, we need to setRefreshing(false) at that point where we get the response from server i.e onPostExecute or similar.
Here is how I use it:
/**
* on Refreshing, fetch trip history again.
*/
#Override
public void onRefresh() {
fetchTripHistory();
}
#Override
public void onFailOfResponse(Object... arguments) {
mSwipeRefreshLayout.setRefreshing(false);
noDataText.setVisibility(View.VISIBLE);
}
};
#Override
public void onRefresh() {
.....
RVAdapterMain adapter = new RVAdapterMain(packages);
recyclerView.setAdapter(adapter);
....
}
.....
}
First of this seems like wrong. Could you please use it in onCreate(). And create the new method add the new data inside your adapter. When you refresh it onRefresh method only notifiyDataSetChanged() with new dataset instead of every time using the new adapter.
I am making an app that counts up every second based on rate of pay, and as it is written now, it crashes on startup.
Am I doing the thread section wrong?
I am kind of new to android, so I am a bit unclear on the onCreate method in general. Any clarification about that and how it relates to my code would be helpful as well.
The button is supposed to start the count. I think it's crashing due to the t.start() line, but I don't know how to trigger the event.
package com.example.terik.myapplication;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView text2;
text2 = (TextView) findViewById(R.id.textView2);
Thread t = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
updateTextView();
}
});
}
} catch (InterruptedException e) {
}
}
};
t.start();
}
private void updateTextView() {
TextView text2;
double update;
double rateofPay = 9.00;
text2 = (TextView)findViewById(R.id.textView2);
CharSequence newtime = text2.getText();
int number = Integer.parseInt(newtime.toString());
update = number+ rateofPay;
text2.setText((int) update);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
One problem was a NumberFormatException when trying to parse a Double as an Integer.
The other problem was trying to call setText() with an int on this line:
text2.setText((int) update);
This fixed it:
private void updateTextView() {
TextView text2;
double update;
double rateofPay = 9.00;
text2 = (TextView)findViewById(R.id.textView2);
CharSequence newtime = text2.getText();
double number = Double.parseDouble(newtime.toString());
update = number+ rateofPay;
text2.setText(String.valueOf(update));
}
Edit:
Here's how you would only start the Thread when you click the Button. First make the Thread t an instance variable, so that it can be accessed in the button click run() method (you might want to re-name that method too!).
I just tested this, it worked for me:
public class MainActivity extends ActionBarActivity {
Thread t;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView text2;
text2 = (TextView) findViewById(R.id.textView2);
t = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
updateTextView();
}
});
}
} catch (InterruptedException e) {
}
}
};
}
public void run(View v) {
t.start();
}
private void updateTextView() {
TextView text2;
double update;
double rateofPay = 9.00;
text2 = (TextView)findViewById(R.id.textView2);
CharSequence newtime = text2.getText();
double number = Double.parseDouble(newtime.toString());
update = number+ rateofPay;
text2.setText(String.valueOf(update));
}
//.........
Edit 2:
As #BladeCoder mentioned in the comments, a Thread is really over-kill for this. Using a Handler and postDelayed() is really the best route for something like this.
Also, it would be better to make the TextView an instance variable so that you don't create a new reference every time you update it.
I tested this version as well:
public class MainActivity extends ActionBarActivity {
TextView text2;
Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text2 = (TextView) findViewById(R.id.textView2);
handler = new Handler();
}
Runnable updateText = new Runnable(){
#Override
public void run(){
updateTextView();
handler.postDelayed(this, 1000);
}
};
public void run(View v) {
handler.postDelayed(updateText, 1000);
}
private void updateTextView() {
double update;
double rateofPay = 9.00;
CharSequence newtime = text2.getText();
double number = Double.parseDouble(newtime.toString());
update = number+ rateofPay;
text2.setText(String.valueOf(update));
}
//.............
Instead of using thread to achieve this, you can achieve the same effect with a "neat way" using the Timer class.
Check this stackoverflow answer Android timer? How-to?
Regarding the onCreate method I suggest you to check the activity life cycle
Called when the activity is first created. This is where you should do all of your normal static set up: create views, bind data to lists, etc. This method also provides you with a Bundle containing the activity's previously frozen state, if there was one.
Always followed by onStart().
Check the documentation for further info http://developer.android.com/reference/android/app/Activity.html#onCreate(android.os.Bundle)
I have the following code, in which I try to connect to google.com and parse the text on that site:
package com.example.parsetest;
import java.io.IOException;
import org.jsoup.*;
import org.jsoup.nodes.Document;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
Thread downloadThread = new Thread() {
public void run() {
Document doc;
try {
doc = Jsoup.connect("http://google.com/").get();
String title = doc.title();
TextView console = (TextView) findViewById(R.id.textview1);
console.setText(title);
} catch (IOException e) {
e.printStackTrace();
}
}
};
}
My issue is that I'm unsure as to whether I've created my new thread properly, and where I'm supposed to call downloadThread.start() from - am I supposed to create a new class? Or do I call it from my onCreate method?
Yes you need to call downloadThread.start(). You cannot update ui from a background thread. Use runOnUiThread
public class MainActivity extends Activity {
TextView console;
String title;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
console = (TextView) findViewById(R.id.textView1);
new Thread() {
public void run() {
Document doc;
try {
doc = Jsoup.connect("http://google.com/").get();
title = doc.title();
runOnUiThread( new Runnable()
{
public void run()
{
console.setText(title); // set text on the ui thread
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
As other have suggested using asynctask is easier.
http://developer.android.com/reference/android/os/AsyncTask.html
Using AsyncTask
public class MainActivity extends Activity {
TextView console;
String title;
ProgressDialog pd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pd = new ProgressDialog(this);
pd.setMessage("Jsoup parsing...");
console = (TextView) findViewById(R.id.textView1);
new TheTask().execute();
}
class TheTask extends AsyncTask<Void,String,String>
{
#Override
protected String doInBackground(Void... arg0) {
// TODO Auto-generated method stub
Document doc;
try {
doc = Jsoup.connect("http://google.com/").get();
title = doc.title();
}
catch(Exception e)
{
e.printStackTrace();
}
return title;
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
pd.dismiss();
console.setText(title);
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
pd.show();
}
}
}
check out android AsyncTask usage example
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
the download should be taken place at doInBackground
I'm unsure as to whether I've created my new thread properly
Yes you have created Thread in right way but inside run method you are updating TextView text which is not valid because only main thread updated ui elements instead of any other thread. you should use runOnUiThread for updating TextView :
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
TextView console = (TextView) findViewById(R.id.textview1);
console.setText(title);
}
});
suggested way is use AsyncTask
where I'm supposed to call downloadThread.start() from
you should call downloadThread.start() in onCreate of Activity after setContentView
I am learning how to use asyncTask and I have issue with trying to display the TextView in real-time. The mainActivity have few buttons that will start new activity plus a TextView that show the value that changes for every 200 milliseconds. But the issue is that the TextView doesn't show up until I click on button to start another activity, and the value doesn't changes when I pressed "back button" to return to mainActivity. However, it does changes the value when I press button to start another activity.
private TextView t;
private int counter;
private boolean isUiVisible = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
t = (TextView) findViewById(R.id.counter);
counter = 0;
}
#Override
public void onStart(){
super.onStart();
isUiVisible = true;
new UpdateUi().execute();
}
#Override
public void onPause(){
super.onPause();
isUiVisible = false;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private class UpdateUi extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
while (true) {
if (isUiVisible) {
counter++;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
// Ensure the asynkTask ends when the activity ends
break;
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
t.setText(counter + "");
}
}
public void callRed(View view){
Intent intent = new Intent(this, RedActivity.class);
startActivity(intent);
}
public void callYellow(View view){
Intent intent = new Intent(this, YellowActivity.class);
startActivity(intent);
}
I have tried setText in onProgressUpdate, but it showed nothing. I also searched to see if other have issues, but it seems that they do have same issue as mine (one was onClickListener, which was not what I was looking for).
The TextView doesn't show up probably because it has no text inside it...cannot tell for sure without looking at the layout.xml file.
You got that behaviour because the variable isUiVisible becomes false only when onPause() is called, that is when you switch activity. At that point the AsyncTask exits his doInBackground method and executes onPostExecute which puts some text in the TextView making it appears.
To try to fix your code you should call publihProgress() inside doInBackground and then use onProgressUpdate to update your TextView in the UIThread.