Callable and future delay android main thread - android

I want to fetch some data from service by callable and future. This is one of my code:
#Override
public void getCIFilesType(Consumer<String> consumer) {
try {
consumer.accept(serviceExecutor.submit(() ->
service.getCi(EsupFactory.getConfigString(SETTING_ROOT_CI) + "GetCI",
translator.makeCiJsonObject("PCiName", "CI_FilesType")).execute())
.get().body().string());
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
I have 10 method like this that execute like above.I used Executor service to run callable :
ExecutorService serviceExecutor = Executors.newSingleThreadExecutor();
I'm my activity I have a menu and then click on one item in the menu a fragment is a transaction in activity. All of the thread tasks immediately started in onViewCreated in fragment:
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
presenter.getCis();
}
But when I clicked on the menu item UI is frizzed till all task down then transaction is down. This is not the first time that I have this problem. Every time I use callable and executor service I do not know why UI is frizzed!!!!
This is profiler :
Someone has some guidance for me!!? Please do not tell me to use asyncTask :-)
What is a read line?? In ui thread I just do transaction not execute long running task!!!

It happens because you're calling get() on the future returned by execute() method. According, to the docs,
If you would like to immediately block waiting for a task, you can use constructions of the form result = exec.submit(aCallable).get();
So, even though you use a background thread, by calling get you block your main thread until the background thread finishes your task.
To avoid UI junks you should've used callbacks.

Related

Communication between main thread and worker threads in android

In my very first android project, I do some data manipulation, so I use multi-threading approach.
In MainActivity, I created multiple Runnable object and use ExecutorService to run all the threads. As my understanding, all threads are put in message queue and executed in turn. And the because the main thread is already in the queue, it will be executed before starting other threads. Is there any way that I can make the main thread wait for other threads to finish and then continue?
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//call MyFunction here
}
private List<Pair[]> myFunction(int dataInput) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(12);
MyTask MyTask = new MyTask();
for (int i = 0; i < gallerySize; ++i) {
final int index = i;
Runnable runnable = MyTask.runLongOperationWithThread(new MyTask.DataCallback(){
#Override
public void onSuccess(double[] scores) {
// get data back to main thread
}
#Override
public void onError(Exception ex) {
//TODO: log this error out to file
}
});
executorService.execute(runnable);
}
// try to get back all data from multi threading and do some operations
return returnList;
}
Do Looper and Handler help in this case?
And please correct me if I have any misunderstanding in android concept and threading.
Thanks.
In Android, stopping main thread is discouraged. The system will tell the user that the app is not responding. However, you can "notify" the main thread that the background thread has finished its work. Once the main thread knows this, it will do something. It is common in Android, it is what AsyncTask for.
However, AsyncTask is used for a simple one thread. In your case, one of the solution is to combine ExecutorService and AsyncTask. In doInBackground method of AsyncTask instance you make, use ExecutorService like usual, and wait it to finish by either shutdown(); awaitTermination() or invokeAll(). Read this question/answer for more information about how to wait ExecutorService to finish.
private class WrappingTask extends AsyncTask<Void, Void, Exception> {
protected Exception doInBackground(Void... args) {
ExecutorService taskExecutor = Executors.newFixedThreadPool(12);
for (. . .) {
taskExecutor.execute(new MyTask(. . .));
}
taskExecutor.shutdown();
try {
taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
. . .
return e;
}
return null;
}
protected void onPostExecute(Exception error) {
// Notify the user that the task has finished or do anything else
// and handle error
}
}
In case of long running task
AsyncTask is a handy class to make threading and communicating (to main thread) easier. The problem for long running task is that the user can leave the Activity (and then come again), or there is an incoming call, etc. If you don't handle this Activity lifecycle with care, it is so "dangerous", AsyncTask does not handle this.
Long running task should be run in a Service. Note that Service is also run in the main thread, so the approach would be the same, unless you use IntentService. In case of IntentService, just execute all of the threads (formerly in doInBackground) in the onHandleIntent method and wait it there, this method is called on a worker thread.
Communicating Service with Activity and maintaining consistency of Activity's state through its lifecycle is a long story. You better read the documentation in "a full concentration" with a cup of coffee :D. This might helps:
Managing the Activity Lifecycle
Best Practices for Background Jobs

