I'm working on an Android application designed with Fragment that's why I'm using the BarcodeFragLib which use the Zxing library.
I'm looking for a way to custom the capture view, adding button and catch the event in my Activity.
If anyone has a hint or an ideas of how to solve my problem is welcome in advance :)
If you are using Xamarin, you could to use a event args static that when the code will be captured then you active the event and you will catch the code.
Is like:
public class GenericEventArgs<T>:EventArgs
{
public T Result;
public GenericEventArgs (T result)
{
Result = result;
}
}
and use this form:
public static event EventHandler<GenericEventArgs<string>> GetCodeBar_Completed;
if (GetCodeBar_Completed != null) {
GetCodeBar_Completed (this, new GenericEventArgs<string> (value));
}
and subcribe this.
PreferencesData.GetCodeBar_Completed += (s, a) => {/*content...*/};
Related
In Android, how do I take an action whenever a variable changes?
So I want to implement a listener for an object I created. What I want it to do is execute a block of code when its value changes from false to true.
As I am following this thread, I can't understand where the person wants us to implement the last block of code containing the logic for the listener.
Could someone, hopefully, guide me in the right direction?
(This question is being asked here as I don't have enough rep. points)
That last bit of example code triggers the listener, so it basically needs to be run whenever the "event" occurs. In this case the "event" is whenever (wherever in the code) the value of the variable changes.
If you have a setter and that is the only place the value changes, that is where you'd put it. If you are changing the value in multiple places throughout your code, I would make a new private method (call it signalChanged), put your code there, and then call it immediately after the variable assignment in the cases you want the listener to fire.
Here's an example (some code borrowed from linked answer, haven't checked that it compiles).
public class MyObj
{
public MyObj(int value)
{
setValue(value);
}
private int myValue;
public int getValue() { return myValue; }
public void setValue( int value )
{
if (value != myValue)
{
myValue = value;
signalChanged();
}
}
public interface VariableChangeListener
{
public void onVariableChanged(Object... variableThatHasChanged);
}
private VariableChangeListener variableChangeListener;
public void setVariableChangeListener(VariableChangeListener variableChangeListener)
{
this.variableChangeListener = variableChangeListener;
}
private void signalChanged()
{
if (variableChangeListener != null)
variableChangeListener.onVariableChanged(myValue);
}
}
you have to create a callback interface
here is a good about custom listener tutorial
here is a sample
public class MyObj {
VariableChanger onVariableChanged ;
public void setOnVariableChanged(VariableChanger onVariableChanged) {
this.onVariableChanged = onVariableChanged;
}
void log(){
boolean changed = false;
onVariableChanged.onVariableChanged();
//this will call it
}
interface VariableChanger{
void onVariableChanged();
}
}
class logic {
MyObj mo = new MyObj();
void main(){
mo.setOnVariableChanged(new MyObj.VariableChanger() {
#Override
public void onVariableChanged() {
//do your action
}
});
}
}
In Android, like any language, most developper uses logic comparisons to check values (if, else, switch, =, !=, >, <, etc) or Event (signal)
What kind of listener do you want to implement?
I'm newbie in Android develop. I use Robobinding (MVVM framework) to develop Android application and I didn't found any solution to create validation in presentation model (not in activity). Has anyone encountered a similar problem? Which approach is chosen?
I need somthing like this:
public class LoginPM extends AbstractPresentationModel {
private String login;
public String getLogin() { return login; }
public void setLogin(String value)
{
if (!StringComparator.IsEquals(this.login, value))
{
if(TextUtils.isEmpty(value))
{
setError("login", "Field cannot be left blank.");
return;
}
this.login = value;
firePropertyChange("login");
}
}
}
Sorry for the late reply. I did not notice the question. Can you have a LoginView interface between your LoginActivity and LoginPM? In that way, you can do something like below:
public void login() {
if(isInvalid(loginInfo)) {
loginView.setLoginError("error info");
} else {
loginService.login(loginInfo);
}
}
Alternatively, you can implement OnTextChange event for TextView, which is fairly easy to do. You can refer to text attribute binding implementation of TextView. And you can register a method to listen to the event. Once the event is fired, you can get hold of TextView from the event object.
Also, you can implement error binding attribute for TextView and update error info accordingly.
If you like, you can post into the RoboBinding google group to get a quick response.
Hope this helps,
Cheng
I have resolved my task using reflection to getting user controls from binding-objects maps (Robobindings).
https://github.com/Barbanyaga/RobobindingValidation/blob/master/BasePresentationModel.java
Use like this:
public class LoginPM extends BasePresentationModel {
private String login;
public String getLogin() { return login; }
public void setLogin(String value)
{
if (!StringComparator.IsEquals(this.login, value))
{
if(TextUtils.isEmpty(value))
{
setError("login", "Field cannot be left blank.");
return;
}
this.login = value;
firePropertyChange("login");
}
}
}
So I have a View:
public class RadialMenuWidget extends View
from where I want to start a thread like I do from an activity
String urlInput = "http://myserver.com/"+mynewfile;
DownloaderThread downloaderThread = new DownloaderThread(UpdateActivity, urlInput);
downloaderThread.start();
but I get the message "Expression expected" on this line "DownloaderThread(UpdateActivity,... " more specifically on the activity name (UpdateActivity) even though I imported the activity inside the Widget.
What can I do to avoid this while still being able to call the thread.
The idea is, I use the RadialMenuWidget, and inside the RadialMenuWidget class I test to see which menu button was pressed and based on that, I decide what to do next. Calling other intents works just fine, but now I want to start to download a file using a separate thread (that I can call from a regular activity's onButtonClick)
EDIT
So my radialMenu has this structure:
public class RadialMenuWidget extends View {
...
public interface RadialMenuEntry {
...
}
public RadialMenuWidget(Context context) {
...
}
#Override
public boolean onTouchEvent(MotionEvent e) {
...
if (state == MotionEvent.ACTION_UP) {
...
if (menuEntries.get(i).getName() == "Update now") {
String urlInput = "http://myhost.com/"+mynewfile;
DownloaderThread downloaderThread = new DownloaderThread(this.UpdateActivity, urlInput);
downloaderThread.start();
}
}
...
And the DownloadThread class looks like this:
public class DownloaderThread extends Thread {
public DownloaderThread(UpdateActivity inParentActivity, String inUrl)
{
downloadUrl = "";
if(inUrl != null)
{
downloadUrl = inUrl;
}
parentActivity = inParentActivity;
}
#Override
public void run()
{
// does the download
}
...
}
Please help.
Thank you
My solution in the end was to mimic a 2 button radial menu using images. I used the images as backgrounds for a button, placed them in a linear layout, used 9-patch images and got to call the thread onClick like before. So I avoided having to deal with radialMenuWidget in this view.
So question is over now.
I was hoping for a java solution to this problem since I am a newbie and eager to learn anything Android, but this is it, I will manage with my (ugly) solution.
Please excuse my french english !
So, I have got a problem in my Android code...
I call a method which much return a arrayList of a custom object... but this arrayList is loaded asynchronously and returned in a listener.
Do you know how I could return datas when the method of my listener is called ?
Here my code :
public static ArrayList<Advert> getAdverts(Context context) {
// Initialize
RestHelper restHelper = new RestHelper();
// Set the listener
restHelper.setOnRestListener(new OnRestListener<Advert>() {
#Override
public void onDataAvailable(ArrayList<Advert> result) {
// -- Datas are loaded : now we must return them ! --
}
});
// Launch the async query
restHelper.getRemoteAdverts();
}
Thanks !!
I'm not sure about the problem. You have an async method that you can call, but it can't return your result since its an async method, so you have 2 solutions :
- Wait in the method that all data are available, but you loose the async benefits.
- Implements an Oberserver/Observable pattern.
For the first option, look into the RestHelper, maybe you have already the solution.
Example for the second option :
public static void requestAdverts(Context context) {
RestHelper restHelper = new RestHelper();
final AdvertListener thisInstance = this;
restHelper.setOnRestListener(new OnRestListener<Advert>() {
#Override
public void onDataAvailable(ArrayList<Advert> result) {
thisInstance.notifyDataLoaded(result);
}
});
// Launch the async query
restHelper.getRemoteAdverts();
Create an Interface :
interface AdvertListener {
notifyDataLoaded(ArrayList<Advert> result);
}
And finally let the main class (the one that call the requestAdverts method) implements your new interface.
Well, please revisit your function design, you are tiring to make asynchronously load inside a synchronous function (getAdverts). If your function is synchronous, then just synchronously load the list and return.
If for any reason, if you want to go ahead with current approach, please block the caller after setOnRestListener and when you get a callback(onDataAvailable) unlock it and return your list.
You can use ConditionVariable, for this.
Block the caller:
ConditionVariable.block ();
ConditionVariable.close ();
UnBlock/open the caller:
ConditionVariable.open ();
Hope, this helps.
I have a weird / unique situation with my ListView. This is the scenario:
I'm making use of the MVP design pattern. As the Activity starts, it raises an event to notify the presenter to fetch some data from a web service. The web service call is an Async call. Once the web service Completed event is raised, I take the result and push it into a property (which is of type Array) that resides within my View / Activity.
Everything I mentioned works just fine, but as soon as the device is rotated, some interesting developments take place.
The async call resumes as normal and provides the property (Array) with a value. So nothing wrong there... (And yes there is data in the collection) I then set the ListView Adapter and call the notifyDataSetChanged, but nothing happens. The UI is not updated or anything?? If I re-enter the Activity the data is visible again ??
I even tried calling invalidateViews and invalidate on the ListView - this didn't do anything.
Could someone please assist me in this matter?
Many thanks in advance!
[Update]
I would like to stress the fact that I am making use of C# (Xamarin) and not Java (:sigh: - yes I know). Furthermore, I am not making use of the ASyncTask class, instead I'm making use of the async methods created within the proxy classes generated by Visual Studio. Pretty straight forward, but this is the code that populates the ListView - the property is set from the presenter
Presenter
Where View is of type IContactsView
protected override void OnCollectData(System.Collections.IEnumerable data, Type typeOfData)
{
if (data != null && typeOfData != null && typeOfData.Equals(typeof(UserContact)))
{
this.View.UserInformationCollection = data.Cast<UserContact>().ToArray();
}
}
Activity
The activity implements IContactsView
public UserContact[] UserInformationCollection
{
get
{
return this._userInformationCollection;
}
set
{
this.RunOnUiThread(() =>
{
this._userInformationCollection = value;
ListView listview = this.FindViewById<ListView>(Resource.Id.userLV);
if (listview != null)
{
UserContact[] subsidiesList = this.GetIndexedContacts(this._userInformationCollection);
listview.Adapter = new ContactsAdapter(this, subsidiesList.ToList());
((ContactsAdapter)listview.Adapter).NotifyDataSetChanged();
}
});
}
}
[/Update]
Found a much better solution! So please ignore the static variable idea!
Activity:
Override the OnRetainNonConfigurationInstance and return the presenter
public override Java.Lang.Object OnRetainNonConfigurationInstance()
{
return this._presenter;
}
Within the OnCreate check the LastNonConfigurationInstance and get the presenter - if it isn't null:
protected override void OnCreate(Bundle bundle)
{
...
if (this.LastNonConfigurationInstance != null)
{
this._presenter = this.LastNonConfigurationInstance as ContactsPresenter;
this._presenter.RefreshView(this);
}
else
{
// create a new presenter
this._presenter = new ContactsPresenter(this);
}
...
}
So maybe, you saw what I did in the previous code sample? Yes, I send the new instance of the activity to the presenter - have a look at the RefreshView
Presenter:
So within my base presenter I have the following method:
public class Presenter<T> : Java.Lang.Object, IPresenter where T : IView
{
/// <param name="view">The view.</param>
public void RefreshView(T view)
{
this.View = view;
}
}
The above code helps my presenter say with the creation of new activities - so when it returns data after the async call it will have the latest and greatest instance of the activity!
Hope this helps!
Kind regards,
Got it working by doing the following:
declare a static variable of the activity:
private static ContactsActivity _cachedActivity = null;
Overrode the OnResume within the activity and set the variable:
protected override void OnResume()
{
base.OnResume();
_cachedActivity = this;
}
Override the OnCreate within the activity and set the variable:
protected override void OnCreate(Bundle bundle)
{
...
_cachedActivity = this;
...
}
Lastly I changed the property mentioned earlier:
public USBUserContact[] UserInformationCollection
{
get
{
return this._userInformationCollection;
}
set
{
_cachedActivity.RunOnUiThread(() =>
{
_cachedActivity._userInformationCollection = value;
ListView listview = _cachedActivity.FindViewById<ListView>(Resource.Id.userLV);
if (listview != null)
{
UserContact[] subsidiesList = _cachedActivity.GetIndexedContacts(_cachedActivity._userInformationCollection);
listview.Adapter = new ContactsAdapter(_cachedActivity, subsidiesList.ToList());
((ContactsAdapter)listview.Adapter).NotifyDataSetChanged();
}
});
}
}
Kind regards,