How to provide two Integer values and emit one String - android

I am learning RxAndroid api, so I created an example where the input is two integers and the output should be a string containing these integers. for example,
for 1 and two the output should be "1,2" and so on.
in the below code is my attempts to achieve what I am planning to do, but I need guiding and help please.
code:
public class MainActivity extends AppCompatActivity {
private final static String TAG = MainActivity.class.getSimpleName();
private EditText mEditTextValue1 = null;
private EditText mEditTextValue2 = null;
private Button mButtonStartAsyncTask = null;
private rx.Observable<Integer> mAsyncObservable = null;
private TextView mTextViewProcessedValue = null;
Subscriber<String> mAsyncSubscriber = new Subscriber<String>() {
#Override
public void onCompleted() {
Log.w(TAG, "onCompleted(mAsyncSubscriber)");
}
#Override
public void onError(Throwable e) {
Log.w(TAG, "onError(mAsyncSubscriber)");
}
#Override
public void onNext(String next) {
Log.w(TAG, "onNext(mAsyncSubscriber)");
mTextViewProcessedValue.setText();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
mEditTextValue1 = (EditText) findViewById(R.id.editTextValue1);
mEditTextValue2 = (EditText) findViewById(R.id.editTextValue2);
mButtonStartAsyncTask = (Button) findViewById(R.id.buttonStartAsyncTask);
mButtonStartAsyncTask.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Integer value1 = Integer.valueOf(mEditTextValue1.getText().toString());
Integer value2 = Integer.valueOf(mEditTextValue2.getText().toString());
mAsyncObservable = rx.Observable.just(value1, value2)
.delay(3, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.doOnNext(items-> {
mTextViewProcessedValue = (TextView) findViewById(R.id.textViewProcessedValue);
return value1 + ", " + value2;
})
.doOnCompleted(new Action0() {
#Override
public void call() {
Log.w(TAG, "doOnCompleted");
}
})
//.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe((Action1<? super Integer>) mAsyncSubscriber);
}
});
}
}

