How to start an activity from other activity but with specific intent - from OnNewIntent - android-activity

Ok... so i guess the title is a bit confusing. so i will explain:
I have an NFC app which i handle a NDEF_DISCOVERED succesfuly in activity A. then a new activity is launched (B).
In this new activity (B) i want to be able to catch another tag and let activity A handle it as before, so i use OnNewIntent to get this intent of the tag and want to start activity A.
But if i call startActivity(myIntent) with the traditional myIntent = new Intent(this, A.class) then activity A launced with this myIntent and i want the activity A to handle the tag intent that was 'caught' on activity B..
how can i do that?
Thanks.

You should be able to add your tag intent in activity B as an extra to the traditional intent with myintent.addExtra("tagkey", tagIntent). Because Intent implements Parcelable, it will be added as a Parcelable extra. Then in the onCreate() of activity A, put something like:
Intent intent = getIntent();
if (intent.hasExtra("tagkey")) {
setIntent(intent.getParcelableExtra("tagkey")
}
Replace the string "tagkey" with whatever is most relevant to your own code. You can put a similar snippet in onNewIntent() as well.

If the NDEF message type is specific enough such that only your Activity A will match it, you can set 'android:launchMode="singleTask"' in the activity section of your Android manifest for this Activity. Activity B will then be closed whenever you scan a new tag with the same type of NDEF message.

Related

MVVM, wait cursor while opening "slow" page

I have MVVM application with multiple pages. My all pages have ReadCommand() bound with:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding ReadCommand}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
This is my Read() command in ViewModel:
private void Read(object parameter)
{
HwDevice Device = new HwDevice();
this.Alarms = Device.Alarms; // this is slow (reading data from RS232 device)
Device.Dispose();
}
One page has slow data source and my application is frozen when this page is being loaded (about 5 seconds).
I want to set wait cursor on whole window, but I don't know how to do it in MVVM (Im MVVM newbie). Do I have to pass window reference by command parameter and set Wait cursor in command? If I should - how can I do it in XAML?
The problem is that the thread where you are going to execute your operation, is the same where your UI live. It's here that the BackgroundWorker come in handy.
BackgroundWorker bw = new BackgroundWorker();
bw.RunWorkerAsync += bw_DoWork;
bw.ProgressChanged += bw_ProgressChanged;
bw.RunWorkerCompleted += bw_WorkDone
The previous part was the declaration. Now you need to implement the events, but first modify Read method
private void Read(object parameter)
{
bw.RunWorkerAsync(parameter);
// put your logic here
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
object parameter = e.Argument;
}
Now that the logic is placed on another thread, you can use the progressChanged method to do various stuff. Like showing a progress bar to report the status, or simply enable or disable your wait cursor.
EDIT: You don't need to pass the bw to the UI. If you are using MVVM (like you should and you are doing) you can use bindings and event at your advantage, or implement an interface like this one. The point of the whole thing is that the UI is just "informed" that something on the background is going on, avoiding to freeze the main thread. You just need to decide how to display it. So it can be either using a wait cursor, or implementing a progress bar.

How to get ISelectionService outside of UI-Thread

I am trying to find the currently selected Project/File and all ways I found so far are using the ISelectionService. The way I found to get an instance of it is:
ISelectionService selectionService = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage();
But unfortunatly .getActiveWorkbenchWindow() returns null since I am not inside the UI-Thread. Is there any good way to get the ISelectionService from outside the UI-Thread?
You can use:
Display.getDefault().synchExec(runnable);
to run a Runnable in the UI thread where you can get the selection service.
However most UI code expects to be run in the UI thread so you may need to use syncExec or asyncExec for anything that is to do with the UI.
Most likely you are following the wrong appraoch. You should obtain the selected project or file before you run the non-UI/background thread.
If your background thread is triggered by a user interaction and should operate on the selected resource (project/file) the selection may well have changed when the thread reaches the point where it queries the selection.
Instead, evaluate the selection on the UI thread and pass the extracted resource as a parameter to your background thread.
For example (simplified code):
// on the UI thread:
IResource resource = ( IResource )getSelectionService().getSelection().getFirstElement();
new Thread( new Runnable() {
public void run() {
resource.copy( ... ); /// or whatever should be done with the resource
}
} ).start();

How to do code split in a typical GWT mvp project?

My app is a typical GWT application, it has a navigation bar, when click one bar item, the place will be changed and the app will find corresponding activity for that place(done in MasterActivityMapper), then call activity.start(). During the init of activities, the corresponding views were also created. When my app first starts, it will by default select the first navigation bar item.
public class MasterActivitiesMapper implements Activity
{
public Activity getActivity( Place place )
{
if(place equals place1)
{
Activity1 a1= new Activity1();
return a1;
}
else if(place equals place2)
{
Activity1 a2= new Activity2();
return a2;
}
else if(...)
{
....
}
}
}
My app works well except that the initial download size is too large, it will takes 10 seconds to load. I have to use code split the solve this problem.
I read the doc
https://developers.google.com/web-toolkit/doc/latest/DevGuideCodeSplitting
However still can not figure out where/how to split the code, could anybody has experience with this help?
Activity.start, being asynchronous by nature, seems like a good place to put a GWT.runAsync.
There's also the possibility of returning an activity async proxy from your ActivityMapper. See http://code.google.com/p/google-web-toolkit/issues/detail?id=5129 and https://gist.github.com/3038878 for some sample code.

pause viewmodel process for user input

