Logic Problem between Main Class and Thread Class - java

Hy!!
I make a new Object from a Thread Class. There is a Http-Post in the run method with a result string.
My Question:
How is it possible to notify the main class that the download finished?
MFG

Have a look at the AsyncTask class which helps you handling work on another thread than the UI thread. It's a very useful class of the Android framework.
You simply create a custom class which inherits from AsyncTask and then you override the doInBackground() and insert the code that should be executed in its own thread. In your case this would be the code to do the download. Furthermore you have to override the onPostExecute() which is called automatically when the doInBackground() method has finished. The object you returned in the doInBackground() method will be automatically passed to the onPostExecute() method. The onPostExecute() will be execute on the UI thread.
So the AsyncTask class will handle all the thread stuff for you and you can focus on your work.
Have a look at the tutorial on the Android Developer site.

If by "main class" you mean your Activity then you can use a Handler.
In your activity:
private static final int DOWNLOAD_COMPLETE = 0;
...
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch(msg.what){
case DOWNLOAD_COMPLETE:
Log.d("MYTAG",msg.obj.toString());
break;
}
}
}
And in some other class:
public doBackgroundUpdate(Handler handler){
Thread backgroundThread = new Thread() {
#Override
public void run() {
// do long-running post operation
// send result back to UI thread
Message msg = Message.obtain();
msg.what = DOWNLOAD_COMPLETE;
msg.obj = "Result String to pass";
handler.sendMessage(msg);
}
}
backgroundThread.start();
}

Instead of creating a thread, create a Callable and pass it to an ExecutorService by way of the submit() method:
Future<T> submit(Callable<T> task)
Submitting a Callable object to the ExecutorService returns a Future object. The get() method of Future will then block until the task has completed and will contain the results of the Callable.
Example:
Callable<String> callable = new Callable<String>(){
#Override
public String call() throws Exception {
return "HELLO WORLD";
}
};
//executor with one thread
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(callable);
executor.shutdown();
String result = future.get();
System.out.println(result);

Related

What do I use now that Handler() is deprecated?

