Java call method on main thread

Java: calling a method from the main thread by signaling in some way from another thread

I have an application with 2 threads (the main and another thread t1 ) which share a volatile variable myVar . Any ideas on how to make the main thread to call a method myMethod by signaling in some way from t1 ? I implemented it by using ChangeListener and myMethod is called when myVar changes, BUT the method is called from t1, and not from the main thread (note: I need to call this method from the main thread because this is a call to a JavaScript code from Java, so for a security reason only the main thread can do so). Thanks in advance.

Wrong mindset. One thread can’t make another thread call a method, and one thread should never make another thread stop, or pause, or. anything. Threads should always cooperate with eacg other. If you want your main thread to wait for some event, and then call some method when the event happens, then write code for your main thread that waits for the event and calls the method.

4 Answers 4

You would have to have your main thread spin in a loop on some scalar, I would recommend one of the Atomics that java provides (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html), but you could use volatile if you wanted for this I think.

Each thread can only run sequentially — it’s just the way computing works. The way you will handle this, is when the main thread spins in some sort of loop, you eventually check to see if this scalar of yours has been set, and when it has, you want unset the variable and execute your JavaScript. In this particular piece of your code, I think the Atomics have an advantage over the volatile with the use of the compareAndSet operations because using volatile can mess you up a bit between threads if you are trying to check the value in one operation and then set it again in another operation which gives the other thread enough time to set it again — meaning you may miss a call to your JS because the other thread set the variable between the main thread checking it and setting it (although the use of volatile vs Atomics may be interpreted as my opinion).

//main thread AtomicBoolean foo = new AtomicBoolean(false); while (. somecondition. ) < if(foo.compareAndSet(true, false))< //execute JS >//do some other work > 

and in your T1 thread, just call foo.set(true) .

If you expect main to call your JS for each time T1 sets foo to true, then you will have to block in T1 until main has unset foo, or use an AtomicInteger to count how many times T1 has set foo — depending on your needs.

Читайте также:  Php output all error

Источник

Glide assert: java.lang.IllegalArgumentException: You must call this method on the main thread

but according to this thread, it should work: https://github.com/bumptech/glide/issues/310 Yet, I cannot get it to work, unless I call it from the main thread. Here’s is what I am trying to do from the main thread:

 Glide.get(mContext); loadUserImage(userImageUrl); // wait 5 seconds before trying again int imageLoadingTimeOut = mContext.getResources().getInteger(R.integer.image_loading_time_out); if (imageLoadingTimeOut > 0) < new Timer().schedule(new TimerTask() < @Override public void run() < if (!mUserImageLoaded) < loadUserImage(userImageUrl); >> >, imageLoadingTimeOut); > > 
private boolean mUserImageLoaded = false; private void loadUserImage(String userImageUrl) < if (userImageUrl != null && !userImageUrl.isEmpty() && !mUserImageLoaded) < Glide.with(mContext).using(Cloudinary.getUrlLoader(mContext)).load(userImageUrl).crossFade().listener(new RequestListener() < @Override public boolean onException(Exception e, String model, Targettarget, boolean isFirstResource) < return false; >@Override public boolean onResourceReady(GlideDrawable resource, String model, Target target, boolean isFromMemoryCache, boolean isFirstResource) < mImageMessageContent.invalidate(); mUserImageLoaded = true; return false; >>).into(mImageMessageContent); > else < mImageMessageContent.setVisibility(View.GONE); >> 

and mContext is just the activity «this» pointer. Anyway, can I use Glide from a thread different than main?

Источник

Running code in main thread from another thread

In an android service I have created thread(s) for doing some background task. I have a situation where a thread needs to post certain task on main thread’s message queue, for example a Runnable . Is there a way to get Handler of the main thread and post Message / Runnable to it from my other thread?

You can also use Custom broadcast receiver. try my answer here, [Inner Broadcast Receiver][1] [1]: stackoverflow.com/a/22541324/1881527

There are many ways. Apart from David’s answer & dzeikei’s comment in his answer, (3) you can use a Broadcast Receiver, or (4) pass the handler in extras of Intent used to start the service, and then retrieve the main thread’s handler inside service using getIntent().getExtras() .

@sazzad-hissain-khan, Why tag this question from 2012 with mostly answers in Java with the kotlin tag?

16 Answers 16

NOTE: This answer has gotten so much attention, that I need to update it. Since the original answer was posted, the comment from @dzeikei has gotten almost as much attention as the original answer. So here are 2 possible solutions:

1. If your background thread has a reference to a Context object:

Make sure that your background worker threads have access to a Context object (can be the Application context or the Service context). Then just do this in the background worker thread:

// Get a handler that can be used to post to the main thread Handler mainHandler = new Handler(context.getMainLooper()); Runnable myRunnable = new Runnable() < @Override public void run() // This is your code >; mainHandler.post(myRunnable); 

2. If your background thread does not have (or need) a Context object

// Get a handler that can be used to post to the main thread Handler mainHandler = new Handler(Looper.getMainLooper()); Runnable myRunnable = new Runnable() < @Override public void run() // This is your code >; mainHandler.post(myRunnable); 

Thanks David it worked out for me, one more thing if you could help me with, if I extend Handler and impl handleMessage() would it prevent main thread from handling its messages ? that’s only a question out of curosity..

No. If you subclass Handler (or use Handler.Callback interface) your handleMessage() method will ONLY be called for messages that have been posted using your handler. The main thread is using a different handler to post/process messages so there is no conflict.

Читайте также:  Java current time millis to time

I believe you won’t even need context if you use Handler mainHandler = new Handler(Looper.getMainLooper());

@SagarDevanga This is not the right place to ask a different question. Please post a new question , not a comment to an unrelated answer. You will get better and faster response that way.

