My MainActivity has 2 views: TextView and a Button. On button click, I am running an AsyncTask which further creates 10 new AsyncTasks for network operations. Every new task creation is delayed by 1 sec. The code is:
public class MainActivity extends ActionBarActivity
{
TextView tv;
Button t;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.textView1);
t = (Button) findViewById(R.id.toggleButton1);
t.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
getData();
}
});
}
void getData()
{
SuperNetworkAsyncTask s = new SuperNetworkAsyncTask();
s.execute("");
}
private class SuperNetworkAsyncTask extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... urls)
{
for(int i=0;i<10;i++)
{
{
nTask = new NetworkAsyncTask();
nTask.execute("");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return "";
}
#Override
protected void onPostExecute(String result)
{
}
}
private class NetworkAsyncTask extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... urls)
{
return String.valueOf(System.currentTimeMillis());
}
#Override
protected void onPostExecute(String result)
{
tv.setText(result);
}
}
}
I was expecting that the moment first NetworkAsyncTask execute method is called, it will start execution. But when I run it, I do not find any NetworkAsyncTask begin its execution until the control comes out of SuperNetworkAsyncTask. Is there any way to push the execution of NetworkAsyncTask thread as soon as execute method is called?
Some clarifications:
Why NetworkAsyncTask are created by SuperNetworkAsyncTask? Because If I create the NetworkAsyncTask in main thread, I get my UI freeze for some time.
Why making 10 object? The purpose of NetworkAsyncTask is to read data from a server at interval of 1 sec for n seconds, here n=10.
Part 2: Updates after doing some tests.
Observation 1:
As a fellow Brian shared a way to avoid creating AsyncTasks in nested way, I tried his code:
void getData() {
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
nTask = new NetworkAsyncTask();
nTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
new Thread(runnable).start();
}
This freezes my UI for few seconds and then the screen is updated in a fraction of second. It is quite surprising to me too.
Observation 2:
With java.lang.Thread, I experimented to make sure that 1) The threads should be executed right away when run() called. 2) The next task will be created only after previous task is finished.
Code:
public static void main(String[] args) {
myThread m;
for (int i=0;i<10;i++)
{
m=new myThread(String.valueOf(i));
m.start();
synchronized (m)
{
try {
m.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class myThread extends Thread
{
public String name = "";
public myThread(String n)
{
name = n;
}
public void run()
{
synchronized (this)
{
System.out.println(" Thread Name = " + name);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
notifyAll();
}
}
}
Output:
Thread Name = 0
Thread Name = 1
Thread Name = 2
Thread Name = 3
Thread Name = 4
Thread Name = 5
Thread Name = 6
Thread Name = 7
Thread Name = 8
Thread Name = 9
Based in this, I updated my NetworkAsyncTask & SuperNetworkAsyncTask as:
private class NetworkAsyncTask extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... urls)
{
synchronized (this)
{
return String.valueOf(System.currentTimeMillis());
}
}
#Override
protected void onPostExecute(String result)
{
synchronized (this)
{
tv.setText(result);
notifyAll();
}
}
}
private class SuperNetworkAsyncTask extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... urls)
{
for(int i=0;i<10;i++)
{
nTask = new NetworkAsyncTask();
nTask.execute(url);
synchronized (nTask)
{
try {
nTask.wait();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return "";
}
#Override
protected void onPostExecute(String result)
{
}
}
With this code the wait() keeps on waiting indefinitely.
Finally I replaced:
nTask.execute(url);
with
nTask.executeOnExecutor(THREAD_POOL_EXECUTOR, "");
This worked well as expected.
The UI will be updated only at onPostExecute(). See notes on AsyncTask
Click here! And Try to avoid 10 AysncTasks, it does not make any sense.
You don't need to use a "super async task" use a runnable and then create new async tasks in parallel
void getData() {
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
nTask = new NetworkAsyncTask();
nTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
new Thread(runnable).start();
}
Post honeycomb you can specify to run async tasks in parallel
An AsyncTask should be started in the UI thread, not on the one doInBackground runs on. You could call publishProgress after every sleep, and spawn each AsyncTask in the resulting calls to onProgressUpdate, which run on the UI thread.
Related
I have same stock item , I want to send local database to ApiService, But when I send also I want to update ProgressBar message. I tried the code below but it just shows when all proccessing is finishing.
ProgressDialog progress= new ProgressDialog(this);
progress.setTitle(getResources().getString(R.string.progress_exporting));
progress.setMessage("0/0");
when click button I call below method
public void Export() {
runOnUiThread(new Runnable() {
#Override
public void run() {
findViewById(R.id.btnExportOnlineWithStocktaking).setEnabled(false);
progress.show();
}
});
UpdateUI(send, total);
try {
switch (_stocktakingType) {
case Division: {
switch (_onlineExportType) {
case Item: {
isExport = ExportDivisionStocktakingItems(stocktakingId);
}
break;
}
} catch (Exception ex) {
}
}
// ExportDivisionStocktaking method
public boolean ExportCustomStocktakingItems(int stocktakingId) {
result = Boolean.parseBoolean(SendCustomStocktakingItems(stocktakingId,countResults).responseString);
}
My call back method
public ResponseModel SendCustomStocktakingItems(int selectedDivision, List<ExtensionServiceStocktakingItem> countResults) throws ExecutionException, InterruptedException {
return new SendCustomStocktakingItemsService(flag -> true).execute(String.valueOf(selectedDivision), countResults.toString()).get();
}
//AsyncTask method
public class SendDivisionStocktakingItemsService extends AsyncTask<String, Void, ResponseModel> {
public AsyncResponseSendDivisionStocktakingItems delegate = null;
public SendDivisionStocktakingItemsService(AsyncResponseSendDivisionStocktakingItems delegate) {
this.delegate = delegate;
}
#Override
protected ResponseModel doInBackground(String... parameters) {
RequestHandler requestHandler = new RequestHandler();
JSONObject params = new JSONObject();
try {
params.put("stocktakingItems", parameters[1]);
} catch (JSONException e) {
e.printStackTrace();
}
ResponseModel responseModel = requestHandler.getRequestPostString(UHFApplication.getInstance().apiUrl
+ "/api/MobileService/SendDivisionStocktakingItemsPost?stocktakingID="
+ parameters[0],
parameters[1]);
return responseModel;
}
#Override
protected void onPreExecute() {
UpdateUI(send,total);
super.onPreExecute();
}
#Override
protected void onPostExecute(ResponseModel responseModel) {
super.onPostExecute(responseModel);
if (HttpURLConnection.HTTP_OK == responseModel.httpStatus) {
delegate.processFinish(true);
} else {
delegate.processFinish(false);
}
}
}
//UICalled method
public void UpdateUI(int send, int total) {
runOnUiThread(() -> {
progress.setMessage(send + "/" + total);
Log.d("Send Data : ", send + "/" + total);
if (send == total) {
progress.dismiss();
Toast.makeText(getApplicationContext(), "Succsess", Toast.LENGTH_SHORT).show();
}
});
}
//Update
//Ok I have a simle example how can I use. Below code when I click button I wan to open progress firstly and after that for loop is working and update progres message. I try it but not working.
Firstly For loop is working and after that progres opened.
public void ExportTry(){
UpdateUI(send,total);
runOnUiThread(new Runnable() {
#Override
public void run() {
btnExport.setEnabled(false);
progress.show();
}
});
for(int i=0;i<1000000;i++){
UpdateUI(i,1000000);
}
}
You are missing the part of AsyncTask that will allow you to show progress messages while doInBackground is running. Take a look at onProgressUpdate and publishProgress on the same page.
publishProgress
void publishProgress (Progress... values)
This method can be invoked from doInBackground(Params...) to publish updates on the UI thread while the background computation is still running. Each call to this method will trigger the execution of onProgressUpdate(Progress...) on the UI thread. onProgressUpdate(Progress...) will not be called if the task has been canceled.
I am trying to publish two different kinds of progress in my background process. I am trying to publish a string sometime and an integer another time. I am handling both kinds of arguments in the onProgressUpdate by overloading them too. But when I declare my AsyncTask class, I have the arguments that is why it is expecting me to send only string type arguments. Is there a way to handle both type of publishProgress events?
Basically there are two ways to address your issue:
The first one is very simple, where you just always publishUpdate(String), and then in your onProgressUpdate(String) checks whether the string is an int or a string, and handle each case differently like this:
private class MyAsyncTask extends AsyncTask<Void, String, Void> {
//Executed on main UI thread.
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
try{
Integer i = Integer.parseInt(values[0]);
TextView v1 = (TextView) findViewById(R.id.textView1);
v1.setText(String.valueOf(i));
}
catch(NumberFormatException e){
TextView v2 = (TextView) findViewById(R.id.textView3);
v2.setText(values[0]);
}
}
#Override
protected Void doInBackground(Void... params) {
int i = 0;
while(i < 100){
try {
if(i%2 == 0){
publishProgress("Divisible by 2: " + String.valueOf(i));
}
publishProgress(String.valueOf(i));
i++;
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
}
In the above example I just try and parse the string to an Integer - if it works then I am 100% sure it is an int - if it throws an exception then it is a String.
If you want more control however, you need to implement your own version of AsyncTask, that support one or more progress updates. The only way you can achieve this is by using Handlers (http://developer.android.com/reference/android/os/Handler.html) and Thread (http://developer.android.com/reference/java/lang/Thread.html) directly (preferably wrapped in a more logical class similar to AsyncTask):
import android.os.Handler;
import android.os.Looper;
public abstract class DIYAsyncTask<Params, IntProgress, StringProgress, Result> {
private Result backGroundResult;
//Run on UI thread
#SuppressWarnings("unchecked")
protected void execute(Params... params){
final Params[] thisParams = params;
Thread worker = new Thread(){
public void run(){
prepareForPreExecute();
backGroundResult = doInBackground(thisParams);
prepareForPostExecute();
}
};
worker.setPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
worker.start();
}
//Code to start onPreExecute on UI thread
private void prepareForPreExecute(){
Handler ui_handler = new Handler(Looper.getMainLooper());
ui_handler.post(
new Runnable(){
public void run(){
onPreExecute();
}
}
);
}
//Code to start onPostExecute on UI thread
private void prepareForPostExecute(){
Handler ui_handler = new Handler(Looper.getMainLooper());
ui_handler.post(
new Runnable(){
public void run(){
onPostExecute(backGroundResult);
}
}
);
}
//Always run on worker thread
#SuppressWarnings("unchecked")
protected abstract Result doInBackground(Params... params);
//Always run on UI
protected void onPreExecute(){
}
//Always run on UI
protected void onPostExecute(Result result){
}
//Run on worker
#SuppressWarnings("unchecked")
protected void publishIntProgress(IntProgress... values){
Handler ui_handler = new Handler(Looper.getMainLooper());
final IntProgress[] thisProgress = values;
ui_handler.post(
new Runnable(){
#Override
public void run(){
onIntProgressUpdate(thisProgress);
}
}
);
}
//Always run on UI
#SuppressWarnings("unchecked")
protected void onIntProgressUpdate(IntProgress... values){
}
//Run on worker
#SuppressWarnings("unchecked")
protected void publishStringProgress(StringProgress... values){
Handler ui_handler = new Handler(Looper.getMainLooper());
final StringProgress[] thisProgress = values;
ui_handler.post(
new Runnable(){
#Override
public void run(){
onStringProgressUpdate(thisProgress);
}
}
);
}
//Always run on UI
#SuppressWarnings("unchecked")
protected void onStringProgressUpdate(StringProgress... values){
}
}
Which you can then override like this (notice the similarity to just using AsyncTask)
private class MyDIYAsyncTask extends DIYAsyncTask<Void, Integer, String, Void> {
//Executed on main UI thread.
#Override
protected void onIntProgressUpdate(Integer... values) {
super.onIntProgressUpdate(values);
TextView v = (TextView) findViewById(R.id.textView1);
v.setText(String.valueOf(values[0]));
}
#Override
protected void onStringProgressUpdate(String... values) {
super.onStringProgressUpdate(values);
TextView v = (TextView) findViewById(R.id.textView3);
v.setText(values[0]);
}
#Override
protected Void doInBackground(Void... params) {
int i = 0;
while(i < 100){
try {
publishIntProgress(i);
publishStringProgress("MyString" + String.valueOf(i));
i++;
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
}
This is my code: (Some random text to complete question osdifhgsoid hgodfhgo hsdhoigifdshgnvfa oidvojd nobndisfn vbjobsf).
private class DownloadFilesTask extends AsyncTask<String, Integer, Long> {
protected Long doInBackground(String... urls) {
try{
Listen();
}
catch (Exception x)
{
textIn.setText("shit! " + x.toString());
}
long i = 10;
return i;
}
}
(Some random text again to complete question(stupid system) dpfgojd ipgsdigjsidoignsdog
public void Listen(){
int count = 0;
TextView msg = MyActivity.msg;
ServerSocket server;
Socket client;
try {
server = new ServerSocket(9797);
Log.d("My log", "server started");
Log.d("My log", "waiting for connnections");
while (started) {
try{
msg.setText("waiting for connection"); <=== here crashing
client = server.accept();
count++;
Log.d("My Log", "Connected");
Log.d("My Log", "aha" + count);
int i = 0;
String data = null;
byte[] bytes = new byte[1024];
InputStream is = client.getInputStream();
OutputStream os = client.getOutputStream();
while (is.available() == 0) {
try{
Thread.sleep(50);
}catch (Exception cc){}
}
is.read(bytes, 0, is.available());
os.write("hala".getBytes());
client.close();
}catch (Exception cc)
{
cc.toString();
}
}
} catch (Exception el) {
el.printStackTrace();
}
}
(Some random text to complete question). Please help
change it via the onPostExecute method!
The purpose of an AsyncTask is to do a long running task in a separate thread and then communicate the result back to the UI thread via onPostExecute().
Also, I'm not sure why you use Long as your return value since you do not seem to be using it. A much better solution would be to have Void as return value and save the exception and use that as an indicator if anything went wrong:
private class DownloadFilesTask extends AsyncTask<String, Integer, Void> {
private Exception exception = null;
#Override
protected Void doInBackground(String... urls) {
try{
Listen();
}
catch (Exception x) {
exception = x;
}
}
#Override
public void onPostExecute(Void result) {
if(exception != null) {
textIn.setText("shit! " + exception.toString());
}
else {
// long running task was completed successfully
}
}
}
Yes, because you are trying to set the TextView inside the doInBackground() method, and this is not allowed.
So there is a solution if you want to set the TextView inside the doInBackground() method, do the UI updating operations inside the runOnUiThread method.
Otherwise, suggestion is to do all the UI display/update related operations inside the onPostExecute() method instead of doInBackground() method of your AsyncTask class.
Good idea would be to return a String in doInBackground(), say exceptionCatched. You can set it to Exception title in catch() block and then in onPostExecuted() just check if(!TextUtils.isEmpty(exceptionCatched)) textIn.setText(exceptionCatched); That's it!
private class DownloadFilesTask extends AsyncTask<Void, Void,Long>{
#Override
protected Long doInBackground(Void... params) {
publishProgress(progress);
//calculate progress and value from your downloading logic
try {
} catch (Exception e) {
return (long) 0;
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
//dis method run deafult on UI thread , so every time u publish ur onProgressUpdate will be called and update ur text here
}
#Override
protected void onPostExecute(Long result) {
super.onPostExecute(result);
if(result==0){
//error occured
}
}
// in case of exception return the result as long value to promt to onPostExceute()
I'm guessing runOnUiThread. You can't update the UI from any other thread than the UI thread.
I'm executing the practically identical code (besides the return statement) in onCreate() in two different ways:
once in a Thread (that works)
and once in an AsyncTask
Somehow the Exception thrown in the AsyncTask can't even be debugged... do you have an idea why this code doesn't work in the AsyncTask and why I can't debug de Exception? (It is not present as a variable)
public class TrainingProgressActivity extends ActivityTemplate {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_training_progress);
// the not working AsyncTask variant
new ProgressGetterTask().execute("");
// the working Thread variant
new Thread(new Runnable() {
public void run() {
try {
RestTemplate restTemplate = RestTemplateFactory.createRestTemplate();
FeatureSetCollectionProgress i = restTemplate.postForObject(URLHelper.BASE_PATH+"training/progress", getDevice(), FeatureSetCollectionProgress.class);
System.out.println(i.getMobilityProgress().get(0).getTransportationMeanType().toString());
} catch(Exception e) {
System.out.println("ex");
e.printStackTrace();
}
}}).start();
}
/**
* ProgressGetterTask. (not working ???)
*/
private class ProgressGetterTask extends AsyncTask<String, FeatureSetCollectionProgress, FeatureSetCollectionProgress> {
protected FeatureSetCollectionProgress doInBackground(String... urls) {
try {
RestTemplate restTemplate = RestTemplateFactory.createRestTemplate();
return restTemplate.postForObject(URLHelper.BASE_PATH+"training/progress", getDevice(), FeatureSetCollectionProgress.class);
} catch(Exception e) {
e.printStackTrace();
return null; // setting breakpoint here, 'e' cannot be resolved to a variable.
}
}
protected void onPostExecute(FeatureSetCollectionProgress featureSetCollectionProgress) {
if(featureSetCollectionProgress!=null) {
} else {
}
}
}
}
I am trying to use ProgressDialog. when i run my app the Progress Dialog box show and disappear after 1 second. I want to show it on completion of my process.. Here is my code:
public class MainActivity extends Activity {
android.view.View.OnClickListener mSearchListenerListener;
private ProgressDialog dialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new YourCustomAsyncTask().execute(new String[] {null, null});
}
private class YourCustomAsyncTask extends AsyncTask <String, Void, Void> {
protected void onPreExecute() {
dialog = new ProgressDialog(MainActivity.this);
dialog.setMessage("Loading....");
dialog.setIndeterminate(true);
dialog.setCancelable(true);
dialog.show(); //Maybe you should call it in ruinOnUIThread in doInBackGround as suggested from a previous answer
}
protected void doInBackground(String strings) {
try {
// search(strings[0], string[1]);
runOnUiThread(new Runnable() {
public void run() {
// updateMapWithResult(); //Or call it onPostExecute before progressDialog's dismiss. I believe this method updates the UI so it should run on UI thread
}
});
} catch(Exception e) {
}
}
#Override
protected void onPostExecute(Void params) {
dialog.dismiss();
//result
}
#Override
protected Void doInBackground(String... params) {
// TODO Auto-generated method stub
return null;
}
}
}
Updated Question:
#Override
public void onCreate(SQLiteDatabase db) {
mDatabase = db;
Log.i("PATH",""+mDatabase.getPath());
mDatabase.execSQL(FTS_TABLE_CREATE);
loadDictionary();
}
/**
* Starts a thread to load the database table with words
*/
private void loadDictionary() {
new Thread(new Runnable() {
public void run() {
try {
loadWords();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
}
private void loadWords() throws IOException {
Log.d(TAG, "Loading words...");
for(int i=0;i<=25;i++)
{ //***//
final Resources resources = mHelperContext.getResources();
InputStream inputStream = resources.openRawResource(raw_textFiles[i]);
//InputStream inputStream = resources.openRawResource(R.raw.definitions);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
StringBuilder sb = new StringBuilder();
while ((word = reader.readLine()) != null)
{
sb.append(word);
// Log.i("WORD in Parser", ""+word);
}
String contents = sb.toString();
StringTokenizer st = new StringTokenizer(contents, "||");
while (st.hasMoreElements()) {
String row = st.nextElement().toString();
String title = row.substring(0, row.indexOf("$$$"));
String desc = row.substring(row.indexOf("$$$") + 3);
// Log.i("Strings in Database",""+title+""+desc);
long id = addWord(title,desc);
if (id < 0) {
Log.e(TAG, "unable to add word: " + title);
}
}
} finally {
reader.close();
}
}
Log.d(TAG, "DONE loading words.");
}
I want to show ProgressDialogue box untill all words are not entered in the database. This code is in inner calss which extends SQLITEHELPER. so how to can i use ProgressDialogue in that inner class and run my addWords() method in background.
You cannot have this
runOnUiThread(new Runnable() {
public void run() {
// updateMapWithResult(); //Or call it onPostExecute before progressDialog's dismiss. I believe this method updates the UI so it should run on UI thread
}
});
in your doInBackground().
Progress dialog doesn't take priority when there is some other action being performed on the main UI thread. They are intended only when the actions are done in the background. runonUIthread inside doInBackground will not help you. And this is normal behavior for the progressdialog to be visible only for few seconds.
You have two doInBackground() methods inside your AsyncTask Class. Remove the runOnUiThread() from First doInBackground() and move it to second doInBackground() which has #Override annotation.
I don't know whether you wantedly written two doInBackground() methods or by mistake but it is not good to have such confusion between the Method. Your AsyncTask is not calling the first doInBackground() and it will call doInBackground() which has #Override annotation. So your ProgressDialog is dismissed in 1 second of time as it returns null immediately.