I've been looking at a view examples of the typical "raise dialog from viewmodel" problem, noting 3 main solutions:
use attached behaviors
use a mediator pattern
use a service
I'm getting a bit bogged down though and struggling to find a solution that easily fits into my problem space - which is a very simple file copy problem:
My viewmodel is processing a loop (copying a list of files)
When a file already exists at the destination I need to raise a modal dialog to get confirmation to replace
The vm needs to wait for and receive confirmation before continuing
The "modal dialog" is actually not a new window but a hidden overlay in my MainWindow, as per http://www.codeproject.com/KB/WPF/wpfmodaldialog.aspx (thanks Ronald!)
I'm mostly there but the biggest struggles I have are:
- how to pause the loop in the viewmodel while it waits for input
- how to get input back to the viewmodel within the loop so it can carry on
So far I'm leaning towards the service solution because it seems a direct method call with a return that the vm must wait for. However, it does mean the service needs to tie directly to the view in order to make an element visible?
If anyone can post some simple code that deals directly with this problem I (and the net) would be very happy! Thanks!
For example, you have a service called IDialogService with the following interface:
public interface IDialogService
{
bool ConfirmAction(string title, string confirmationText);
}
As you mentioned, in order for the service to be able to show the actual dialog it needs to have a reference to the view that will show the actual overlay element. But instead of directly referencing the view I prefer to reference it via an interface. Lets call it ICanShowDialog and it will have the following members:
public interface ICanShowDialog
{
void ShowDialog(object dialogContent);
void HideDialog();
}
This interface will be implemented by your view that owns the dialog overlay (e.g. your main window).
Now the interesting part: suspending the code execution while the dialog is shown. First of all, I would recommend you not to use overlay elements but use usual windows if possible. Then you will not have that problem. You can style the dialog window so it will look just like the overlay element.
Anyway, if you still want to use overlay elements then you can do the following trick to suspend the code execution:
Here is pseudo code of the ConfirmAction method of the IDialogService inteface:
public bool ConfirmAction(string title, string confirmationText)
{
ConfirmationDialogView dialogView = new ConfirmationDialogView(title, confirmationText);
DialogShower.ShowDialog(dialogView); // DialogShower is of type ICanShowDialog
while (!dialogView.ResultAvailable)
{
DispatcherUtils.DoEvents();
}
DialogShower.HideDialog();
return dialogView.Result;
}
Here is the code of DispatcherUtils.DoEvents() (that was taken from here: http://dedjo.blogspot.com/2007/08/how-to-doevents-in-wpf.html):
public static class DispatcherUtils
{
public static void DoEvents()
{
DispatcherFrame f = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(
DispatcherPriority.Background,
(SendOrPostCallback)delegate(object arg) {
DispatcherFrame fr = arg as DispatcherFrame;
fr.Continue=True;
}, f);
Dispatcher.PushFrame(frame);
}
}
But I must warn you. Using DoEvents can result in some subtle bugs caused by inner dispatcher loops.
As an alternative to suspending the code execution while a dialog is shown you can use callbacks:
public interface IDialogService
{
void ConfirmAction(string title, string confirmationText, Action<bool> dialogResultCallback);
}
But it will not be so convenient to use.

Problem in Large scale application development and MVP tutorial

I recently tried to follow the Large scale application development and MVP tutorial. The tutorial was great but I am having a hard time with a few things.
If you try and add a contact to the list, the contact is created. If you try and add another contact, you are taken to the edit screen of the last contact you created. No more contacts can be added once you add your first contact. What needs to be changed so you can add more than one contact.
Changes I have made to try and get it to work:
Create a new editContactsView each time the add button is pressed. This brings up a blank edit screen, but the new contact still overwrites the previous addition.
Changed contacts.size() to contacts.size()+1 when determining the ID of the new contact.
Actually, there are a couple of problems (from what I can see):
like Lumpy already mentioned, the new Contact created via EditContactPresenter doesn't get an id assigned (it's null). This is because EditContactPresenter uses the default Contact() constructor which doesn't set the id. There are many possible solutions to this: add setting the id in the default constructor (so that you don't have to keep track of the ids somewhere else in the app), delegate that function to your server (for example, make your DB generate the next available id and send it back) or just add a contact.setId(whatever); in the appropriate place in EditContactsPresenter
AppController.java:134 - this example reuses the view (which is a good idea), but it doesn't clear it if you use it for creating a new Contact. Solution: either disable view reusing (just make a new EditContactsView every time) or add a clear() or sth similar to your Views and make the Presenters call it when they want to create a new entry, instead of editing an exisiting one (in which case, the values from the current entry overwrite the old values, so it's ok).
It's weird that this sample was left with such bugs - although I understand that it's main purpose was to show how MVP and GWT go together, but still :/
When a new contact is added it's id is never set. Because the id field is a string it is stored as "". That is how the first contact is added. Now every time you create a new contact you overwrite the contact with key "". To fix this you need to set the value of the id. I did this by changing the doSave method in EditContactsPresenter.
private void doSave() {
contact.setFirstName(display.getFirstName().getValue());
contact.setLastName(display.getLastName().getValue());
contact.setEmailAddress(display.getEmailAddress().getValue());
if(History.getToken.equals("add")
rpcService.updateContact(contact, new AsyncCallback<Contact>() {
public void onSuccess(Contact result) {
eventBus.fireEvent(new ContactUpdatedEvent(result));
}
public void onFailure(Throwable caught) {
Window.alert("Error updating contact");
}
});
else
rpcService.updateContact(contact, new AsyncCallback<Contact>() {
public void onSuccess(Contact result) {
eventBus.fireEvent(new ContactUpdatedEvent(result));
}
public void onFailure(Throwable caught) {
Window.alert("Error updating contact");
}
});
}