How do I fix the deprecation warning in this code? Alternatively, are there any other options for doing this?
Handler().postDelayed({
context?.let {
//code
}
}, 3000)
Only the parameterless constructor is deprecated, it is now preferred that you specify the Looper in the constructor via the Looper.getMainLooper() method.
Use it for Java
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
// Your Code
}
}, 3000);
Use it for Kotlin
Handler(Looper.getMainLooper()).postDelayed({
// Your Code
}, 3000)
Source : developer.android.com
From API level 30, there are 2 constructors are deprecated.
Handler()
Handler(Handler.Callback)
Google explains the reason below.
Implicitly choosing a Looper during
Handler construction can lead to bugs where operations are silently
lost (if the Handler is not expecting new tasks and quits), crashes
(if a handler is sometimes created on a thread without a Looper
active), or race conditions, where the thread a handler is associated
with is not what the author anticipated. Instead, use an Executor or
specify the Looper explicitly, using Looper#getMainLooper, {link
android.view.View#getHandler}, or similar. If the implicit thread
local behavior is required for compatibility, use new
Handler(Looper.myLooper(), callback) to make it clear to readers.
Solution 1: Use an Executor
1. Execute code in the main thread.
Java
// Create an executor that executes tasks in the main thread.
Executor mainExecutor = ContextCompat.getMainExecutor(this);
// Execute a task in the main thread
mainExecutor.execute(new Runnable() {
#Override
public void run() {
// You code logic goes here.
}
});
Kotlin
// Create an executor that executes tasks in the main thread.
val mainExecutor = ContextCompat.getMainExecutor(this)
// Execute a task in the main thread
mainExecutor.execute {
// You code logic goes here.
}
2. Execute code in a background thread
Java
// Create an executor that executes tasks in a background thread.
ScheduledExecutorService backgroundExecutor = Executors.newSingleThreadScheduledExecutor();
// Execute a task in the background thread.
backgroundExecutor.execute(new Runnable() {
#Override
public void run() {
// Your code logic goes here.
}
});
// Execute a task in the background thread after 3 seconds.
backgroundExecutor.schedule(new Runnable() {
#Override
public void run() {
// Your code logic goes here
}
}, 3, TimeUnit.SECONDS);
Kotlin
// Create an executor that executes tasks in a background thread.
val backgroundExecutor: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor()
// Execute a task in the background thread.
backgroundExecutor.execute {
// Your code logic goes here.
}
// Execute a task in the background thread after 3 seconds.
backgroundExecutor.schedule({
// Your code logic goes here
}, 3, TimeUnit.SECONDS)
Note: Remember to shut down the executor after using.
backgroundExecutor.shutdown(); // or backgroundExecutor.shutdownNow();
3. Execute code in a background thread and update UI on the main thread.
Java
// Create an executor that executes tasks in the main thread.
Executor mainExecutor = ContextCompat.getMainExecutor(this);
// Create an executor that executes tasks in a background thread.
ScheduledExecutorService backgroundExecutor = Executors.newSingleThreadScheduledExecutor();
// Execute a task in the background thread.
backgroundExecutor.execute(new Runnable() {
#Override
public void run() {
// Your code logic goes here.
// Update UI on the main thread
mainExecutor.execute(new Runnable() {
#Override
public void run() {
// You code logic goes here.
}
});
}
});
Kotlin
// Create an executor that executes tasks in the main thread.
val mainExecutor: Executor = ContextCompat.getMainExecutor(this)
// Create an executor that executes tasks in a background thread.
val backgroundExecutor = Executors.newSingleThreadScheduledExecutor()
// Execute a task in the background thread.
backgroundExecutor.execute {
// Your code logic goes here.
// Update UI on the main thread
mainExecutor.execute {
// You code logic goes here.
}
}
Solution 2: Specify a Looper explicitly by using one of the following constructors.
Handler(Looper)
Handler(Looper, Handler.Callback)
1. Execute code in the main thread
1.1. Handler with a Looper
Java
Handler mainHandler = new Handler(Looper.getMainLooper());
Kotlin
val mainHandler = Handler(Looper.getMainLooper())
1.2 Handler with a Looper and a Handler.Callback
Java
Handler mainHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(#NonNull Message message) {
// Your code logic goes here.
return true;
}
});
Kotlin
val mainHandler = Handler(Looper.getMainLooper(), Handler.Callback {
// Your code logic goes here.
true
})
2. Execute code in a background thread
2.1. Handler with a Looper
Java
// Create a background thread that has a Looper
HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
// Create a handler to execute tasks in the background thread.
Handler backgroundHandler = new Handler(handlerThread.getLooper());
Kotlin
// Create a background thread that has a Looper
val handlerThread = HandlerThread("HandlerThread")
handlerThread.start()
// Create a handler to execute tasks in the background thread.
val backgroundHandler = Handler(handlerThread.looper)
2.2. Handler with a Looper and a Handler.Callback
Java
// Create a background thread that has a Looper
HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
// Create a handler to execute taks in the background thread.
Handler backgroundHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(#NonNull Message message) {
// Your code logic goes here.
return true;
}
});
Kotlin
// Create a background thread that has a Looper
val handlerThread = HandlerThread("HandlerThread")
handlerThread.start()
// Create a handler to execute taks in the background thread.
val backgroundHandler = Handler(handlerThread.looper, Handler.Callback {
// Your code logic goes here.
true
})
Note: Remember to release the thread after using.
handlerThread.quit(); // or handlerThread.quitSafely();
3. Execute code in a background thread and update UI on the main thread.
Java
// Create a handler to execute code in the main thread
Handler mainHandler = new Handler(Looper.getMainLooper());
// Create a background thread that has a Looper
HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
// Create a handler to execute in the background thread
Handler backgroundHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(#NonNull Message message) {
// Your code logic goes here.
// Update UI on the main thread.
mainHandler.post(new Runnable() {
#Override
public void run() {
}
});
return true;
}
});
Kotlin
// Create a handler to execute code in the main thread
val mainHandler = Handler(Looper.getMainLooper())
// Create a background thread that has a Looper
val handlerThread = HandlerThread("HandlerThread")
handlerThread.start()
// Create a handler to execute in the background thread
val backgroundHandler = Handler(handlerThread.looper, Handler.Callback {
// Your code logic goes here.
// Update UI on the main thread.
mainHandler.post {
}
true
})
If you want to avoid the null check thing in Kotlin (? or !!) you can use Looper.getMainLooper() if your Handler is working with some UI related thing, like this:
Handler(Looper.getMainLooper()).postDelayed({
Toast.makeText(this#MainActivity, "LOOPER", Toast.LENGTH_SHORT).show()
}, 3000)
Note: use requireContext() instead of this#MainActivity if you are using fragment.
The deprecated function is that constructor for Handler. Use Handler(Looper.myLooper()) .postDelayed(runnable, delay) instead
Consider using coroutines
scope.launch {
delay(3000L)
// do stuff
}
Using lifecycle scope this is more easy. Inside activity or fragment.
lifecycleScope.launch {
delay(2000)
// Do your stuff
}
or use handler
Handler(Looper.myLooper()!!)
I have 3 solutions:
Specify the Looper explicitly:
Handler(Looper.getMainLooper()).postDelayed({
// code
}, duration)
Specify the implicit thread local behavior:
Handler(Looper.myLooper()!!).postDelayed({
// code
}, duration)
using Thread:
Thread({
try{
Thread.sleep(3000)
} catch (e : Exception) {
throw e
}
// code
}).start()
Handler() and Handler(Handler.Callback callback) constructors are deprecated. Because those can leads to bugs & crashes. Use Executor or Looper explicitly.
For Java
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
//do your work here
}
}, 1000);
use this
Looper.myLooper()?.let {
Handler(it).postDelayed({
//Your Code
},2500)
}
Use Executor instead of handler for more info Executor.
To achieve post delay use ScheduledExecutorService:
ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
Runnable runnable = () -> {
public void run() {
// Do something
}
};
worker.schedule(runnable, 2000, TimeUnit.MILLISECONDS);
Provide a looper in the Handler Constructor
Handler(Looper.getMainLooper())
import android.os.Looper
import android.os.Handler
inline fun delay(delay: Long, crossinline completion: () -> Unit) {
Handler(Looper.getMainLooper()).postDelayed({
completion()
}, delay)
}
Example:
delay(1000) {
view.refreshButton.visibility = View.GONE
}
If you are using Variable for Handler and Runnable then use it like this.
private Handler handler;
private Runnable runnable;
handler = new Handler(Looper.getMainLooper());
handler.postDelayed(runnable = () -> {
// Do delayed stuff here
handler.postDelayed(runnable, 1000);
}, delay);
Also You need to remove callbacks in onDestroy()
#Override
public void onDestroy() {
super.onDestroy();
if (handler != null) {
handler.removeCallbacks(runnable);
}
}
Coroutines Kotlin
private val SPLASH_SCREEN_TIME_OUT_CONST: Long = 3000
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
window.setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN
)
GlobalScope.launch {
delay(SPLASH_SCREEN_TIME_OUT_CONST)
goToIntro()
}
}
private fun goToIntro(){
startActivity(Intent(this, IntroActivity::class.java))
finish()
}
It's a good idea use this structure in Kotlin
companion object Run {
fun after(delay: Long, process: () -> Unit) {
Handler(Looper.getMainLooper()).postDelayed({
process()
}, delay)
}
}
Later call as
Run.after(SPLASH_TIME_OUT) {
val action = SplashFragmentDirections.actionSplashFragmentToLogin()
v.findNavController().navigate(action)
}
Java Answer
I wrote a method to use easily. You can use this method directly in your project. delayTimeMillis can be 2000, it means that this code will run after 2 seconds.
private void runJobWithDelay(int delayTimeMillis){
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
//todo: you can call your method what you want.
}
}, delayTimeMillis);
}
According to the document (https://developer.android.com/reference/android/os/Handler#Handler()):
Implicitly choosing a Looper during Handler construction can lead to bugs where operations are silently lost (if the Handler is not expecting new tasks and quits), crashes (if a handler is sometimes created on a thread without a Looper active), or race conditions, where the thread a handler is associated with is not what the author anticipated. Instead, use an Executor or specify the Looper explicitly, using Looper#getMainLooper, {link android.view.View#getHandler}, or similar. If the implicit thread local behavior is required for compatibility, use new Handler(Looper.myLooper()) to make it clear to readers.
We should stop using the constructor without a Looper, and specify a Looper instead.
I usually use this one
Code:
Handler(Looper.myLooper() ?: return).postDelayed({
// Code what do you want
}, 3000)
Screenshot:
The handler() etc code is generated by the Android Studio 4.0.1 when a Fullscreen Activity, for example, is created from scratch. I know that we are being encouraged to use Kotlin, which I do, but from time to time I use sample projects to get an idea going.
It seems strange that we are chastised by AS when AS actually generates the code. It might be a useful academic activity to go through the errors and fix them but maybe AS could generate new clean code for us enthusiasts...
For Xamarin Android, instead of
Handler handler;
handler = new Handler();
just write
Handler handler;
handler = new Handler(Looper.MyLooper());
the rest of the code is fine.

Executing Java callback on a new thread

On this project, a Manager performs event queuing, and to return the result of the event a callback is used (the callback does not extend Runnable). The manager runs on a separate thread, dispatching the events. Once the events terminate, this same thread calls the callbacks. This means that the next event will not be dispatched before the callback of the previous event terminates. In order to avoid this, I though about having the manager create a new thread for each callback, and executing the callbacks there. How good is this solution in terms of design practices, and is there a better way to achieve this?
A simple Callback code:
import java.util.concurrent.*;
import java.util.*;
public class CallBackDemo{
public CallBackDemo(){
System.out.println("creating service");
ExecutorService service = Executors.newFixedThreadPool(10);
try{
for ( int i=0; i<10; i++){
Callback callback = new Callback(i+1);
MyCallable myCallable = new MyCallable((long)i+1,callback);
Future<Long> future = service.submit(myCallable);
//System.out.println("future status:"+future.get()+":"+future.isDone());
}
}catch(Exception err){
err.printStackTrace();
}
service.shutdown();
}
public static void main(String args[]){
CallBackDemo demo = new CallBackDemo();
}
}
class MyCallable implements Callable<Long>{
Long id = 0L;
Callback callback;
public MyCallable(Long val,Callback obj){
this.id = val;
this.callback = obj;
}
public Long call(){
//Add your business logic
System.out.println("Callable:"+id+":"+Thread.currentThread().getName());
callback.callbackMethod();
return id;
}
}
class Callback {
private int i;
public Callback(int i){
this.i = i;
}
public void callbackMethod(){
System.out.println("Call back:"+i);
// Add your business logic
}
}
output:
creating service
Callable:1:pool-1-thread-1
Call back:1
Callable:2:pool-1-thread-2
Call back:2
Callable:8:pool-1-thread-8
Call back:8
Callable:3:pool-1-thread-3
Call back:3
Callable:10:pool-1-thread-10
Callable:4:pool-1-thread-4
Call back:10
Callable:7:pool-1-thread-7
Call back:7
Callable:6:pool-1-thread-6
Call back:6
Callable:9:pool-1-thread-9
Callable:5:pool-1-thread-5
Call back:9
Call back:4
Call back:5
Summary:
Replace Manager with ExecutorService of your preferred choice.
Either your can pass Callaback object to Callable/Runnable object Or you can create Callback object inside Callable/Runnable. In my example, I have explicitly passed Callback object to Callable.
Before returning the result, Callable object invokes Callback method. If you want to block on proceeding further unless you get response from current event, just uncomment below line.
System.out.println("future status:"+future.get()+":"+future.isDone());
I think you are going to avoid it and hence keep above line commented. You don't have to create new thread for Callback method invocation. If you want to process Callback event asynchronously, you can create one more ExecutorService and submit the event.
I would have the thread which executes the task, also execute the call back. Instead of creating a Thread each time, I suggest you use an ExecutorService.
public static <T> void submit(ExecutorService service,
Callable<T> callable,
Consumer<T> callback) {
service.submit(() -> {
try {
callback.accept(callable.call());
} catch (Throwable t) {
// log the Throwable
}
});
}

Handover execution to main thread in android

I am using Runnable to do some background task in my android application. The runnable after completing the background task will call a callback which is implemented by caller of the function which implemented runnable. Now i want to handover execution to main thread once the callback is called.
public void DoInBackground(Callback callback)
{
Thread thread = new Thread(new Runnable(){
//Execution that to be done in background
//calling callback once the result is obtained
});
thread.start()
}
public void callee(){
DoInBackground(new callback(){
#Override
public void onSuccess(int value){
//Do operations after completion of background task
}
});
}
I want the onSucess to run on the main thread rather than the new runnable created in DoInBackground function.
I know it can be done with async task. Is there any other way to do it.
you can use an Handler to post a runnable in the UI Thread queue, or if the context is the Activity ones you can use the runOnUiThread method. The snippet inside the runnable will be run on the UI Thread
put your callback function inside runOnUiThread function :
runOnUiThread(new Runnable() {
#Override
public void run() {
// callback function
}
});

FutureTask Submitted to an Executor Doesn't Run

I've written a class, a series of instances of which are intended to be called from an AsyncTask, which will return a result from the method runReport(). It creates a worker thread just fine, but for some reason it then doesn't execute the Callable's call() method. What am I doing wrong?
//Problem: doStuff() never gets called, even though the worker thread gets created.
#Override
public ReportResult runReport() throws InterruptedException, ExecutionException {
Callable<ReportResult> report = new Callable<ReportResult>() {
#Override
public ReportResult call() throws Exception {
doStuff();
...
return new ReportResult(varWrittenByMethod);
}
};
FutureTask<ReportResult> result = new FutureTask<ReportResult>(report);
//I tried a few of these ExecutorService factory methods, with the same result.
//I only made my own ThreadFactory to verify the worker was created
ExecutorService es = Executors.newSingleThreadExecutor(new ThreadFact());
es.submit(report);
ReportResult finalResult = result.get();
es.shutdownNow();
return finalResult;
}
private class ThreadFact implements ThreadFactory{
#Override
public Thread newThread(Runnable r) {
Log.d(TAG, "Created worker Thread");
return new Thread(r);
}
}
As far as I can tell, I have to do this as a FutureTask in its own Thread, because it needs to do the following (all of which apart from the return is inside doStuff() ):
Do heavy some synchronous setup (The AsyncTask keeps that off the UI thread)
Call Looper.prepare()
Register a listener
Call Looper.loop(), catch a few callbacks from the listener over a period of time.
Call Looper.myLooper().quit() inside the listener callback when I have enough datapoints
Return the result
I'm open to better ways to do this. I originally let the AsyncTask make this call, then ran Looper.loop() on its thread, but I couldn't process a queue of these objects since I needed to call Looper.myLooper.quit() from the listener before returning a result, which poisoned the thread's message queue irreversibly.
Your thread factory doesn't propagate the passed Runnable to the created thread. In your ThreadFactory, try:
return new Thread(r);
Also, you should be using the FutureTask returned by the submit method, not the one you created explicitly. E.g.
FutureTask<ReportResult> result = es.submit(report);
ReportResult finalResult = result.get();
As a note, you probably will regret doing this level of work from an AsyncTask, because the threads in an AsyncTask will get killed during an Activity lifecycle change. Better to do the asynchronous setup in an IntentService. If you don't need Looper(), you can use plain threads rather than HandlerThreads.

Is there a way to add a listener to an Executor/Future's?

Java : Is there a way to add a listener to an Executor?
I have a collection with Futures which I try to monitorize , as to update some GUI statuses. Currently I am checking in a background thread if there are differences in the submitted/completed tasks, but I am doing this in a while(true){} block and I do not like this approach.
You could use SwingWorkers or similar classes depending on your GUI toolkit to get notified when a task completes.
Unfortunately, there is no way to do that.
Instead, use Google's ListenableFuture<V> interface.
Alternatively, use a language with better async support, such as C# and the TPL.
If you want to do something when the task completes, you add it to the task itself.
public static <T> void addTask(Callable<T> tCall) {
executor.submit(new Runnable() {
public void run() {
T t = tCall.call();
// what you want done when the task completes.
process(t);
}
});
}
Use java.util.concurrent.ExecutorCompletionService instead of Executor to submit tasks. It has method take() which returns recently completed task. Start additional thread (or SwingWorker) which would call take() in a loop, and update GUI status with the result.
I did something similar to #Peter Lawrey's answer.
I added a listener as a member variable of the callable and called that listener just before the Callable returned its result.
So you have a Listener interface:
#FunctionalInterface
public interface Listener<T> {
void notify(T result);
}
A Callable with that as a member variable:
public class CallbackCallable implements Callable<String>{
private Listener<String> listener;
#Override
public String call() throws Exception {
// do some stuff
if (listener != null)
listener.notify("result string");
return "result string";
}
public void setListener(Listener<String> listener) {
this.listener = listener;
}
}
And in your application you pass an implementation of the listener with what you want to be done with the result:
public static void main(String[] args) {
ExecutorService es = Executors.newSingleThreadExecutor();
System.out.println("This is thread: " + Thread.currentThread().getName());
CallbackCallable myCallable = new CallbackCallable();
myCallable.setListener(r -> {
// process your callable result here
System.out.println("Got from Callable: " + r);
System.out.println("This is thread: " + Thread.currentThread().getName());
});
es.submit(myCallable);
}
Only thing you need to keep in mind is that your implementation will run on the same thread as the Callable, as you can see if you run that:
This is thread: main
Got from Callable: result string
This is thread: pool-1-thread-1

Categories