The code below is where the error is coming from. What I wanted is to bring up the loginDialog1 after loginRedirectCheck is true. But instead of showing the progressDialog, the application crash. Am I doing anything wrong? How can I fix it? Thank you.
Runnable myRunnable = new Runnable() {
#Override
public void run() {
while(loginCheck){
if(loginRedirectCheck){
loginCheck = false;
new Handler().post(new Runnable() {
#Override
public void run() {
loginDialog1.show();
}
});
}
}
}
};
Thread myThread = new Thread(myRunnable);
myThread.start();
Am I doing anything wrong?
Yes, you are creating the Handler inside of your new thread. That causes its posted Runnables to be executed there which leads to an execution of loginDialog1.show(); inside the new thread but I guess it has to be executed in the UI-Thread.
How can I fix it?
Create your handler inside your UI-Thread (for example as instance variable of your object containing the myThrad.start()) and post() your runnable to that handler instead of a newly created one.
EDIT:
I think in your case a final local variable would be fine:
final Handler myHandler = new Handler();
Runnable myRunnable = new Runnable() {
[...]
loginCheck = false;
myHandler.post(new Runnable() {
#Override
[...]
Related
i need to update a textView from my asynctask. I have an custom adapter for the listview and there i want to have a countdown for each entry. I will start the asynctask for each entry from my Adapter. How can i update the textview each second from the asynctask?
Thanks for help :)
If you post your code, I can give you a better answer. However, a common way to update views periodically is by using Handlers.
private final Handler mHandler = new Handler(); //intialize in main thread
public void test() {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mTextView.setText("hello");
}
}, 1000);
}
You can do something like this (this will add an entry to a list view every one second). I have used the normal ArrayAdapter to add a string. You can use your custom adapter to do something similar. The publishProgress() method basically triggers the onProgressUpdate() method which hooks to the UI thread and displays the elements getting added.:
class AddStringTask extends AsyncTask {
#Override
protected Void doInBackground(Void... params) {
for(String item : items) {
publishProgress(item);
SystemClock.sleep(1000);
}
return null;
}
#Override
protected void onProgressUpdate(String... item) {
adapter.add(item[0]);
}
#Override
protected void onPostExecute(Void unused) {
Toast.makeText(getActivity(), "Done adding string item", Toast.LENGTH_SHORT).show();
}
}
Here is my question :-
I am in the process of building a client-server application where I post the request to the server to generate 2 XML's for me (server fetches the information from the DB and generates XML based on this fetched info). Now, once the server has created these 2 XML's, server streams back these 2 files to the client so that client can save them on their machine.
(POSTING + READING FROM THE STREAM) IS ONE JOB. Without 2nd operation i.e. reading from stream, Job is incomplete.
I have created a Job in eclipse which posts the request to the server and takes the streamed files and save them on client machine. Posting the request to the server is a asynchronous call (it will return immediately). Once call is posted and returned immediately, I start polling on the Network Pipe for any data sever has sent(in this case it is the XML's data) & write it into a file.
As you can see here that reading the XML's from the stream and writing them into a file is part of the overall main Job but, still a separate job in itself (should be run in a separate thread). If User cancels the main job, reading from the network stream should also be cancelled.
So, basically my requirement is a cacellable job which does this entire thing. Reading from the stream should be separate Thread/Job but should be inside the main Job. If user cancels the main Job, this innner Job (reading from the Job) should also get cancelled.
Can you guys suggests a clean approach for doing this?
-Ankit
You can create a mainjob and within that mainjob you can create a subjob. If the mainjob is cancelled you can delegate the cancel to the subjob.
I created a simple view with two buttons. One for starting the jobs and the other for cancelling.
package rcpexperiments;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
public class View extends ViewPart
{
private Job mainJob;
#Override
public void createPartControl(final Composite parent)
{
final Button button = new Button(parent, SWT.PUSH);
button.setText("Start Job");
button.addSelectionListener(new SelectionAdapter()
{
#Override
public void widgetSelected(final SelectionEvent e)
{
mainJob = new Job("Main Job")
{
private boolean canceled = false;
#Override
protected void canceling()
{
System.out.println("Cancel requested.");
canceled = true;
}
#Override
protected IStatus run(final IProgressMonitor monitor)
{
final Job subJob = createSubJob();
subJob.schedule();
canceled = false;
while (!canceled)
{
try
{
Thread.sleep(100);
}
catch (final InterruptedException e)
{
}
}
subJob.cancel();
System.out.println("Main Job is canceled.");
return Status.CANCEL_STATUS;
}
private Job createSubJob()
{
return new Job("Sub Job")
{
boolean subJobCancel = false;
#Override
protected void canceling()
{
subJobCancel = true;
}
#Override
protected IStatus run(final IProgressMonitor monitor)
{
System.out.println("Sub Job started.");
while (!subJobCancel)
{
try
{
Thread.sleep(100);
}
catch (final InterruptedException e)
{
}
}
System.out.println("Sub Job canceled");
return Status.CANCEL_STATUS;
}
};
}
};
mainJob.addJobChangeListener(new JobChangeAdapter()
{
#Override
public void done(final IJobChangeEvent event)
{
System.out.println("Job finished by " + event.getResult());
}
});
mainJob.schedule();
System.out.println("Main Job started.");
};
});
final Button cancel = new Button(parent, SWT.PUSH);
cancel.setText("Cancel");
cancel.addSelectionListener(new SelectionAdapter()
{
#Override
public void widgetSelected(final SelectionEvent e)
{
mainJob.cancel();
}
});
}
/** {#inheritDoc} */
#Override
public void setFocus()
{
}
}
I hope that is what you wanted.
It seemed to me like a bit of a hassle to define subjobs the way Micheal K. suggested. So I went looking into the Eclipse docs and found that the Job class defines a static method called createProgressGroup and can be used as follows (same doc) which does roughly the same thing:
Job parseJob, compileJob;
IProgressMonitor pm = Job.getJobManager().createProgressGroup();
try {
pm.beginTask("Building", 10);
parseJob.setProgressGroup(pm, 5);
parseJob.schedule();
compileJob.setProgressGroup(pm, 5);
compileJob.schedule();
parseJob.join();
compileJob.join();
} finally {
pm.done();
}
Please note that the IJobManager.getJobManager is deprecated.
My code is below: I am seeing that on running the app the loadWidget method gets invoked even when the adminLink is not clicked. This is not want I want, but I'm not sure what is causing the issue. Please advise
public class LoginModule implements EntryPoint {
LoginPopup loginPopup;
private class LoginPopup extends PopupPanel {
public LoginPopup() {
super(true);
}
public void loadWidget(){
System.out.println("I am called 1");
CommonUi cUi = new CommonUi();
//#342 moved code to common area
FormPanel loginForm = cUi.getLoginFormUi();
setWidget(loginForm);
}
}
#Override
public void onModuleLoad() {
//#251 improved login popup ui.
final Anchor adminLink = new Anchor("User Login");
// final Label adminLink = new Label("User Login");
adminLink.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
// Instantiate the popup and show it.
loginPopup = new LoginPopup();
loginPopup.loadWidget();
loginPopup.showRelativeTo(adminLink);
loginPopup.show();
}
});
if(RootPanel.get("admin") !=null)
RootPanel.get("admin").add(adminLink);
}
}
Running Dev Mode, set a breakpoint in that method in your Java IDE, and take a look at the current stack, what code is calling that method. If that is the only code in your app, then this only appears to be invokable from that onClick handlers, so it is a matter of figuring out why that is being invoked.
I have written an Eclipse plugin that works. What happens, though, is that during the run, no console output is displayed. Only when the process is finished does the output show up in the console. Below is my handler, which appears as an extension point of type org.eclipse.ui.commands:
public class MyHandler extends AbstractHandler {
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
...
MessageConsoleStream out = myConsole.newMessageStream();
...
IConsoleView view = (IConsoleView) page.showView(id);
view.display(myConsole);
...
out.println("output that only shows up at the end");
myConsole.activate();
...
// Slow process
...
out.println("everything is done");
return null;
}
}
So while the process runs, nothing in the console. Then at the end, both output lines pop into view.
I'm obviously doing the console thing incorrectly, but I haven't found any good examples, nor has my experimentation proven very fruitful. Please advise.
You could consider using a ProgressMonitor (possibly with cancelation in case the user wants to abort), so that the user can see that there is something going on.
This worked:
public class Merge extends AbstractHandler {
private static MessageConsole myConsole = null;
private static ExecutionEvent event = null;
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
Merge.event = event;
//same idea as original post and other examples where it makes new or finds existing
myConsole = makeConsole(Merge.event);
Job job = new Job("My Job Name"){
#Override
protected IStatus run(IProgressMonitor monitor){
...
if (blah) {
MessageConsoleStream out = myConsole.newMessageStream();
out.println("output show up right away");
...
// Slow process
...
out.println("everything is done");
} else {
MessageDialog.openInformation(HandlerUtil.getActiveShell(Merge.event), "Information", "Please select valid file");
}
monitor.done();
return Status.OK_STATUS;
}
};
job.setUser(true);
job.schedule();
return null;
}
...
}
Maybe you can call out.flush() after every out.print...
I have implemented a wizard for my Eclipse plug-in, showing several pages. One of these pages needs some lengthy initialization, that means it consists of a SWT table, which needs to be populated by information coming from an external source. This source needs to be activated first (one single method call that returns after a couple of seconds - I can not know in advance how long it will take exactly), before it can be used as input for for the table viewer. This initialization is currently done by the table model provider when it needs to access the external source for the first time.
Therefore, when I enter the wizard page, I would like to show a dummy progress bar that just counts up for a while. My approach was the following, but unfortunately does not work at all:
private void initViewer() {
IRunnableWithProgress runnable = new IRunnableWithProgress() { // needed to embed long running operation into the wizard page
#Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
SubMonitor progress = SubMonitor.convert(monitor);
Thread thread = new Thread() {
#Override
public void run() {
Display.getDefault().syncExec(new Runnable() {
public void run() {
viewer.setInput(ResourcesPlugin.getWorkspace().getRoot()); // this will make the table provider initialize the external source.
}
});
}
};
thread.start();
while(thread.isAlive()) {
progress.setWorkRemaining(10000);
progress.worked(1);
}
progress.done();
}
};
try {
getContainer().run(false, false, runnable);
} catch(Exception e) {
throw new Exception("Could not access data store", e);
}
}
This method gets then invoked when the wizard page's setVisible()-method is called and should, after a couple of seconds, set the viewer's input. This, however, never happens, because the inner-most run()-method never gets executed.
Any hints on how to deal with long-running (where an exact estimate is not available) initializations in Eclipse wizards would be very appreciated!
I have given below a simple example on how to use IRunnableWithProgress along with a ProgressMonitorDialog to perform a task of unknown quantity. To start with, have an implementation to IRunnableWithProgress from where the actual task is performed. This implementation could be an inner class.
public class MyRunnableWithProgress implements IRunnableWithProgress {
private String _fileName;
public MyRunnableWithProgress(String fileName) {
_fileName = fileName;
}
#Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
int totalUnitsOfWork = IProgressMonitor.UNKNOWN;
monitor.beginTask("Performing read. Please wait...", totalUnitsOfWork);
performRead(_fileName, monitor); // This only performs the tasks
monitor.done();
}
}
Now, a generic implementation to ProgressMonitorDialog can be created as below which could be used for other places where a progress monitor dialog is required.
public class MyProgressMonitorDialog extends ProgressMonitorDialog {
private boolean cancellable;
public MyProgressMonitorDialog(Shell parent, boolean cancellable) {
super(parent);
this.cancellable = cancellable;
}
#Override
public Composite createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
setCancelable(cancellable);
return container;
}
}
Having got the required implementation, the task can be invoked as below to get it processed with a progress dialog.
boolean cancellable = false;
IRunnableWithProgress myRunnable = new MyRunnableWithProgress(receivedFileName);
ProgressMonitorDialog progressMonitorDialog = new MyProgressMonitorDialog(getShell(), cancellable);
try {
progressMonitorDialog.run(true, true, myRunnable);
} catch (InvocationTargetException e) {
// Catch in your best way
throw new RuntimeException(e);
} catch (InterruptedException e) {
//Catch in your best way
Thread.currentThread().interrupt();
}
Hope this helps!
I assume the reason why it's "not working" for you is that the preparation of input is done in UI thread meaning that the progress bar cannot be updated. A better approach is to prepare input in advance and only set input to viewer after that.