The operator you want to use really depends on how many numbers you will have, how many products you want, and what you want to do with the final answer. For this example, we'll use scan(...)
apply a function to each item emitted by an Observable, sequentially, and emit each successive value
Observable.just(value1, value2)
.delay(3, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.scan("", (string, integer) -> string + "," + integer)
The above will emit once: "{value1},{value2}".
If you add a third value, it will emit twice : "{value1},{value2}" and "{value1},{value2},{value3}"

i'm new with RxJava too ... this might be what you want
io.reactivex.Observable.range(1, 100).subscribe(new DisposableObserver<Integer>() {
List<Integer> list = new ArrayList<>(2);
#Override
public void onNext(Integer integer) {
list.add(integer);
if (list.size() % 2 == 0) {
Log.i(TAG, "onNext: couple int :" + list.get(0) + " ," + list.get(1));
list.clear();
}
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
if you want to emit two values together you may emit a array or list or Pojo.
using zip operator example:
io.reactivex.Observable<Integer> s1 = io.reactivex.Observable.range(1, 100);
io.reactivex.Observable<Integer> s2 = io.reactivex.Observable.range(-100, 100);
io.reactivex.Observable.zip(s1, s2, new BiFunction<Integer, Integer, String >() {
#Override
public String apply(Integer i1, Integer i2) throws Exception {
return i1 + " ," + i2;
}})
.subscribe(System.out::println);

Looking on code what you trying achieve is reading from 2 fields on button click and emit them to observable, is it correct?
Please check this project to replace listener with rxjava bindings:
https://github.com/JakeWharton/RxBinding. Then code would be something like this:
RxView.clicks(button)
.map(event -> {
Integer value1 = Integer.valueOf(mEditTextValue1.getText().toString());
Integer value2 = Integer.valueOf(mEditTextValue2.getText().toString());
return value1 + "," + value2;
})
.subscribe(combinedIntegers ->
mTextViewProcessedValue.setText(combinedIntegers));

Related

workaround for async call to read from Firebase

I'm new to Android and Firebase environment but I'm working on it !
I'm working on an Android app and I need to read some values related to a child within a Firebase database. After this initial read, I need to modify / update these values and write them to the same child.
public class MainActivity extends Activity {
public static class Shoe extends JSONObject {
private String name;
private int size;
Shoe(){
// Default constructor required for calls to
// DataSnapshot.getValue(Shoe.class)
}
Shoe( String nm, int sz) { this.name = nm; this.size = sz; }
public int getSize() { return this.size; }
public void setSize(int sz) { this.size = sz; }
public String getName() { return this.name;}
public void setName(String nm) {this.name = nm; }
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
// Write a message to the database
FirebaseDatabase database = FirebaseDatabase.getInstance();
database.setPersistenceEnabled(true);
DatabaseReference myRefTarget = database.getReference("target");
Shoe obj1 = new Shoe("item ID 1", 99);
Shoe obj2 = new Shoe("item ID 2", 1000);
final Shoe obj_old = new Shoe();
Shoe obj_new = new Shoe();
DatabaseReference myRefDeviceA = myRefTarget.child("deviceA").getRef();
myRefDeviceA.keepSynced(true);
myRefDeviceA.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
obj_old.setName( dataSnapshot.getValue(Shoe.class).getName());
obj_old.setSize( dataSnapshot.getValue(Shoe.class).getSize());
Log.d(TAG_CLOUD, "from onDataChange: deviceA = " + obj_old.getName() + ", " + obj_old.getSize());
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
// HERE
Log.d(TAG_CLOUD, "Name = " + obj_old.getName() + ", Size = " + obj_old.getSize());
}
the issue I got is that the read operation is asynchronously done..
D/FROM CLOUD: Name = null, Size = 0
D/FROM CLOUD: from onDataChange: deviceA = item ID 1, 99
how can adapt / modify the source code in such way that first "read" to give me values different than null and '0' ? "HERE" line
eg.
Name = item ID 1 Size = 99
Thank you.
You don't suppose to perform networking operations on the UI thread.
If you want to display the data in the activity, you should show a loading dialog in the onCreate method, and then after fetching the data close the dialog and update the activity view

How to manually call observer.onNext in rxJava

I am relatively new to RxJava/RxAndroid. I have been using AsyncTask to do my long running tasks before now.
I have converted most of my AsyncTask to RxJava but this one.
The particular problem I am having is calling something like AsyncTask's publishProgress(params); in
the background thread. I need to do this to update the progress of a ProgressBar.
First this is the code in AsyncTask
private static class AddBooksToDatabase extends AsyncTask<String, String, String> {
//dependencies removed
AddBooksToDatabase(AddBooksDbParams params) {
//Removed assignment codes
}
#Override
protected String doInBackground(String... strings) {
//Initializing custom SQLiteOpenHelper and SQLite database
File mFile = new File(mFolderPath);
int booksSize = getFilesInFolder(mFile).size();
String[] sizeList = {String.valueOf(booksSize)};
//The first publishProgress is used to set the max of the progressbar
publishProgress(sizeList);
for (int i = 0; i < booksSize; i++) {
//publishProgress with current item, current file
publishProgress(String.valueOf(i), getFilesInFolder(mFile).get(i).getName());
//Inserting current items in database. Code removed
}
return null;
}
#Override
protected void onPreExecute() {
//Show ProgressBar
}
#Override
protected void onPostExecute(String s) {
//Hide ProgressBar
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
if (values.length == 1) {
//The first call to publishProgress
mProgressBar.setMax(Integer.parseInt(values[0]));
} else {
//Subsequent calls to publish progress
Log.i(TAG, "Current item is " + values[0] + " and current file is " + values[1]);
infoText.setText(values[1]);
mProgressBar.setProgress(Integer.parseInt(values[0]), true);
}
}
#Override
protected void onCancelled() {
cancel(true);
}
}
Code Using RxJava
final Observable<String[]> addBooksObserver = Observable.create(new Observable.OnSubscribe<String[]>() {
#Override
public void call(Subscriber<? super String[]> subscriber) {
subscriber.onNext(setAddSubscription());
subscriber.onCompleted();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
private String[] setAddSubscription() {
S//Initializing custom SQLiteOpenHelper and SQLite database
File mFile = new File(mFolderPath);
int booksSize = getFilesInFolder(mFile).size();
String[] sizeList = {String.valueOf(booksSize)};
//The first publishProgress is used to set the max of the progressbar
addBooksObserver.doOnNext(addReturnParams(String.valueOf(sizeList.length), null, null));
for (int i = 0; i < booksSize; i++) {
EpubReader reader = new EpubReader();
//publishProgress with current item, current file*
addBooksObserver.doOnNext(addReturnParams(String.valueOf(sizeList.length),
String.valueOf(i), getFilesInFolder(mFile).get(i).getName()));
//Inserting current item in database. Code removed
}
return null;
}
private String[] addReturnParams(String totalItems, String currentItem, String currentFile) {
return new String[]{totalItems, currentItem, currentFile};
}
The problem is that lines addBooksObserver.doOnNext(addReturnParams( are displaying this error
doOnNext (rx.functions.Action1) cannot be applied to (java.lang.String[])
I don't know have any idea how to fix this because I thought that since setAddSubscription() and addReturnParams(String totalItems, String currentItem, String currentFile) are returning String array then this shouldn't be a problem. Please can you help me out?
you just have to pass the values to the onNext method of your subscriber, not the doOnNext method of your observable!
you also have to subscribe to the service. try something like this for your obserable:
Observable.create(new Observable.OnSubscribe<String[]>() {
#Override
public void call(Subscriber<? super String[]> subscriber) {
setAddSubscription(subscriber);
subscriber.onCompleted();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String[]>() {
#Override
public void onCompleted() {
// handle 'oparation is done'
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String[] values) {
if (values.length == 1) {
//The first call to publishProgress
mProgressBar.setMax(Integer.parseInt(values[0]));
} else {
//Subsequent calls to publish progress
Log.i(TAG, "Current item is " + values[0] + " and current file is " + values[1]);
infoText.setText(values[1]);
mProgressBar.setProgress(Integer.parseInt(values[0]), true);
}
}
});
you also need to modify your private methods a little bit:
private void setAddSubscription(Subscriber<? super String[]> subscriber) {
//Initializing custom SQLiteOpenHelper and SQLite database
File mFile = new File(mFolderPath);
int booksSize = getFilesInFolder(mFile).size();
String[] sizeList = {String.valueOf(booksSize)};
//The first publishProgress is used to set the max of the progressbar
subscriber.onNext(addReturnParams(String.valueOf(sizeList.length), null, null));
for (int i = 0; i < booksSize; i++) {
EpubReader reader = new EpubReader();
//publishProgress with current item, current file*
subscriber.onNext(addReturnParams(String.valueOf(sizeList.length),
String.valueOf(i), getFilesInFolder(mFile).get(i).getName()));
//Inserting current item in database. Code removed
}
}
private String[] addReturnParams(String totalItems, String currentItem, String currentFile) {
return new String[]{totalItems, currentItem, currentFile};
}
You can use Subject to call onNext() manually like this:
Subject<Event> event = Subject.create();
Now call the onNext() for sending event like:
event.onNext("event");
Finally you can return Observable by using this code:
event.toFlowable(BackpressureStrategy.LATEST)
.toObservable();
Your Observer should be like Observable.create(new Observable.OnSubscribe<String>() & in your call method you should loop through the StringArray & pass it to onNext for example:
#Override
public void call(Subscriber<? super String> subscriber) {
for(String val : setAddSubscription()) {
subscriber.onNext(val);
}
subscriber.onCompleted();
}
now onNext shall return you individual items & onCompleted will be called upon the loop is finished.
Edit
myObserver.subscribe(new Subscriber<String>() {
#Override
public void onCompleted() {
// handle completion.
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String value) {
// do whatever with each value passed to onNext
}
});
Observable.create(emitter -> {
for (int i = 0; i < 10; i++) {
int[] ii = {i, i * 2};
emitter.onNext(ii);
}
emitter.onComplete();
}).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(o -> {
// update progress
int[] i = (int[]) o;
Toast.makeText(SearchActivity.this, "oftad " + i[0] + " - " + i[1], Toast.LENGTH_SHORT).show();
}, t -> {
// on error
Toast.makeText(SearchActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}, () -> {
// progress tamom shod
Toast.makeText(SearchActivity.this, "completed", Toast.LENGTH_SHORT).show();
});

Realm change in change listener

I try to replicate database trigger function with Realm with Rx. Once I get RealmList emitted, I do some stuff with it and save. Sadly, this results into Realm's change listener to be executed again, emitting the list over and over again.
Dummy example:
realm.where(MyRealmObject.class)
.equalTo("state", "new")
.findAll()
.asObservable()
.flatMap(new Func1<RealmResults<MyRealmObject>, Observable<MyRealmObject>>() {
#Override
public Observable<MyRealmObject> call(RealmResults<MyRealmObject> list) {
return Observable.from(list);
}
})
.subscribe(new Action1<MyRealmObject>() {
#Override
public void call(final MyRealmObject object) {
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
// do any realm change
}
});
}
});
Once I commit the transaction in subscriber, new RealmList is emited from observable. I know why this happens, I just don't see any way how to workaround this.
This takes us to my question. Is there any way how to replicate trigger functionality with realm where I will do any realm change?
Workaround can be built with helper stream determing whether next item from db should be consumed. Every data store into db should be accompanied with write into helper stream. Running test below yields:
upstream: IgnoreAction{action='start', ignoreNext=false}
result: 1
result: 2
result: 3
upstream: IgnoreAction{action='1', ignoreNext=true}
upstream: IgnoreAction{action='2', ignoreNext=true}
upstream: IgnoreAction{action='3', ignoreNext=true}
So, first data ("start") is consumed, and writes triggered in onNext are ignored.
#Test
public void rxIgnore() throws Exception {
MockDb mockDb = new MockDb();
BehaviorSubject<Boolean> ignoreNextStream = BehaviorSubject.create(false);
Observable<String> dataStream = mockDb.dataSource();
dataStream.zipWith(ignoreNextStream, Data::new)
.doOnNext(action -> System.out.println("upstream: " + action))
.filter(Data::isTakeNext)
.flatMap(__ -> Observable.just(1, 2, 3))
.subscribe(new Observer<Integer>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(Integer val) {
System.out.println("result: " + val);
ignoreNextStream.onNext(true);
mockDb.data(String.valueOf(val));
}
});
mockDb.data("start");
Observable.empty().delay(1, TimeUnit.MINUTES).toBlocking().subscribe();
}
private static class Data {
private final String action;
private final boolean ignoreNext;
public Data(String action, boolean ignoreNext) {
this.action = action;
this.ignoreNext = ignoreNext;
}
public boolean isTakeNext() {
return !ignoreNext;
}
#Override
public String toString() {
return "IgnoreAction{" +
"action='" + action + '\'' +
", ignoreNext=" + ignoreNext +
'}';
}
}
private static class MockDb {
private final Subject<String, String> subj = PublishSubject.<String>create()
.toSerialized();
public void data(String action) {
subj.onNext(action);
}
Observable<String> dataSource() {
return subj;
}
}

RxJava/Android: Construct an Observable as the combination of original item and transformed item

Here is the example:
Student[] students = ...;
Subscriber<Course> subscriber = new Subscriber<Course>() {
#Override
public void onNext(Course course) {
Log.d(tag, course.getName());
}
...
};
Observable.from(students)
.flatMap(new Func1<Student, Observable<Course>>() {
#Override
public Observable<Course> call(Student student) {
return Observable.from(student.getCourses());
}
})
.subscribe(subscriber);
It's easy to observe courses, but what if I want to print out the pair of student-course? Is that necessary to change Observable<Course> to Observable<Pair<Student, Course>>? This method could be very tedious, because we could have multiple operators during transforming, but we don't want to keep the Pairs all the way transforming the observable.
Is that any other good way we can refer to the original item based on the transformed one?
Depending on your goals and implementation you can use an overloaded variant of flatMap like this:
Observable.from(students)
.flatMap(new Func1<Student, Observable<Course>>() {
#Override
public Observable<Course> call(Student student) {
return Observable.from(student.getCourses());
}
}, new Func2<Student, Course, Void>() {
#Override
public Void call(Student student, Course course) {
Log.d(tag, student + "->" + course.getName());
return null;
}
})
.subscribe();
students.doOnNext(new Action1<String>() {
#Override
public void call(String student) {
ArrayList<String> studentCourses = courses.get(student);
for (int i=0 ; i<studentCourses.size() ; i++) {
System.out.println(student + " -> " + studentCourses.get(i) + " " + test);
}
}
})
.subscribe(new Subscriber<String>() {
#Override
public void onNext(String s) { /*System.out.println(s); */}
#Override
public void onCompleted() { }
#Override public void onError(Throwable e) { }
});

How to send composing / is typing (Chat states) event in Multiuser chat / Group chat & One to One chat in xmpp android?

I want send composing event in Group (Multiuser) chat in xmpp, I am using asmack library, I have done same functionality with One to One chat.
I am using below code:
mMessageEventManager = new MessageEventManager(XMPPConnectApplication.getInstance().getXmppConnection());
mMessageEventManager.addMessageEventNotificationListener(new MessageEventNotificationListener() {
#Override
public void offlineNotification(String arg0, String arg1) {
}
#Override
public void displayedNotification(String arg0, String arg1) {
}
#Override
public void deliveredNotification(String arg0, String arg1) {
}
#Override
public void composingNotification(String from, String to) {
Log.e("Receiver-composingNotification",from + " is started typing......"+to);
}
#Override
public void cancelledNotification(String from, String to) {
Log.e("Receiver-cancelledNotification",from + " is stopped typing......"+to);
}
});
Please let me know if you have any idea for the same.
Any help will be appreciated.
Yes, I have idea about it and I have done just before 1 week.
I have used MessageEventManager to manage Chat States.
private MessageEventManager mMessageEventManager;
Add this method for Chat State Receiving Listener:
private void chatStateRecognizer(){
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
mMessageEventManager = new MessageEventManager(mXmppConnection);
mMessageEventManager.addMessageEventNotificationListener(new MessageEventNotificationListener() {
#Override
public void offlineNotification(String arg0, String arg1) {
}
#Override
public void displayedNotification(String arg0, String arg1) {
}
#Override
public void deliveredNotification(String from, String arg1) {
}
#Override
public void composingNotification(String from, String to) {
Log.i("Receiver:Compose state",from + " is started typing......"+to);
}
#Override
public void cancelledNotification(String from, String to) {
Log.i("Receiver:Stop state",from + " is stopped typing......"+to);
}
});
}
});
thread.start();
}
Create one Model class name with GroupInfoModel.java:
public class GroupInfoModel implements Comparable<GroupInfoModel>, Serializable{
private static final long serialVersionUID = 1L;
private String memberId = "", memberName = "";
private boolean isAdmin;
public String getMemberId() {
return memberId;
}
public void setMemberId(String memberId) {
this.memberId = memberId;
}
public String getMemberName() {
return memberName;
}
public void setMemberName(String memberName) {
this.memberName = memberName;
}
public boolean isAdmin() {
return isAdmin;
}
public void setAdmin(boolean isAdmin) {
this.isAdmin = isAdmin;
}
#Override
public int compareTo(GroupInfoModel another) {
return getMemberName().compareTo(another.getMemberName());
}
}
Now take ArrayList of GroupInfoModel.java class:
private ArrayList<GroupInfoModel> groupDetailsList = new ArrayList<GroupInfoModel>();
private boolean isComposingStarted;
on onCreate() of Activity / Fragment:
groupDetailsList.clear();
ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(mXmppConnection);
DiscoverItems items = discoManager.discoverItems(mRoomId);
for (Iterator<Item> it = items.getItems(); it.hasNext();) {
DiscoverItems.Item item = (DiscoverItems.Item) it.next();
String occupant = item.getEntityID();
occupant = occupant.split("/")[1];
GroupInfoModel groupInfoModel = new GroupInfoModel();
groupInfoModel.setAdmin(false);
groupInfoModel.setMemberId(occupant+"#"+mServiceNameHere);
groupInfoModel.setMemberName(occupant);
groupDetailsList.add(groupInfoModel);
}
Now add TextWatcher on your EditText of Compose Message (Chat view) screen:
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(s.toString().length()==1&&!isComposingStarted){
isComposingStarted = true;
if(chatType.equals("OneToOneChat")){
mMessageEventManager.sendComposingNotification(myJabberId, friendJabberId);
}else if(chatType.equals("GroupChat")){
for (int i = 0; i < groupDetailsList.size(); i++) {
if(!groupDetailsList.get(i).getMemberId().contains(myJabberId)){
mMessageEventManager.sendComposingNotification(groupDetailsList.get(i).getMemberId(), roomId);
}
}
}
}else if(s.toString().length()==0){
isComposingStarted = false;
if(chatType.equals("OneToOneChat")){
mMessageEventManager.sendCancelledNotification(myJabberId, friendJabberId);
}else if(chatType.equals("GroupChat")){
for (int i = 0; i < groupDetailsList.size(); i++) {
if(!groupDetailsList.get(i).getMemberId().contains(myJabberId)){
mMessageEventManager.sendCancelledNotification(groupDetailsList.get(i).getMemberId(), roomId);
}
}
}
}
}
I strongly recommended that use above code in Application class, you can modify methods as your requirements.
Done.
// send multi user chat typing status
public static void sendMUCTypingStatus(ChatState state)
{
// check if you are connected to group
if(multiUserChat != null)
{
try{
// create packet
Message statusPacket = new Message();
// set body to null
statusPacket.setBody(null);
// set packet type to group chat
statusPacket.setType(Message.Type.groupchat);
// set subject to null
statusPacket.setSubject(null);
// set to the group name
statusPacket.setTo(multiUserChat.getRoom());
// set from my current jis example : me#domain.com
statusPacket.setFrom(new MyPrefrence(XmppBase.context).getUsername());
// get the chat state extension and pass our state
ChatStateExtension extension = new ChatStateExtension(state);
// add the extention to our packet
statusPacket.addExtension(extension);
// get the connection and send the packet
Utils.getConnection().sendStanza(statusPacket);
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
}
}
Usage :
sendMucTypingStatus(ChatState.composing);
watch this : Quick overview of using
With RxJava and Jake Wharton's RxBinding, it's quite simple to do:
RxTextView.afterTextChangeEvents(editText)
.observeOn(Schedulers.io())
.skip(1)
.map({ input ->
// FIRE ChatState.composing EVENT HERE
input // just returning the argument here
})
.debounce(2, TimeUnit.SECONDS)
.observeOn(Schedulers.io())
.subscribe {
// FIRE ChatState.active EVENT HERE
}
Remember that we will have to write code to catch these events via smack stanzaListener and display it on the UI accordingly!
Code is written in Kotlin, but it is fairly straight forward.

Categories

Resources