I have a requirement to generate a bitmap out of an EditText and then perform some manipulations on it.
My main concern is not to call View.buildDrawingCache() method on the UI thread and possibly block it, especially when talking about large screens (i.e. Nexus 10) since the EditText will occupy about 80% of the available screen size.
I execute Runnables inside a ThreadPoolExecutor, those will inflate dummy views on a worker thread and set all the required attributes to them, then simply call buildDrawingCache() & getDrawingCache() to generate a bitmap.
This works perfect on some devices yet recently I have encountered a few devices that crash with the following message:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
I understand why this happens, as some phones must have modified implementation for EditText that creates a Handler and thus requires Looper.prepare() to be called first.
From what I've read online there is no issue with calling Looper.prepare() inside a worker thread though some stated it is highly unrecommended yet I could not find a reason for that.
Other than that, most posts related to this issue state you are not supposed to inflate views inside a background thread, probably due to the following from Android's official documentation (Processes and Threads):
"Do not access the Android UI toolkit from outside the UI thread"
What is the recommended approach to dealing with this problem?
Is there any harm in calling build/get drawingcache from the main thread? (performance-wise)
Will calling Looper.prepare() inside my worker thread solve this problem?
EDIT
Just to elaborate on my specific requirement, I have a user-interface consisting of an ImageView and a custom EditText on top of it, the EditText can change it's font and color according to the user selection, it can be zoomed in/out using "pinch to zoom" gesture and can also be dragged around to allow the user to reposition it on top of the image.
Eventually what I do is create a dummy view inside my worker thread using the exact same values (width, height, position) it currently has on the UI and then generate it's drawingcache, the original image's bitmap is decoded again from a local file.
Once the two bitmaps are ready I merge them into a single bitmap for future use.
So to put it simple, is there anything wrong with executing the following code (from within a background thread):
Call Looper.prepare()
Create a new view with application context, call measure() & layout() manually and then build+get drawingcache from it, i.e.:
Looper.prepare();
EditText view = new EditText(appContext);
view.setText("some text");
view.setLayoutParams(layoutParams);
view.measure(
View.MeasureSpec.makeMeasureSpec(targetWidth, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(targetHeight, View.MeasureSpec.EXACTLY));
view.layout(0, 0, targetWidth, targetHeight);
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
How does this apply to the restriction with not accessing the Android UI toolkit from outside the UI thread, what could possibly go wrong?
In your case, you can do it of course, but be carefull only reading values from UI data, to avoid synchronizations bug.
Also you should not recreate the EditText from the background thread, it will be more efficient to directly access the already existant one instead:
Looper.prepare();
myEditText.setDrawingCacheEnabled(true);
Bitmap bitmap = myEditText.getDrawingCache();
If your question is : why it is not recommanded by android guidelines, here is a good SO answer to your question.
Calling View.buildDrawingCache() calls Bitmap.nativeCreate which can be a large allocation, so yes, it can be potentially harmful to run on main thread. I don't see a problem with calling Looper.prepare() in your background thread. However, it's unclear what you are trying to achieve and there may be a better solution to your problem.
The reason you are not supposed to the UI toolkit from other threads is that it is not written to be thread safe it is written under the assumption that only one thread runs it. This means it's really hard to tell what can go wrong, the bad effects, if any, will mostly happen in an un-repeatable due to specific timing of threads.
Your description of what you are trying to do it not too clear. In your case, I would just allocate a large bitmap, and draw text into it. Why are you using the EditText in the first place ? It seems like a kind of a hack, and hacks tend to break eventually.
Why View.buildDrawingCache()? What about using View.draw(Canvas canvas) to manually render to a Canvas backed by a Bitmap? Method seems simple enough to not cause problems on background threads.
EditText edit = (EditText)findViewById(R.id.edit);
edit.buildDrawingCache();
ImageView img = (ImageView)findViewById(R.id.test);
img.setImageBitmap(edit.getDrawingCache());
Lalit when you try to build the cache in the onCreate method, the drawing hasn't happened yet so the drawingCache should have nothing. Either put the buildDrawingChache method in the onClick method. Or use the following code in onCreate.
ViewTreeObserver vto = editText.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
editText.buildDrawingCache();
}
});
I also encountered this error a few times already:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
my solution:
new Thread(new Runnable(){
#Override
public void run(){
//add implementations that DOES NOT AFFECT the UI here
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run(){
//manage your edittext and Other UIs here
}
});
}
}).start();
just create a handler inside your worker thread to apply data changes to your UI
Related
I have a simple question.
In my UWP app I am using multiple threads and while on a background thread when i try to create a simple BitmapImage by using code: var image=new BitmapImage();. It throws an exception
The application called an interface that was marshalled for a different thread.
this exception occurs on the very line where I try to create the image. I simply want to create this image, deal with its properties and then store it in my datalist.
Note: datalist is a simple public static property which is accesible throughout the app. thankyou
I can't see the full context from the question, so I am not sure why this exception is bubbling up, but one sure way to fix it is using CoreDispatcher.RunAsync().
The documentation says:
If you are on a worker thread and want to schedule work on the UI thread, use CoreDispatcher::RunAsync.
If you are using MVVMLight, you can also make use of it's DispatcherHelper class' CheckBeginInvokeOnUI method. It's a bit better, since it first checks which thread it is called on and if it's the UI thread, it executes the action immediately and passes it to the UI thread only if needed.
I am creating a winRt app. In which I am having a Home.xaml page which having a another page called Market.xaml. So for snapped mode the same code is repeated.
Now my itemListView (used for snapped) and itemGridView (for full view) both have this page (Market)
<views:Market x:Name="viewMarket"/>
And the constructor of this page is called twice which I not want.
So do I use some flag kind of thing or some better approach is there.
Thanks
So, let's talk about this:
XAML is basically a varying syntax to C#. So, when XAML references a control like your views:Market with <Views:Market />, you are actually putting in something like new Views.Market() in both places. Basically, invoking the class twice. Should the constructor not fire twice, the time-space continuum would split in half. Dogs and cats living together, the whole 9 yards.
But, more fundamental here, what is the purpose of the constructor in C#, or in a XAML class? Is to do expensive things that you would not want to repeat? No. The reason for this is because the completion of the constructor is necessary before the UI thread is released and allowed to render the control. The resulting effect is a UI hang.
Moreover, the C# constructor is a synchronous method. It cannot properly invoke or hold asynchronous operations. This means long-running or expensive tasks that should be invoked immediately, should not be invoked in the constructor because it would also require them to be synchronous and UI-blocking. It is because of these last two points I suspect your constructor is being misused.
The solution is in the XAML framework. The XAML Page pipeline includes the constructor (since it is a C# class and they all have it) but it also includes a Loaded event. In many cases, the hard work necessary to fill page controls is in the Loaded handler. This allows the page to render properly, then starts the long-running action that will ultimately and asynchronously update control content.
In WinRT, the Page pipeline also includes an OnNavigatedTo() virtual method in the base that you can override to the same effect. In the override you can include the hard work of talking to a service, deserializing from a file, or whatever you need to make your UI work. Both the Loaded event and the override can be asynchronous, and neither prevent rendering by freezing the constructor.
But, there's another thing to consider since we're in C# and that the rather common pattern called singleton that allows for us to reference a type in two different contexts but without creating a brand new class. This is accomplished by making the class constructor private, but exposing a public property usually called Instance that returns a single, shared instances in some static place.
That might solve your problem already. Then again, none of that is probably what you need. Assuming you already know all that, the quick answer is you can't prevent a constructor because a constructor is necessary to create a new instantiation of any class, including a XAML view. Instead, whatever you are trying to prevent being double might need to be a combination of the discussions above. An offloaded method, and a static reference to prevent duplicate efforts.
Something like this:
public class Market : UserControl
{
public Market()
{
Loaded += Market_Loaded;
}
static bool AlreadyLoaded = false;
void Market_Loaded(object sender, RoutedEventArgs e)
{
if (AlreadyLoaded)
return;
AlreadyLoaded = true;
// TODO: your work
}
}
But that might not do it for you because the static variable is scoped too large. Instead, you can control if it does the big operation with a dependency property you add to your control. With a boolean dependency property set to false, the second control knows not to do something. With it set to true, the first knows to go ahead. And, so on. This prevents all future use of the view or user control in your app from thinking it should not run because of the static property in the above solution. Then again, that might be perfect.
Best of luck!
In Swing you have paint or update(Graphics g) method for each UI component which executes every frame. You can put your drawing logic in the overrided method and draw whatever you want. What is the paint method for JavaFX2 UI?
What I want to do is my UI receives control information from a socket server (another thread). Whenever a control information is received, I should update the UI.
There are two problems:
1. The control information is received from a different thread, it can not access the rendering thread directly.
2. How to update the UI constantly?
For Q1, I have a solution if I know where the update function is (Q2).
I can declare a List object, and insert the new control command received from the socket into the list. In the rendering loop, I can just observe the List object, retrieve the unprocessed command, and delete the already processed command.
However, where can I find such a rendering loop function? I guess maybe I can also do it with javax.concurrent.Task, but I don't find a way to do it.
I think i find the method, I use the following method and it can work. I don't know if there is a better solution
final Duration oneFrameAmt = Duration.millis(1000/10);
final KeyFrame oneFrame = new KeyFrame(oneFrameAmt,new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
//put UI update here
}
});
TimelineBuilder.create().cycleCount(Animation.INDEFINITE)
.keyFrames(oneFrame)
.build()
.play();
I'm using swing to display multiple javafx Tableview, each embeded (thanks to JFXPanel) in a swing TabbedPane
I use the well know pattern described in the oracle doc, in scala way :
implicit def fun2Run[T](x: ⇒ T) = new Runnable {
def run = x
}
def myTabbedScene():Scene = {
val root = new StackPane
root.getChildren.add(new Label("Hello world!"))
new Scene(root, 300, 300)
}
def initFxPanel(fxPanel: JFXPanel, s: ⇒ Scene) = {
fxPanel.setScene(s)
}
def initSwingGui(panel: PluginPanel) = {
val fxPanel = new JFXPanel()
// code to add panel to JPanel
panel.peer.add(fxPanel)
Platform runLater initFxPanel(fxPanel,myTabbedScene())
}
val jfxSwingPanel = new PluginPanel("wrap 2") {
var jtemp = new JPanel()
contents += jtemp
}
SwingUtilities invokeLater initSwingGui(jfxSwingPanel)
This code is executed each time the user open a new swing tab (only scene method differs) but i'm not sure this is the best way to manage thread in this case :-/
When i close or open a tab, i have some incoherent state in my application and error during display.
An example of my use case, and somes questions linked :
I open a first tab J1, a runlater is invoked, my scene display without problem in the tab.
I open a second tab J2, a new runlater is invoked on javafx Thread,
I switch to tab J1, how display in my tab is refresh ? An implicit runnable action is launched to main thread to make this possible ? How javafx recognized the good tab to refresh ? If i have a button which launch some action, i launch a runlater() action on the javafx main thread which dispatch ?
Update:
I find a code source which can help reader on this point, you can revalidate() or/and repaint() your swing panel (here _contentpane) which contain your jfxPanel
SwingUtilities.invokeLater(new Runnable() {
public void run() {
_contentPane.add(_jfxPanel);
_contentPane.revalidate();
_contentPane.repaint(); }});
I close the first tab J1, javafx automaticly close/garbage the javafx resource associated?
I have multiples other general questions :
How javafx application main thread manage this multiple runlater() call
when they arrive from different jfxpanel in swing ?
How can i close properly the resources (without close main javafx thread with exit() Platform method) associated to my jfxpanel when user close a tab ? If i destroy the JFXPanel,javafx resources used to display are liberated ?
Using task to manage my thread can be an answer to my problem ?
My question are probably naive, but i start in gui building, and i have problem to understand how javafx manage scene on different embedded panel.
How javafx application thread manage this multiple runlater() call when they arrive from different jfxpanel in swing ?
From the Platform.runLater javadoc:
Run the specified Runnable on the JavaFX Application Thread at some
unspecified time in the future. This method, which may be called from
any thread, will post the Runnable to an event queue and then return
immediately to the caller. The Runnables are executed in the order
they are posted. A runnable passed into the runLater method will be
executed before any Runnable passed into a subsequent call to
runLater.
Further:
How can i close properly the thread (without close main javafx thread) which execute my jfxpanel when user close a tab?
It's unclear which thread you are referring to. In general, when integrating JavaFX and Swing there are only two threads to be concerned with - the Swing dispatch thread and the JavaFX application thread - both of which should be managed by the respective underlying frameworks and you don't need to explicitly close. You don't need any other threads unless you are trying to do something which should not execute on either of those threads (such as a highly CPU intensive task or a remote I/O) - which from your sample code would not be appear to be the case.
Using task to manage my thread can be an answer to my problem ?
Unless you have a specific need for such a thing, such a solution would likely further complicate your situation than improve it.
I close the first tab J1, javafx automaticly close/garbage the javafx resource associated?
If you don't keep a reference to any of the resources in the related jfxpanel, then the Java Virtual Machine can garbage collect the jfxpanel and and resources associated with it - this is just standard Java garbage collection technology, nothing special here.
I switch to tab J1, how display in my tab is refresh ? An implicit runnable action is launched to main thread to make this possible ?
Sounds like a bad idea (the main thread in Java terms is the thread used to launch the Java's main function and is not involved in GUI programming at all). You probably want to submit your runnable refresh request via Platform.runLater() so that it will be executed on the JavaFX application thread.
How javafx recognized the good tab to refresh ?
You have a JavaFX JFXPanel in each swing tab and each swing tab knows which JFXPanel it has, so when you invoke Platform.runLater to refresh the specific panel, pass a (final) reference to the JFXPanel to be used. Here is some psuedo-code in no language whatsoever to illustrate the concept:
on swing tab change event
final JFXPanel curPanel = tab.getJFXPanel()
Platform.runLater() {
// update curPanel here...
}
If i have a button which launch some action, i launch a runlater() action on the javafx main thread which dispatch ?
In essence I think you are correct here, I'll just rewrite your question to clarify some of the terminology - let's say it's a swing button and on performing an action on the swing button, you make a call to Platform.runLater, then the code in the runLater call will be eventually be executed on the JavaFX application thread.
Other questions I cannot answer as I am not fluent enough in Scala to provide a reasonable answer.
Honestly, if you are just starting GUI building, then my unsolicited advice would be to use Java rather than Scala and stick with either Swing or JavaFX, but not mix it all together until you are really comfortable with the GUI building process - otherwise there are just way too many traps and pitfalls you may encounter during the integration that few will be able to assist you with.
I have a C++/CLI System::Windows::Forms::UserControl derived control which should only redraw (a small portion of) itself as new data is fed into it. For some reason though, the OnPaint mechanism is being called even when there's nothing to cause it external to the app.
Here's a snippet:
void Spectrogram::OnPaint(System::Windows::Forms::PaintEventArgs ^e)
{
// Overidden to stop the background being painted(?)
}
void Spectrogram::AddNewFFTData( float* data, int fataWidth )
{
Graphics^ gfx = CreateGraphics();
//now do some drawing
gfx->Dispose();
}
So I call the add data method to add some new data which should in theory write over the previous entry (which clears some highlighting) and write the new entry.
Back in the day I used to develop MFC/OpenGL apps and one of the first things I'd do would be to override the OnEraseBackground method. As far as I can see though, there's no obvious way of stopping it being erased. What have I missed?
You may be looking for Control.OnPaintBackground(). I've had to override that to do nothing for a custom control I wrote to bring a legacy MFC control into a Winforms project. Otherwise it would paint the background on top of the MFC control's paint job.
Essentially, in the .cpp:
void MyControl::OnPaintBackground(System::Windows::Forms::PaintEventArgs ^pevent)
{
// Do nothing, we don't want to paint over the native control.
// You may want to do something a little fancier for DesignMode
// if you use the winforms designer, though.
}
On the prototype:
protected:
void virtual OnPaintBackground(System::Windows::Forms::PaintEventArgs ^pevent) override;
What rectangle is being passed in to you via the event args? Is the entire control being invalidated, or just a portion of it?
Maybe it's a statement like this in the Form's constructor:
//do own background painting
this.SetStyle(ControlStyles.Opaque, true);
I think that prevents OnPaintBackground being invoked at all: so you don't need to override OnPaintBackground, and instead you can erase the background (or not) yourself in your OnPaint.
I did some stuff with the OnPaint lately (C#, if that matters), and I noticed it literally is drawn when a area of the control is revealed.
A better solution is to draw on a cached Bitmap, and draw it to the control every time dotNet asks for it.