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.
}
}
Related
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);
}
}
In my Activity, I load the content for a list from a DB, and want to display a ProgressDialog while it´s loading.
I got both working on it´s own, but if I load the data in a thread (which I should do?), the list is displayed before it´s data is loaded. But if I use join, the ProgressDialog doesnt even appear.
How can I combine this? Or is this not possible at all with threads? (AsyncTask maybe?)
Here´s the code for reference:
final ProgressDialog progressD=ProgressDialog.show(ShopSwitchActivity.this, "", "Loading..", true);
Thread myThread = new Thread(new Runnable() {
#Override
public void run() {
try
{
getData();
}catch(Exception e){}
}
});
myThread.start();
try {
myThread.join();
} catch (InterruptedException e) {
}
progressD.dismiss();
EDIT: Updated Code with AsyncTask:
public class LoadList extends AsyncTask<String, Void, Boolean> {
ProgressDialog dialog;
ShopSwitchActivity activity;
public LoadList(ShopSwitchActivity activity) {
this.activity = activity;
dialog = new ProgressDialog(activity);
}
protected void onPreExecute() {
this.dialog.setMessage("Loading...");
this.dialog.show();
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
}
protected Boolean doInBackground(final String... args) {
try{
activity.getData();
} catch (Exception e) {
Log.e("error", e.getMessage());
}
return true;
}
}
Edit: My Solution
Using AsyncTask now to load the Data, and after it´s done, I refresh the list with the new data.
You can do it with AsyncTask. Write AsyncTask class in your main class that you want to do your operations. You can create the progress dialog in preexcecute of your async class and dismiss in onpostexecute of async class. Here is how you will do this:
class MyAsync extends AsyncTask<String, Void, Void> {
ProgressDialog pd;
Context co;
MyActivity ma;
public MyAsync (MyActivity ma){
this.ma= ma;
this.co = ma;
pd= new ProgressDialog(co);
}
#Override
protected void onPreExecute() {
this.pd.show();
super.onPreExecute();
}
#Override
protected Void doInBackground(String... params) {
// do your database operations here
return null;
}
#Override
protected void onPostExecute(Void result) {
// show db results and dismiss progress dialog pd.dismiss();
super.onPostExecute(result);
}
}
in MyActivity call as :
MyActivity ma = this;
new MyAsync(ma).execute();
You seem to miss the point of a thread. A thread occurs at the same time as your application. So your app doesn't call start then wait for the thread to be over- if it did you could just use a function. Instead your code continues to run. So if you just call join immediately, you're not doing anything. You'd get around a NetworkOnMainThreadException this way, but you'd still hold up the UI thread making your app totally non-responsive (and as a result not showing the dialog), and you'd eventually crash when a watchdog timer kills you.
Instead, the best way to handle this is to use an AsyncTask. Call getData in doInBackground(). Then dismiss the dialog in onPostExecute.
You should use AsyncTask instead actually.
Here is the link to the library. It is fairly simple:
1) onPreExecute() = show ProgressDialog
2) doInBackground() = execute your code
3) onPostExecute() = dismiss ProgressDialog
Here's a nice tutorial too.
In general:
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(this.context);
dialog.setMessage("Loading...");
dialog.setCanceledOnTouchOutside(false);
}
#Override
protected void onPostExecute(String result) {
if(dialog.isShowing()) {
dialog.dismiss();
}
}
private Thread myThread;
private ProgressDialog mProgDialog;
mProgDialog = ProgressDialog.show(ShopSwitchActivity.this,"","Laden..", true);
myThread= new Thread(new Runnable()
{
public void run()
{
myThread.setPriority(Thread.MIN_PRIORITY);
try
{
getData();
}catch(Exception e){}
runOnUiThread(new Runnable()
{
public void run()
{
if (mProgDialog != null&& mProgDialog.isShowing())
mProgDialog.dismiss();
} }
});
}
});
myThread.start();
What can I do, if I'm in any Activity and I want download a file (using thread) and at same time I want the main thread waits until download is finished?
Use AsyncTask.. from activity
new DownloadTask(this).execute();
The task for example:
public class DownloadTask extends AsyncTask<Void, Void, String> {
private ProgressDialog progressDialog;
private Context context;
/**
*
* #param context
* #param pdfDoc the document of the PDF
*/
public DownloadTask(Context context) {
this.context = context;
progressDialog = new ProgressDialog(context);
}
#Override
protected void onPreExecute() {
progressDialog.setMessage("Downloading...");
progressDialog.setIndeterminate(true);
progressDialog.show();
}
#Override
protected String doInBackground(Void... arg0) {
//download here
}
#Override
protected void onPostExecute(final String result) {
progressDialog.dismiss();
}
}
Use AsyncTask and callbacks.
public interface DownloadCallback<T>{
public void onFinishDownload(T downloadedResult);
}
public static void downloadString(String url, DownloadCallback<String> callback){
new AsyncTask<Void,Void,Void>(){
String result;
#Override
protected void onPreExecute() {
// Do things before downloading on UI Thread
}
#Override
protected String doInBackground(Void... arg0) {
//download here
result = download(url);
}
#Override
protected void onPostExecute(final Void result) {
// Do things on UI thread after downloading, then execute your callback
if (callback != null) callback.onFinishDownloading(result);
}
}.execute();
}
And to use this, you just do this:
downloadString("http://www.route.to.your.string.com", new DownloadCallback<String>(){
public void onFinishDownloading(String downloadedResult){
Toast.makeText(YourActivityName.this, downloadedResult, Toast.LENGTH_SHORT).show();
}
});
If you want the thread to communicate with he main thread, telling that download is finished, use a handler
This code will help you understand it
MyHnadler handler;
onCreate(Bundle savedInstance)
{
setContent..
...
handler=new MyHandler();
new MyThread().start();
}
public class MyHandler extends Handler
{
#Override
public void handleMessage(Message message) {
switch (message.what) {
case 1: //....threading over
//write your code here
break;
case2 : //if you want to be notiifed of something else
..
}
public class MyThread extends Thread
{
#Override
public void run()
{
//run the threa
//and when over
Message msg=handler.getMessage();
msg.what=1;
handler.sendMessage(msg); //send the message to handler
}
}
}
As you can see the thread communicates with the UI thread via the Handler. In the above example, I have only sent any object from the thread to the UI thread. To do that just do msg.obj=your_obj in the thread. It can be any object. Hope this helps you:)
I found this code in SO to show ProgressDialog while load Activity:
progDailog = ProgressDialog.show(MyActivity.this, "Process", "please wait....", true, true);
new Thread(new Runnable() {
public void run() {
// code for load activity
}).start();
Handler progressHandler = new Handler() {
public void handleMessage(Message msg1) {
progDailog.dismiss();
}
};
But I always get this exception:
java.lang.RuntimeException: Can't create handler inside thread that
has not called Looper.prepare()
I appreciate any help for this issue, thanks in advance.
Here is what I would do,
AsyncTask to do the "heavy work" in background:
public class MyTask extends AsyncTask<String, String, String> {
private Context context;
private ProgressDialog progressDialog;
public MyTask(Context context) {
this.context = context;
}
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(context);
progressDialog.show();
}
#Override
protected String doInBackground(String... params) {
//Do your loading here
return "finish";
}
#Override
protected void onPostExecute(String result) {
progressDialog.dismiss();
//Start other Activity or do whatever you want
}
}
Start the AsyncTask:
MyTask myTask = new MyTask(this);
myTask.execute("parameter");
Of course you can change the generic types of the AsyncTask to match your problems.
The problem is because you are trying to create Handler inside a worker Thread. It is not possible. Create your Handler inside of onCreate() or somewhere else on the main UI. And you can send message to your handler from your Worker Thread.
This is because Android doesn't allow you to modify the UI from any other Thread other than the Main UI thread itself.
You need to create your handler on the main thread rather than inside OnClick.
I am building a project in which i use async task to show progress bar.
I am using get() method to wait the main thread so we can do the other task before .
but progress bar is showing after completion of doInBackground thered.
I Want to show the loading bar when the loading starts.
It will dismiss when onPostExecute calls.
public class TempConverterActivity extends Activity {
pojo p;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button b= (Button) findViewById(R.id.btn);
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
showResult();
}
});
}
private void showResult() {
try {
new LoadData().execute().get();
} catch (Exception e) {
Log.e("async brix--", e.getMessage());
}
runned();
}
private void runned() {
ArrayList<String> al = p.getData();
for (String str : al){
Toast.makeText(getApplicationContext(), str, Toast.LENGTH_SHORT).show();
}
}
private class LoadData extends AsyncTask<Void, Void, Void> {
private final ProgressDialog dialog = new ProgressDialog(TempConverterActivity.this);
protected void onPreExecute() {
dialog.setMessage("Loading data...");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.show();
}
protected void onPostExecute(final Void unused) {
if (dialog.isShowing()) {
dialog.dismiss();
}
}
#Override
protected Void doInBackground(Void... params) {
p = new pojo();
new SoapParser(p);
return null;
}
}}
Please help . Thanks in advance.
You can try following code,
progDailog = ProgressDialog.show(loginAct,"Process ", "please wait....",true,true);
new Thread ( new Runnable()
{
public void run()
{
// your code goes here
}
}).start();
Handler progressHandler = new Handler()
{
public void handleMessage(Message msg1)
{
progDailog.dismiss();
}
}
Edited: In my previous answer I suggested using a Handler; however, AsyncTask eliminates the need to do this which I didn't spot.
Why do you feel the need to call AsyncTask.get()? This is a blocking call, and you call this from the UI thread, thus it is ultimately a race condition as to whether it or onPreExecute() is run first.
I see no reason why you should call get() in this context. You want to call runned() after the AsyncTask completes, but you could do this by launching a new thread from onPostExecute(). Alternatively you could do as you do now, using get(), but call that from a new thread instead of the UI thread.