As a commenter below pointed correctly, this is not a general solution for services, only for threads launched from your activity (a service can be such a thread, but not all of those are). On the complicated topic of service-activity communication please read the whole Services section of the official doc — it is complex, so it would pay to understand the basics: http://developer.android.com/guide/components/services.html#Notifications

The method below may work in the simplest cases:

If I understand you correctly you need some code to be executed in the GUI thread of the application (cannot think about anything else called «main» thread). For this there is a method on Activity :

someActivity.runOnUiThread(new Runnable() < @Override public void run() < //Your code to run in GUI thread here >//public void run() < >); 

Hope this is what you are looking for.

OP says he is running threads in a Service . You cannot use runOnUiThread() in a Service . This answer is misleading and doesn’t address the asked question.

Kotlin versions

When you are on an activity, then use

When you have activity context, mContext then use

When you are in somewhere outside activity where no context available, then use

Handler(Looper.getMainLooper()).post < //code that runs in main >

There is another simple way, if you don’t have an access to the Context.

1). Create a handler from the main looper:

Handler uiHandler = new Handler(Looper.getMainLooper()); 

2). Implement a Runnable interface:

Runnable runnable = new Runnable() < // your code here >

3). Post your Runnable to the uiHandler:

That’s all 😉 Have fun with threads, but don’t forget to synchronize them.

A condensed code block is as follows:

 new Handler(Looper.getMainLooper()).post(new Runnable() < @Override public void run() < // things to do on the main thread >>); 

This does not involve passing down the Activity reference or the Application reference.

 Handler(Looper.getMainLooper()).post(Runnable < // things to do on the main thread >) 

If you run code in a thread, e.g. do delaying some action, then you need to invoke runOnUiThread from the context. For example, if your code is inside MainActivity class then use this:

MainActivity.this.runOnUiThread(new Runnable() < @Override public void run() < myAction(); >>); 

If your method can be invoked either from main (UI thread) or from other threads you need a check like:

public void myMethod() < if( Looper.myLooper() == Looper.getMainLooper() ) < myAction(); >else

@DavidWasser Is that documented anywhere? The method docs don’t mention anything about it. developer.android.com/reference/android/app/…

@GregBrown As you’ve indicated by your link to the Activity documentation, runOnUiThread() is a method of Activity . It is not a method of Service , therefore you cannot use it. What could be clearer than that?

@DavidWasser Fair enough. I don’t even remember why I asked that question now (it was posted almost a year ago).

I know this is an old question, but I came across a main thread one-liner that I use in both Kotlin and Java. This may not be the best solution for a service, but for calling something that will change the UI inside of a fragment this is extremely simple and obvious.

Читайте также:  Html iframe relative width

HandlerThread is better option to normal java Threads in Android .

  1. Create a HandlerThread and start it
  2. Create a Handler with Looper from HandlerThread : requestHandler
  3. post a Runnable task on requestHandler

Communication with UI Thread from HandlerThread

  1. Create a Handler with Looper for main thread : responseHandler and override handleMessage method
  2. Inside Runnable task of other Thread ( HandlerThread in this case), call sendMessage on responseHandler
  3. This sendMessage result invocation of handleMessage in responseHandler .
  4. Get attributes from the Message and process it, update UI

Example: Update TextView with data received from a web service. Since web service should be invoked on non-UI thread, created HandlerThread for Network Operation. Once you get the content from the web service, send message to your main thread (UI Thread) handler and that Handler will handle the message and update UI.

HandlerThread handlerThread = new HandlerThread("NetworkOperation"); handlerThread.start(); Handler requestHandler = new Handler(handlerThread.getLooper()); final Handler responseHandler = new Handler(Looper.getMainLooper()) < @Override public void handleMessage(Message msg) < txtView.setText((String) msg.obj); >>; Runnable myRunnable = new Runnable() < @Override public void run() < try < Log.d("Runnable", "Before IO call"); URL page = new URL("http://www.your_web_site.com/fetchData.jsp"); StringBuffer text = new StringBuffer(); HttpURLConnection conn = (HttpURLConnection) page.openConnection(); conn.connect(); InputStreamReader in = new InputStreamReader((InputStream) conn.getContent()); BufferedReader buff = new BufferedReader(in); String line; while ((line = buff.readLine()) != null) < text.append(line + "\n"); >Log.d("Runnable", "After IO call:"+ text.toString()); Message msg = new Message(); msg.obj = text.toString(); responseHandler.sendMessage(msg); > catch (Exception err) < err.printStackTrace(); >> >; requestHandler.post(myRunnable); 

Источник

How to call a method with a separate thread in Java?

This worked perfectly for what I was doing. Needed to run a webservice and updating a progress bar concurrently using the observer pattern.

Do we need to explicitly terminate the thread? Isn’t there a risk of creating a memory leak by not explicitly terminating the thread? Or does the thread terminate when it’s done with run() ?

Create a class that implements the Runnable interface. Put the code you want to run in the run() method — that’s the method that you must write to comply to the Runnable interface. In your «main» thread, create a new Thread class, passing the constructor an instance of your Runnable , then call start() on it. start tells the JVM to do the magic to create a new thread, and then call your run method in that new thread.

public class MyRunnable implements Runnable < private int var; public MyRunnable(int var) < this.var = var; >public void run() < // code in the other thread, can reference "var" variable >> public class MainThreadClass < public static void main(String args[]) < MyRunnable myRunnable = new MyRunnable(10); Thread t = new Thread(myRunnable) t.start(); >> 

Take a look at Java’s concurrency tutorial to get started.

If your method is going to be called frequently, then it may not be worth creating a new thread each time, as this is an expensive operation. It would probably be best to use a thread pool of some sort. Have a look at Future , Callable , Executor classes in the java.util.concurrent package.

Источник

Оцените статью