Do works in background indefinitely

I need to have a background thread that works indefinitely. I've wrote this code to define an IntentService:
public class RecordInternetUsageService extends IntentService {
public RecordInternetUsageService() {
super("test");
// TODO Auto-generated constructor stub
}
#Override
protected void onHandleIntent(Intent intent) {
synchronized (this) {
try {
wait(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Toast.makeText(this, "test", Toast.LENGTH_LONG).show();
}
}
I have two questions, Is it a suitable class to do works indefinitely in background?
Why when I want to sleep this thread using by wait() method, Throws me an exception that mentioned below?
"sending message to a Handler on a dead thread".
And how can I solve this problem?
To do long processing task even when your application is closed i.e. in background one has to use Service... but you can do long processing work on that Main thread of Service or else you get ANR(android not responding). So you have to make a background thread and submit all the task on that background thread(That is done by Handle class) and handle all submitting and responding stuff... to wrap up this design pattern IntenServcie class is offered.
IntentService class automatically invokes the thread when a job is submitted and when the job is completed it kills the sevrice and frees up the memory. IntentSerive Exits as soon as it is done with its job.
The problem here is that you are creating a Toast inside a thread that is managed by the IntentService. The system will use the Handler associated with this thread to show and hide the Toast.
First the Toast will be shown correctly, but when the system tries to hide it, after the onHandleIntent method has finished, the error "sending message to a Handler on a dead thread" will be thrown because the thread in wich the Toast was created is no longer valid,.

make asynctask return results when time is exceeded

I have some asynctasks in my application that do network functions (download/upload files,http requests) in the background.While these actions are in progress I use ProgressDialog in order to display messages about the progress of the task. However some tasks may require more time to complete (for example downloading a file on a slow network) and this is something unwanted in the application.
How can I set a parameter to control the duration of each asynctask? I want the asynctask to complete at some point regardless of the completion of the job in the task. I have to make the asynctask call the onPostExecute method.
I read about this http://developer.android.com/reference/android/os/AsyncTask.html#get%28long,%20java.util.concurrent.TimeUnit%29
This was not very helpful because the UI would freeze and there was no actual control of the duration of the asynctask
This is a part of my code
public void downloadFiles(String address) {
String mainUrl =address;
//// I overrride the onPostExecute to get
/// results and call another asynctask
new Downloader(this){ //<--asynctask
#Override
protected void onPostExecute(String result){
super.onPostExecute(result);
TestResults=result;
//another method called that creates another asynctask
uploadFiles(mainUrl);
}
}.execute(mainUrl);
}
I also tried to use a Handler like this
But it didn't work either.
Is there a way to make the asynctask return results (which means to make asynctask call onPostExecute method) after a period of time ?
Using a while loop in the doInBackground method of asnctask is not the solution. I guess I need a timer from the mainUI to make the asynctask return results.
PS I have my application using fragments, that is why I call new Downloader(this) to pass the gui from the fragment.
Just tried this:
public void downloadFiles(String address) {
String mainUrl =address;
final Downloader tempObject =new Downloader(this){
#Override
protected void onPostExecute(String result){
super.onPostExecute(result);
downloadResults=result;
}
};
try {
tempObject.execute(mainUrl).get(3000L, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
This would make the UI freeze for 3 seconds and then the task would be evoked.... Which is not what I want.
Also tried out this:
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
#Override
public void run() {
if ( tempObject.getStatus() == Downloader.Status.RUNNING )
tempObject.cancel(true);
}
}, 5000 );
This would cause the message of onProgressUpdate of asynctask to stop, however the asynctask keeps running....
Any ideas ?
The methodology of the Handler function needs something additional to work. The solution to the problem lies here
AsyncTask may be canceled, however the doInbackground method is still running. Actually the task is set to value "cancel", but the doInbackgroung will still be running until it finishes. To solve this we must periodically check within a loop in doInbackground to see whether the task was set to cancel. Although this is not exactly what I wanted to do, this seems to be the only solution.
In doInBackground we have to check for the status of the task to see whether it was cancelled or not. So actually ,someone could just have the timer inside the doInbackground and make life easier without using the handler class.
I find it disappointing that one can not just terminate the execution of a synctask at will..... If anyone has a better idea, please let me know.

Android thread sometimes does not start

I must use Thread in an Android project. Sometimes, it works corectly, however sometimes does not; it does not start (does not call SendToServer() method)or it starts but return to another function suddenly (return updated; line)before the thread does not finish.
Note: affected value is bigger than 0, it gives condition and it goes to if statement.
Here is the my code sample;
public static Boolean MyUpdateFunction(MyObject myobject){
Boolean updated=false;
//Code for updating local database
int affected= SqliteDb.update(....);
if(affected>0)
{
//Send updated data to server
//For this I must use Thread(I can't use AsyncThread)
updated=true;
SendToServer();
}
return updated;
}
public static void SendToServer()
{
try{
;
Thread th=new Thread(new Runnable() {
public void run() {
try {
//Create data and send it to server
//.......
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
th.start();
th.join();
}
catch(SQLException e)
{
Toast.makeText(myContext,"ERROR: "+e.getMessage(), Toast.LENGTH_LONG).show();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Other people are correct in that an AsyncTask is the way forward, but the direct problem due to what you're experiencing is this (and as such, I would recommend reading up on how Threading works):
When you start the thread, it begins a new process. The UI thread (which is generally where the majority of your code is) continues. So your code will fire the thread with SendToServer(), and then by definition will immediately return updated, as the UI thread immediately goes to the next line.
What you need is a callback from your Thread, which is handled in the onPostExecute() method of an AsyncTask. There's a good tutorial on how to use them and what they do here
Edit:
I've just seen from a comment above that you can't use Asynctasks, fair enough, but you still need a callback/event fired from your Thread to return any results
Instead of using threads and your variables (updated and affected), you can use AsyncTasks: see: http://developer.android.com/reference/android/os/AsyncTask.html
With AsyncTask, you have some methods which are doing exactly what you want:
onPreExecute
doInBackground
onPostExecute
So, what you can do is to check your condition in onPreExecute, then do your SendToServer in the doInBackground and onPostExecute do what you need.

how do you read text files off the internet in Android 4.0.3

I am a relatively new Android programmer and I was wondering how you could get read text off the internet in 4.0.3. I keep finding code that gives me a Network on Main exception: http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html and was wondering if anyone could provide me some sample code to get around this, for reference I got the code I tried to use here: http://android-er.blogspot.com/2011/04/read-text-file-from-internet-using-java.html. Thanks a lot.
In Honeycomb and Ice Cream Sandwich (i.e. Android 3.0+) , you cannot connect to the internet in the main thread (onCreate(), onPause(), onResume() etc.), and you have to instead start a new thread. The reason why this has changed is because network operations can make the app wait for a long time, and if you're running them in the main thread, the whole application becomes unresponsive. If you try to connect from the main thread, Android will throw a NetworkOnMainThreadException.
To bypass this, you can run networking code from a new thread, and use runOnUiThread() to do things in the main thread, such as update the user interface. Generally, you can do something like:
class MyActivity extends Activity {
public onCreate(Bundle savedInstanceState) {
super.onCreate();
// Create thread
Thread networkThread = new Thread() {
#Override
public void run() {
try {
// this is where your networking code goes
// I'm declaring the variable final to be accessible from runOnUiThread
final String result = someFunctionThatUsesNetwork();
runOnUiThread(new Runnable() {
#Override
public void run() {
// this is where you can update your interface with your results
TextView myLabel = (TextView) findViewById(R.id.myLabel);
myLabel.setText(result);
}
}
} catch (IOException e) {
Log.e("App", "IOException thrown", e);
}
}
}
}
}
You need to complete an HTTP Request. There are a lot of examples available on line. Try here for starts.

Categories

Resources