I have designed an app that gets the network information and updates the UI every 5 seconds.
It is advised to do the background processes on a separate thread than the UI thread, and I did so...but I still get an error that:
"I/Choreographer﹕ Skipped 3730 frames! The application may be doing
too much work on its main thread."
Why is that?
Here's my code
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
wifiTextView = (TextView)findViewById(R.id.wifi_textView);
ipTextView = (TextView)findViewById(R.id.ip_val_textView);
// and so on
//Updating the UI every mInterval seconds, using a separate thread than UI thread
Thread backgroundThread = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(mInterval);
runOnUiThread(new Runnable() {
#Override
public void run() {
//Log.d(DEBUG_TAG, "run(): Background thread");
MyNetwork network = new MyNetwork(getApplicationContext()); // passing the context
updateUI(network);
}
});
}
} catch (InterruptedException e) {
wifiTextView.setText("Exception: Please Close and Restart the App");
}
}
};
backgroundThread.start();
}
In the same MainActivity class, I have this private function:
private void updateUI(MyNetwork network){
// Handles updating the textviews in the UI
//Log.d(DEBUG_TAG, "updateUI(DeepstreamNetwork)");
if (network.isConnected()){
wifiTextView.setText(R.string.wifi_is_on);
wifiTextView.setTextColor(Color.GREEN);
ipTextView.setText(network.getIpAddress());
else {
wifiTextView.setText(R.string.wifi_is_off);
wifiTextView.setTextColor(Color.RED);
ipTextView.setText("N/A");
}
}
UPDATE
So, I have updated my MainActivity class to have this MyAsyncTask method to handle background work...here's my code:
private class MyAsyncTask extends AsyncTask<Void, Void, MyNetwork> {
#Override
protected void onPostExecute(MyNetwork network) {
updateUI(network);
}
#Override
protected MyNetwork doInBackground(Void... params) {
MyNetwork network = new MyNetwork(getApplicationContext()); // passing the context
return network;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
Two issues:
1) how do I force it to do this background task every 5 seconds. Since the network status changes every few secs (disconnection etc...), so I want it to update the UI respectively.
2) should I call it like this in MainActivity: new MyAsyncTask().execute();
Thanks all
I dont know why you called it Thread backgroundThread = new Thread() because runOnUiThread() is really the main Thread.
You should try this in an asynctask where you only update the UI in onPostExecute()
EDIT:
private class MyAsyncTask extends AsyncTask<Void, Void, String> {
private MyNetwork network;
#Override
protected void onPreExecute() {
this.network = new MyNetwork(getApplicationContext());
}
#Override
protected String doInBackground(Void... params) {
return network.getIpAddress();
}
#Override
protected void onPostExecute(String ipAddress) {
if (this.network.isConnected()){
wifiTextView.setText(R.string.wifi_is_on);
wifiTextView.setTextColor(Color.GREEN);
ipTextView.setText(ipAddress);
else {
wifiTextView.setText(R.string.wifi_is_off);
wifiTextView.setTextColor(Color.RED);
ipTextView.setText("N/A");
}
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
Related
Right now I'm facing a problem which I cannot solve, There's a thread which I need to fill two arrays with specific data, and then use these two arrays later, however, my main thread does not wait for the thread to finish and I don't know why!!
Here is my code
private void loadingData(){
Thread myThread=new Thread(new Runnable() {
#Override
public void run() {
getNationalities();
getReligions();
}
});
myThread.start();
try {
myThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
loadingIcon.show();
while(myThread.isAlive()){}
//Here I'm using the two filled arrays
nationalitySpinner();
religionSpinner();
loadingIcon.hide();
}
You can't run asynchronous Networking or time-consuming operation in the in main thread it will freeze the UI.
Try to use AsyncTask, in OnPostExecute of AsyncTask you can update in UI
Example :
private void loadingData(){
new MyTask().execute();
}
class MyTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
loadingIcon.show();
}
#Override
protected Void doInBackground(Void... voids) {
getNationalities();
getReligions();
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
nationalitySpinner();
religionSpinner();
loadingIcon.hide();
}
}
For more info refer Processes and threads, AsyncTask
I have a specific case where I want to run an AsyncTask's doInBackground on UI Thread. How can I do that?
You definitively could, but as #Devrath said, it is pointless. AsyncTask are used for background operation.
Here is a sample that uses the runOnUiThread method:
private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
runOnUiThread(new Runnable() {
#Override
public void run() {
// WORK on UI thread here
}
});
return null;
}
#Override
protected void onPostExecute(Void result) {
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(Void... values) {}
}
I ended up doing the following:
Got all the code from doInBackground and moved it to a method.
In doInBackground I make a call only to this method.
In the cases where I need the asynctask to be executed normally, I call LongOperation().execute()
In the cases where I need the asynctask to be ran on the UI thread, I dont call it but I call the method instead.
Try this
public void commentBuilder() {
new Thread(new Runnable() {
#Override
public void run() {
//Your code
}
}).start();
}
Also, see this for more detail https://stackoverflow.com/a/14038370
As far i know ..... You cannot !
AsyncTask are designed to perform background task which takes
longer time to perform
So they have to be performed in a seperate thread different from the
mainthread
Mainthread takes care of all the UI for your app
If you want ot update a UI while performing a background operation::
Just use onProgressUpdate method of the AsyncTask to update the
UI during the background operation
else use onPre method to update UI before the beckground call is
made
Else finally use onPost method to update after rte async task
completes doInBackground
{SAMPLE}
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.interrupted();
}
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed"); // txt.setText(result);
// might want to change "executed" for the returned string passed
// into onPostExecute() but that is upto you
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(Void... values) {}
}
I want to show the progress dialog while loading the images in grid view.
The problem i'm facing was the current thread and Progress Dialog thread running simultaniously.
public String Method1(){
String output="";
final ProgressDialog aProgDialogL = ProgressDialog.show(this, "", "Loading...");
Thread thread = new Thread() {
public void run () {
//My codes
aHandlerL.post(new Runnable() {
#Override
public void run() {
//Post Runnable codes
aProgDialogL.dismiss();
}
});
}
};
thread.start();
/*
*
*
* OTHER CODES
*
*
*/
return output;
}
In the above example I need to run the code inside Progress Dialog Thread. After it finish executing i need to run my "OTHER CODES". How to do it?
.
I tried using Async task. Before async task completes method1 gets extcuted and reurning the string.
public String Method1(){
String result="";
new GetImages().execute();
return result;
}
public class GetData extends AsyncTask<Void, Void, Integer>{
#Override
protected void onPreExecute() {
aProgDialogL = ProgressDialog.show(Main.this, "", "Loading...");
}
#Override
protected Integer doInBackground(Void... params) {
//Progress Dialig Code
return null;
}
#Override
protected void onPostExecute(Integer result) {
aProgDialogL.dismiss();
//OTHER CODES
super.onPostExecute(result);
}
}
You can use Async task. http://developer.android.com/reference/android/os/AsyncTask.html. There is a good tutorial here. http://www.vogella.com/articles/AndroidPerformance/article.html.Also have a look at this link
http://developer.android.com/guide/components/processes-and-threads.html. Use asynctask modify it according to your needs.
doInBackground()- For long running operations. Don't update ui here.
onPreExecute()- update ui before running the operatio nin background.
onPostExecute()- update ui after running the operation.
I would suggest you to take somewhat different approach.
Dont involve any threads in Method1() function.Rather your Method1() function should be run under separate thread.
Below snippet will help you.
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((Button) findViewById(R.id.btnPopup))
.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
new Thread() {
public void run() {
String answer = Method1();
runOnUiThread(new Runnable() {
#Override
public void run() {
// Here you will write the code which is
// to be executed on main thread.
}
});
};
}.start();
}
});
}
public String Method1() {
// Write code
return "result";
}
}
Instead of that : What about use Timer After specific Time Stop Your thread and and write your code you want after stop statement Like that :
Timer timer=new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
thread.stop;
// Other code }
}, Time You want );
Because if I start an activity, and I launch the threads in the method onResume, the UI of Activity is displayed only when the thread ends?
#Override
protected void onResume() {
super.onResume();
processDocuments();
}
private void processDocuments(){
parser = new Parser(rssDocument.getDocument(),rssDocument.getFeedRSS(), listener);
Thread processThread = new Thread(parser);
processThread.start();
}
You need to run the thread in the background using AsyncTask
private class getRSSS extends AsyncTask<Void, Void, Void> {
#Override
protected String doInBackground(void... args) {
parser = new Parser(rssDocument.getDocument(),rssDocument.getFeedRSS(), listener);
Thread processThread = new Thread(parser);
processThread.start();
}
#Override
protected void onPostExecute(String result) {
//Set a toast to say finished. You are allowed to update the UI here.
}
}
Ok this is a very weird problem I am having, and I'm pretty sure that I am messing up somewhere, but I can't quite figure out where.
What I am trying is -
Schedule a Timer to execute a TimerTask every five seconds
The TimerTask in turn executes an AsyncTask (which in this case simple sleeps for a second before returning the static count of the number of AsyncTasks).
Finally, the aforementioned count is updated in the UI.
And of course, the appropriate Handlers and Runnables have been used to post asynchronous messages from other threads to the UI.
This code executes only once. I expect it to fire every 5 seconds. Here's the code.
Note: I had no idea what to do with the Looper. I put it there after trial and error!
public class TimerAsyncMixActivity extends Activity {
public static final String TAG = "TimerAsyncMix";
static int executionCount = 0;
Handler mHandler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new Timer().schedule(new MyTimerTask(this), 0, 5000);
}
class MyAsyncTask extends AsyncTask<String, Void, Integer>{
#Override
protected Integer doInBackground(String... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ++executionCount;
}
#Override
protected void onPostExecute(Integer result) {
mHandler.post(new UpdateUiThread(TimerAsyncMixActivity.this, result));
super.onPostExecute(result);
}
}
}
class MyTimerTask extends TimerTask{
private TimerAsyncMixActivity tma;
public MyTimerTask(TimerAsyncMixActivity tma) {
this.tma = tma;
}
#Override
public void run() {
Looper.prepare();
Log.d(TimerAsyncMixActivity.TAG, "Timer task fired");
tma.new MyAsyncTask().execute();
Looper.loop();
Looper.myLooper().quit();
}
}
class UpdateUiThread implements Runnable{
int displayCount;
TimerAsyncMixActivity tma;
public UpdateUiThread(TimerAsyncMixActivity tma, int i) {
this.displayCount = i;
this.tma = tma;
}
#Override
public void run() {
TextView tv = (TextView) tma.findViewById(R.id.tvDisplay);
tv.setText("Execution count is : "+displayCount);
}
Can anyone point me to what I'm doing wrong?
techie, this is how I implemented similar things. I'm won't claim that this is the best way, but it has worked for me and doesn't look too bad.
I have the following code in my activity. I create an async task when the activity starts and I stop it onPause. The AsyncTask does whatever it needs to do, and updates the UI on onProgressUpdate() (which is run on the UI thread, so there's no need to use a Handler).
private Task task;
#Override
protected void onPause() {
task.stop();
task = null;
}
#Override
protected void onResume() {
task = new Task();
task.execute();
}
private class Task extends AsyncTask<Void, String, Void> {
private boolean running = true;
#Override
protected Void doInBackground(Void... params) {
while( running ) {
//fetch data from server;
this.publishProgress("updated json");
Thread.sleep(5000); // removed try/catch for readability
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
if( ! running ) {
return;
}
String json = values[0];
//update views directly, as this is run on the UI thread.
//textView.setText(json);
}
public void stop() {
running = false;
}
}
Do not use a timer. If your phone goes to sleep, the timer is suspended too. Use AlarmManager.