The scenario is, I am developing an app which reads integer value from file and store it in integer. And value that I get from that file is always changing cause it is cpu frequency value.
How do I keep watch on this value from my activity ?
The ways in my mind are through broadcast receiver, service, observer etc.
But dont know how do I implement..
You can use a listener:
public class CpuValueReader {
private CpuValueReaderListener listener = null;
int cpuValue;
public void setListener(CpuValueReaderListener listener) {
this.listener = listener;
}
public void startReading() {
// this is an exmaple, you may read the file here
// found value:
setValue(theNewValue);
}
private setValue(int value) {
if (value != cpuValue) {
cpueValue = value;
if (listener != null)
listener.cpuValueChanged(value);
}
}
}
the interface:
public inteface CpuValueReaderListener {
public void cpuValueChanged(int newValue);
}
Using it (just an example):
CpuValueReader instance = new CpuValueReader ();
instance.setListener(new CpuValueReaderListener() {
#Override
public void cpuValueChanged(int newValue) {
// do cool things with new value
}
});
I achieve this using chronometer tick listner. So on every tick of chronometer I read the file and set value to text view
chronometer = (Chronometer)findViewById(R.id.chronometer1);
chronometer.setOnChronometerTickListener(new OnChronometerTickListener()
{
#Override
public void onChronometerTick(Chronometer arg0)
{
//read file here and set the value to my textView
}
});
chronometer.start();
Related
I am working with fragments but I am not able to access its variables from an external class.
Currently, I have a fragment fragmentView which has a settings button. Whenever it is pressed, it shows an UI Element to define different settings. I copy the code that I have:
Fragment
public static Boolean show = false;
private void initSettingsPanel() {
m_settingsBtn = (ImageButton) m_activity.findViewById(R.id.settingButton);
/* click settings panel button to open or close setting panel. */
m_settingsBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
m_settingsLayout = (LinearLayout) m_activity.findViewById(R.id.settingsPanelLayout);
if (m_settingsLayout.getVisibility() == View.GONE) {
m_settingsLayout.setVisibility(View.VISIBLE);
if (m_settingsPanel == null) {
m_settingsPanel = new SettingsPanel(m_activity, show); //HERE I CALL THE EXTERNAL CLASS
}
} else {
m_settingsLayout.setVisibility(View.GONE);
}
}
});
}
SettingsPanel
private Activity m_activity;
private static Boolean p_show;
private Switch p_switch;
public SettingsPanel(Activity activity, Boolean show
) {
p_show = show;
m_activity = activity;
initUIElements(); // Init switch
}
private void initUIElements() {
p_switch = (Switch) m_activity.findViewById(R.id.showSwitch);
setUIListeners();
}
private void setUIListeners() {
p_switch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
p_show = isChecked;
}
});
}
}
What is currently happening is that when I activate the switch I change the value of th evariable of Pannel but it does not affect to the fragment. Why? Is there any other way to change the value of its variables not sending to SettingPanel each of the variables? Is it at least a correct way to do it?
You can register an interface between your activity and your fragment(s) -
public interface CallbackInterface {
//you can also return values from this interface
void performSomething(); //Add params to this method as per yourneed
}
In your activity class -
public YourActity extends AppCompactActivity implements CallbackInterface {
//your interface instance
private CallbackInterface mCallbackInterface;
#Override
void performSomething() {
// Write your code here.
}
}
}
In your fragment, you can override the
onAttach()
to register to the interface --
#Override
public void onAttach(Context context) {
super.onAttach(context);
mCallbackInterface = (CallbackInterface) context;
}
Voila! Now you can use this interface to send any data back to your activity.
In the end, I have created an abstract class in order to get and set the variables:
ShowVar
public abstract class ShowVar {
static private Boolean show = false;
public Boolean getShow() {
return show;
}
public void setShow(Boolean value) {
this.show = value;
}
}
From my SettingPanel I have instance ShowVar to set the new values of the variable each time and change the switch
SettingsPanel
public class SettingsPanel {
public ShowVar showVar = new ShowVar() {
#Override
public void set_Show(Boolean show) {
super.setShow(show);
}
};
}
and from my fragment I have access to the values by using my variable m_settingsPanel
Fragment
m_settingsPanel.showVar.getShow()
In my Activity, I have a Training object member initialized during onCreate(). All the members of this object are set.
private Training mTraining; is a class member
public class Training extends BaseModel {
...
#SerializedName("state")
public TrainingState state;
....
public TrainingPreview() {
}
This object is got from server (JSON), and I had a converter on this state to ensure this enum can't be null (I use GSON engine):
public class TrainingStateConverter extends EnumConverter<TrainingState> {
public static final Type TYPE = new TypeToken<TrainingState>() {}.getType();
#Override
protected TrainingState deserialize(String value) {
return TrainingState.fromString(value);
}
#Override
protected TrainingState getUnknownValue() {
return TrainingState.UNKNOWN;
}
}
During the setup, I've created the exercise list with the listener to show a specific exercise:
private void refreshExercisesList() {
final Runnable showTrainingParts = new Runnable() {
public void run() {
int nbItems = mCardExercises.setExercises(mTraining.training, mTraining.state,
new FlatCardTrainingProfilePartExercisesView.OnClickExerciseListener() {
#Override
public void showPart(String trainingPartId, int index) {
onClickOnExercisesList(trainingPartId, index);
}
});
}
};
}
...
}
My onClickOnExercisesList() method:
private void onClickOnExercisesList(String trainingPartId, int index) {
...
switch (mTraining.state) {
...
This Activity code works perfectly since couple of months, but yesterday there was a NullPointerException on switch (mTraining.state) :
int com.xxx.model.training.TrainingState.ordinal()' on a null object reference
com.xxx.ui.training.TrainingActivity.onClickOnExercisesList
How is possible guys?
Thank you very much for your help!
This would occur if state did not appear in the JSON.
The TypeConverter is only used if there is a value in the JSON to convert. If the value isn't present, then there's nothing to convert, so the value is whatever the default is, which is null, because you didn't set it:
#SerializedName("state")
public TrainingState state;
To fix the issue, initialize the variable to a default value:
#SerializedName("state")
public TrainingState state = TrainingState.UNKNOWN;
I'm mostly C# developer and I'm recently working on some Android project. I have to implement some custom written events in Android, but I'm not sure how to do that.
I wrote a C# code for what I want to do, so if anyone can help me with translating it into Android code, that would be appreciated.
I need to have a custom function (event), placed at MySecondClass, which can be triggered from MyFirstClass.
For example, we have the class:
private class MyFirstClass
{
private event EventHandler<MyCustomEventArgs> _myCustomEvent;
public event EventHandler<MyCustomEventArgs> MyCustomEvent
{
add { _myCustomEvent += value; }
remove { _myCustomEvent -= value; }
}
public void Initialize()
{
MySecondClass myObjectSecondClass = new MySecondClass();
this.MyCustomEvent += myObjectSecondClass.SomeMethodSecondClass;
}
public void SomeMethodFirstClass(int index)
{
//here we will trigger the event with some custom values
EventsHelper.Fire(this.MyCustomEvent, this, new MyCustomEventArgs(index));
}
}
The MyCustomEventArgs is defined as:
public class MyCustomEventArgs : EventArgs
{
public int index;
public MyCustomEventArgs(int indexVal)
{
index = indexVal;
}
}
And the the second class is defined as:
private class MySecondClass
{
public void SomeMethodSecondClass(object sender, MyCustomEventArgs e)
{
//body of the method
//we can use e.index here in the calculations
}
}
So I'm not sure how to handle with these "Event" related commends in Android.
Its all interfaces in java. No fancy complicated key word here :)
There should be an interface which the second class implements.
public interface EventHandler{
void onEventFired(EventParams e);
}
public class MyFirstClass{
EventHandler eventHandler;
public void initialize(){
eventHandler = new MySecondClass();
}
public void method(){
EventParams eventParams = new EventParams();
//fire event here
eventHandler.onEventFired(eventParams);
}
}
public class MySecondClass implements EventHandler{
#Overrride
void onEventFired(EventParams e){
//handle event here
}
}
I hope you get the idea
In a loop, I need to call multiple times a method with callback . How can I know when all is finished ?
#Override
public void onObjectsMustBeParsed(String parsableObjects) {
String[] parsedObjects = parsableObjects.split(",");
for (String parsedObject : parsedObjects){
loadObject(parsedObject, new LoadObjectCallback() {
#Override
public void onObjectLoaded(Object object) {
//Object Loaded
saveObject(object, new SaveObjectCallback() {
#Override
public void onObjectSaved() {
// Object saved
}
#Override
public void onError() {
// Object not saved
}
});
}
#Override
public void onError(Throwable throwable) {
// Object not Loaded
}
});
}
}
// => do something when all processing of parsed-objects are finished
// do something if all is ok
// do other thing if partially ok
Note : To manipulate my data, I use a repository with local and remote data sources. This piece of code is a part of repository.
Add a volatile integer which indicates the amount of running tasks. Increment when you start a task. Decrement in onObjectLoaded or in onObjectSaved. Then after every decrement check if the task counter is nul.
Similar approach to the comments, but using an AtomicInteger instead:
AtomicInteger countDownLatch = null;
#Override
public void onObjectsMustBeParsed(String parsableObjects) {
String[] parsedObjects = parsableObjects.split(",");
countDownLatch = new AtomicInteger(parsedObjects.length);
for (String parsedObject : parsedObjects){
loadObject(parsedObject, new LoadObjectCallback() {
#Override
public void onObjectLoaded(Object object) {
//Object Loaded
saveObject(object, new SaveObjectCallback() {
#Override
public void onObjectSaved() {
// Object saved
int value = countDownLatch.decrementAndGet();
if ( value == 0 ) {
// we are done
}
}
#Override
public void onError() {
// Object not saved
int value = countDownLatch.decrementAndGet();
if ( value == 0 ) {
// we are done
}
}
});
}
#Override
public void onError(Throwable throwable) {
// Object not Loaded
}
});
}
}
I am learning Observer pattern, I want my observable to keep track of a certain variable when it changes it's value and do some operations, I've done something like :
public class Test extends MyChildActivity {
private int VARIABLE_TO_OBSERVE = 0;
Observable<Integer> mObservable = Observable.just(VARIABLE_TO_OBSERVE);
protected void onCreate() {/*onCreate method*/
super();
setContentView();
method();
changeVariable();
}
public void changeVariable() {
VARIABLE_TO_OBSERVE = 1;
}
public void method() {
mObservable.map(value -> {
if (value == 1) doMethod2();
return String.valueOf(value);
}).subScribe(string -> System.out.println(string));
}
public void doMethod2() {/*Do additional operations*/}
}
But doMethod2() doesn't get called
Nothing is magic in the life : if you update a value, your Observable won't be notified. You have to do it by yourself. For example using a PublishSubject.
public class Test extends MyChildActivity {
private int VARIABLE_TO_OBSERVE = 0;
Subject<Integer> mObservable = PublishSubject.create();
protected void onCreate() {/*onCreate method*/
super();
setContentView();
method();
changeVariable();
}
public void changeVariable() {
VARIABLE_TO_OBSERVE = 1;
// notify the Observable that the value just change
mObservable.onNext(VARIABLE_TO_OBSERVE);
}
public void method() {
mObservable.map(value -> {
if (value == 1) doMethod2();
return String.valueOf(value);
}).subScribe(string -> System.out.println(string));
}
public void doMethod2() {/*Do additional operations*/}
}
If interested here a Kotlin version of Variable class, which lets subscribers to be updated after every variable change.
class Variable<T>(private val defaultValue: T) {
var value: T = defaultValue
set(value) {
field = value
observable.onNext(value)
}
val observable = BehaviorSubject.createDefault(value)
}
Usage:
val greeting = Variable("Hello!")
greeting.observable.subscribe { Log.i("RxKotlin", it) }
greeting.value = "Ciao!"
greeting.value = "Hola!"
This will print:
"Hello!"
"Ciao!"
"Hola!"
#dwursteisen Nothing is magic, no, but I think we can get it a little more magic than that... 😊
How about using an Rx BehaviourSubject in this way:
import rx.functions.Action1;
import rx.subjects.BehaviorSubject;
public class BehaviourSubjectExample {
public BehaviourSubjectExample() {
subject.skip(1).subscribe(new Action1<Integer>() {
#Override
public void call(Integer integer) {
System.out.println("The value changed to " + integer );
}
});
}
public final BehaviorSubject<Integer> subject = BehaviorSubject.create(0);
public int getValue() { return subject.getValue(); }
public void setValue(int value) { subject.onNext(value); }
}
Remove the .skip(1) if you want the observing code to see the initial value.
The variable backing remains with the BehaviourSubject and can be accessed through conventional Java Getter/Setter. This is a toy example of course: If your use case were really this simple there'd be no excuse for not just writing:
private int value = 0;
public int getValue() { return value; }
public void setValue(int value) {
this.value = value;
System.out.println("The value changed to " + value );
}
...but the use of BehaviourSubject lets you bridge changes to other Rx data-streams inside your class for composing more advanced behaviours.