on child added method work multiple times - java

I am making a challenge between two users in my app using firebase database. in the challenge I store player1Uid and player2Uid(player1 is the player who started the challenge and player two is the player who will accept or refuse the challenge). I want to make a history of challenges so If the challenge is completed I store it in a list called"completedChallengesList" and if the challenge isn't completed yet I store it in a list called uncompleted challenge list.the code some times work fine but in other times it bring the data more than one time to the list.
this is my code that brings data :
public void startAsynkTask() {
//TODO : search for a solution to this error
AsyncTask asyncTask = new AsyncTask() {
#Override
protected Boolean doInBackground(Object[] objects) {
try {
Socket sock = new Socket();
sock.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
sock.close();
return true;
} catch (IOException e) {
return false;
}
}
#Override
protected void onPostExecute(Object o) {
if ((boolean) o) {
clearLists();
ChildEventListener generalChallengesListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String challengeState = dataSnapshot.child("state").getValue().toString();
Log.v("Logging2", "onChildAdded");
if (challengeState.equals(uncompletedChallengeText)) {
getChallengeData(dataSnapshot, "onChildAdded");
view.onDataFound();
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
//TODO : note that the only changing handled is when challenge moves from uncompleted to completed state
getChallengeData(dataSnapshot, "onChildChanged");
for (int i = 0; i < uncompletedChallengesList.size(); i++) {
if (uncompletedChallengesList.get(i).getId().equals(dataSnapshot.getKey())) {
uncompletedChallengesList.remove(i);
view.notifyAdapters(completedChallengesList.size(), uncompletedChallengesList.size());
break;
}
}
checkListsSizeAndAdjustViews();
view.hideProgressBar();
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
startAsynkTask();
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
//Toast.makeText(getActivity(), "فشل تحميل البيانات من فضلك تأكد من الاتصال بالانترنت", Toast.LENGTH_SHORT).show();
view.hideProgressBar();
Log.v("Logging", "error loading data : " + databaseError);
}
};
//this code gives data where current user is player 1
player1Listener = challengesReference.orderByChild("player1Uid").equalTo(currentUserUid).addChildEventListener(generalChallengesListener);
//this code gives data where current user is player 2
player2Listener = challengesReference.orderByChild("player2Uid").equalTo(currentUserUid).addChildEventListener(generalChallengesListener);
challengesReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
onInitialDataLoaded();
Log.v("ChallengesFragPresenter", "completed list size :" + completedChallengesList + " , uncompleted list size : " + uncompletedChallengesList);
challengesReference.removeEventListener(this);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
} else {
view.onNoInternetConnection();
}
}
};
asyncTask.execute();
}
public String getChallengeData(DataSnapshot dataSnapshot, String tag) {
Log.v("ChallengesFragPresenter", "get challenge data called");
Log.v("ChallengesFragPresenter", "completedChallengesList : " + completedChallengesList.size()
+ ", uncompletedChallengesList " + uncompletedChallengesList.size());
view.startCompletedChallengesAdapter(completedChallengesList);
view.startUnCompletedChallengesAdapter(uncompletedChallengesList);
GenericTypeIndicator<List<Question>> t = new GenericTypeIndicator<List<Question>>() {
};
challenge = new Challenge();
String challengeDate = dataSnapshot.child("date").getValue().toString();
String challengeSubject = dataSnapshot.child("subject").getValue().toString();
String challengeState = dataSnapshot.child("state").getValue().toString();
String challengeId = dataSnapshot.getKey();
ArrayList challengeQuestionsList = (ArrayList) dataSnapshot.child("questionsList").getValue(t);
long player1Score = (long) dataSnapshot.child("player1score").getValue();
long player2Score = (long) dataSnapshot.child("player2score").getValue();
String player1Name = dataSnapshot.child("player1Name").getValue().toString();
String player1Image = dataSnapshot.child("player1Image").getValue().toString();
String player1Uid = dataSnapshot.child("player1Uid").getValue().toString();
String player2Name = dataSnapshot.child("player2Name").getValue().toString();
String player2Image = dataSnapshot.child("player2Image").getValue().toString();
String player2Uid = dataSnapshot.child("player2Uid").getValue().toString();
String challengerName, challengerImage;
if (player1Uid.equals(currentUserUid)) {
currentPlayer = 1;
challengerName = player2Name;
challengerImage = player2Image;
challenge.setSecondChallengerUid(player2Uid);//second means that it is not the player who starts the challenge
if (tag.equals("onChildAdded")) {
player1childrenCount++;
}
} else {
currentPlayer = 2;
challengerName = player1Name;
challengerImage = player1Image;
challenge.setSecondChallengerUid(player1Uid);//second means that it is not the player who starts the challenge
if (tag.equals("onChildAdded")) {
player2childrenCount++;
}
}
challenge.setCurrentPlayer(currentPlayer);
challenge.setChallengerName(challengerName);
challenge.setDate(challengeDate);
challenge.setImage(challengerImage);
challenge.setSubject(challengeSubject);
challenge.setState(challengeState);
challenge.setId(challengeId);
challenge.setQuestionsList(challengeQuestionsList);
String score;
if (currentPlayer == 1) {
score = player2Score + " : " + player1Score;
} else {
score = player1Score + " : " + player2Score;
}
challenge.setScore(score);
if (challenge.getState().equals("اكتمل")) {
view.showCompletedChallengesTv();
if(!completedChallengesList.contains(challenge)) {
completedChallengesList.add(0, challenge);
}
view.notifyAdapters(completedChallengesList.size(), uncompletedChallengesList.size());
} else if (challenge.getState().equals(refusedChallengeText)) {
view.showCompletedChallengesTv();
if(!completedChallengesList.contains(challenge)) {
completedChallengesList.add(0, challenge);
}
view.notifyAdapters(completedChallengesList.size(), uncompletedChallengesList.size());
} else if (challenge.getState().equals(uncompletedChallengeText)) {
view.showUncompletedChallengesTv();
if(!uncompletedChallengesList.contains(challenge)) {
uncompletedChallengesList.add(0, challenge);
}
view.notifyAdapters(completedChallengesList.size(), uncompletedChallengesList.size());
}
return player1Uid;
}
after long time of debugging I found that the method getChallengeData() is called more than one time when a new child added . I tried a lot to know why but I couldn't.
NOTE : I am using asynk task to check if there is internet connection or no before start loading data.

I think that your problem is, you are not removing your listner "generalChallengesListener", so multiple refereces will be created, so the onChildAdded will be excuted multiple times as the number of listners you created. So add a reference to your lister and know when you should remove it.
Hope it will helps you =)

Related

OutOfMemory Exception in Android-Java. Allocation failed due to fragmentation

So I developed an Android application which acts as a server for my Android game(two separated apps), both applications were written in Java.
Previously I got messages on the Log like: "Skipped 2000 frames. The main thread could be overworking".
This is the code of my app, it's made of only the MainActivity:
I tried to introduce concurrent Threads in order to make the main thread lighter. Now the skipped n frames message isn't showed anymore but messages such like the followings are shown anyways.
"Alloc concurrent copying GC freed", "Starting a blocking GC alloc", "Waiting for a blocking GC alloc", "WaitForGcToComplete blocked alloc on HeapTrim" and all of this ends with
Throwing OutOfMemoryError "Failed to allocate a 32 byte allocation with 15604408 free bytes and 14MB until OOM, target footprint 268435456, growth limit 268435456; failed due to fragmentation (largest possible contiguous allocation 0 bytes)" (VmSize 5539048 kB).
I tried to deallocate some objects (lines of code which contains "x = null") but it didn't solve. Furthermore I checked with a log if there is some sort of endless loop but it doesn't seem to be the case.
public class MainActivity extends AppCompatActivity {
private static ActivityMainBinding binding;
private WSocServer server;
private int port = 8080;
private boolean isOnline = false;
private static ArrayList<String> logs = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
binding.openConnection.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(!isOnline) {
isOnline = true;
server = new WSocServer(port);
server.start();
Toast toast = Toast.makeText(view.getContext(),"Server is on", Toast.LENGTH_LONG);
toast.show();
Log.i("WebSocket Server", "Started on port " + server.getPort());
}
else{
Snackbar snack = Snackbar.make(view ,"We are already online!", Snackbar.LENGTH_INDEFINITE);
snack.setAction("Got it", new View.OnClickListener() {
#Override
public void onClick(View view) {
snack.dismiss();
}
});
snack.show();
}
}
});
binding.closeConnection.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(isOnline) {
isOnline = false;
logs.clear();
Toast toast = Toast.makeText(view.getContext(),"Server is off", Toast.LENGTH_LONG);
toast.show();
try {
server.stop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else{
Snackbar snack = Snackbar.make(view ,"We are already offline!", Snackbar.LENGTH_INDEFINITE);
snack.setAction("Got it", new View.OnClickListener() {
#Override
public void onClick(View view) {
snack.dismiss();
}
});
snack.show();
}
}
});
}
private static void addOnView(){
ConstraintLayout cl = binding.logsView;
Handler h = new Handler(Looper.getMainLooper());
for(int i = 0; i < logs.size(); i++){
TextView tv = new TextView(binding.getRoot().getContext());
tv.setTextSize(16);
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
tv.setPadding(40,180*(i+1),40,0);
tv.setText(logs.get(i));
Runnable r = new Runnable() {
#Override
public void run() {
cl.addView(tv);
}
};
h.post(r);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
try {
server.stop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static class WSocServer extends WebSocketServer {
private List<String> matchUsers;
private Integer timerSeconds;
private UUID matchId;
//a key represents a match to which an array of extracted numbers is associated
private Hashtable<String,Integer[]> matchExtractedNumbers = new Hashtable<>();
private Hashtable<String, Collection<WebSocket>> matchClients = new Hashtable<>();
private Hashtable<String,Hashtable<String,ArrayList<String>>> users_scorePerMatch = new Hashtable<>();
private Hashtable<String,WebSocket> clientConnection = new Hashtable<>();
private void initTimer(){
timerSeconds = 60;
Timer timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
if(timerSeconds > 0) timerSeconds--;
else {
timerSeconds = 60; timer.cancel(); timer.purge();
}
}
};
timer.schedule(task,0L,1000L);
}
private String UsersListToString(List list){
return list.toString().replace("[","").replace("]","");
}
private Integer[] generateExtractedNumbers(){
Integer[] callerBoard = new Integer[90];
List<Integer> boardPool = new ArrayList<>();
boardPool.addAll(Arrays.asList(IntStream.rangeClosed(1,90).boxed().toArray(Integer[]::new)));
for(int i = 0; i < 90; i++){
int rng = ThreadLocalRandom.current().nextInt(0,90-i);
callerBoard[i] = boardPool.remove(rng);
}
return callerBoard;
}
private void initMatch(){
matchId = UUID.randomUUID();
Integer[] matchBoard = generateExtractedNumbers();
matchExtractedNumbers.put(matchId.toString(),matchBoard);
matchClients.put(matchId.toString(),clientConnection.values());
Hashtable<String,ArrayList<String>> matchData = new Hashtable<>();
for(String user: matchUsers) matchData.put(user,new ArrayList<>());
users_scorePerMatch.put(matchId.toString(), matchData);
}
private Integer getExtractedNumber(String match, Integer turn){
if(turn >= 90) return -1;
Integer[] thisMatchExtractedNumbers = matchExtractedNumbers.get(match);
Integer returning = thisMatchExtractedNumbers[turn];
thisMatchExtractedNumbers = null;
return returning;
}
public WSocServer(int port){
super(new InetSocketAddress(port));
}
public WSocServer(InetSocketAddress address) {
super(address);
}
#Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
Log.i("WebSocket(open)", conn.getRemoteSocketAddress().getAddress().getHostAddress() + " entered the room!");
logs.add(conn.getRemoteSocketAddress().getAddress().getHostAddress() + " entered the room!");
matchUsers = new ArrayList<>();
matchUsers.addAll(Arrays.asList("user1","user2","user3","user4","user5"));
}
});
thread.start();
}
#Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
Log.i("WebSocket(close)", conn + " has left the room! Reason: " + reason);
logs.add(conn + " has left the room!");
}
});
thread.start();
}
#Override
public void onMessage(WebSocket conn, String message) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
logs.add(message + " from " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
Log.i("WebSocket(message)", conn + ": " + message);
MainActivity.addOnView();
if(message.startsWith("username")){
if(matchUsers.size() < 6){
String user = message.replace("username;","");
if(!matchUsers.contains(user)) {
matchUsers.add(user);
clientConnection.put(user,conn);
}
String sending = "matchUsers;" + UsersListToString(matchUsers);
conn.send(sending);
}
else conn.send("errorUsername");
}
else if(message.equals("timerStart")){
initTimer();
if(matchUsers.size() < 6){
String sending = "timeStarter;" + timerSeconds.toString();
conn.send(sending);
}
else conn.send("errorTimer");
}
else if(message.equals("getMatchId")){
if(!matchUsers.isEmpty()){
initMatch();
matchUsers.clear();
}
String sending = "matchId;" + matchId.toString();
conn.send(sending);
}
else if(message.startsWith("inGame")){
String[] fields = message.split(";");
String matchId = fields[1].split("=")[1];
int turn = Integer.parseInt(fields[2].split("=")[1]);
Integer extraction = getExtractedNumber(matchId,turn);
fields = null;
conn.send("extracted=" + extraction.toString());
}
else if(message.startsWith("score")){
String matchId = message.split(";")[1].split("=")[1];
String score = message.split(";")[0].split("=")[1];
WebSocket[] clients = matchClients.get(matchId).toArray(new WebSocket[0]);
String user = "";
Enumeration<String> keys = clientConnection.keys();
String key = keys.nextElement();
while(!key.isEmpty()){
if(clientConnection.get(key) == conn) {
user = key;
break;
}
key = keys.nextElement();
}
keys = null;
Hashtable<String,ArrayList<String>> tmp = users_scorePerMatch.get(matchId);
ArrayList<String> tmp_list = tmp.get(user);
tmp_list.add(score);
tmp.replace(user,tmp_list);
users_scorePerMatch.replace(matchId,tmp);
for(int i = 0; i < clients.length; i++){
clients[i].send("statement;" + user + " got " + score + " with");
}
clients = null;
}
else if(message.startsWith("endMatchData")){
String matchId = message.split(";")[1].split("=")[1];
Hashtable<String,ArrayList<String>> users_ofMatch = users_scorePerMatch.get(matchId);
ArrayList<String> users = new ArrayList<>();
Enumeration<String> e = users_ofMatch.keys();
while(e.hasMoreElements()){
Log.e("endmatchdata","a");
users.add(e.nextElement());
}
e = null;
String sending = "matchEndData;";
for(String user: users) sending += user + "=" + UsersListToString(users_ofMatch.get(user)) + ":";
users_ofMatch = null;
conn.send(sending);
}
else if(message.startsWith("totalEnd")){
String matchId = message.split(";")[1].split("=")[1];
if(matchClients.get(matchId)!=null) {
WebSocket[] clients = matchClients.get(matchId).toArray(new WebSocket[0]);
for (WebSocket client : clients) client.close();
Enumeration<String> e = clientConnection.keys();
boolean exit = false;
while (e.hasMoreElements() && !exit) {
Log.e("totalend", "while");
for (WebSocket client : clients) {
Log.e("totalend", "for");
String tmp = e.nextElement();
if (clientConnection.get(tmp) == client) {
clientConnection.remove(tmp);
exit = true;
break;
}
}
}
e = null; clients = null;
matchClients.remove(matchId);
users_scorePerMatch.remove(matchId);
matchExtractedNumbers.remove(matchId);
}
}
}
});
thread.start();
}
#Override
public void onMessage(WebSocket conn, ByteBuffer message) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
Log.i("WebSocket(message)", conn + ": " + message );
}
});
thread.start();
}
public static void main(String[] args){
}
#Override
public void onError(WebSocket conn, Exception ex) {
ex.printStackTrace();
}
#Override
public void onStart() {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
Log.i("WebSocket", "Server started!");
}
});
thread.start();
}
}
}
EDIT: The thing seems to be happening at the end of the match(i.e in the message.startsWith("totalEnd") or message.startsWith("endmatchdata") if cases in the onMessage method
EDIT 2: I found out that the addOnView function was badly written.
I changed it into
private static void addOnView(){
ConstraintLayout cl = binding.logsView;
Handler h = new Handler(Looper.getMainLooper());
final TextView tv = new TextView(binding.getRoot().getContext());
tv.setTextSize(16);
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
tv.setPadding(40,180*(logs.size()+1),40,0);
tv.setText(logs.get(logs.size()-1));
Runnable r = new Runnable() {
#Override
public void run() {
cl.addView(tv);
}
};
h.post(r);
h = null;
r = null;
}
And it solved.

The use of threads and async-tasks couldn't prevent ANR error

I'm having a huge problem for days. In fact, in my activity, I call an NTP server which I do using an async-task and I do multiple database operations(I'm using Firebase Database), and whenever this activity opens, there's an ANR error. I read that for long tasks, we should use a worker thread so I put the database operations in a thread but even with that, I still get an ANR error. What else do you suggest ?
(the NTP server returns the correct result and all the operations in database are done everytime, even though I get the ANR error.)
public class Start extends AppCompatActivity {
//declaring variables
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
new Thread(new Runnable() {
public void run(){
finishQuiz();
}
}).start();
final DatabaseReference myRef = FirebaseDatabase.getInstance().getReference();
myRef.addValueEventListener(new ValueEventListener() {
//in this part, I call getNetworkTime, and under specific conditions I set an intent AlarmManager
}
Here is the function finishQuiz() I call inside the thread :
public void finishQuiz() {
// DEFINING THE VARIABLES NEEDED
myRef.addListenerForSingleValueEvent( new ValueEventListener() {
String dateD, hourD, userID, nom, prenom;
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Date d = new Date();
timee = d.getTime();
try {
timee = new Start.getNetworkTime().execute().get();
} catch (Exception e) {
timee = d.getTime();
}
String dateD = dataSnapshot.child("quiz").child("dateD").getValue(String.class);
String hourD = dataSnapshot.child("quiz").child("heureD").getValue(String.class);
if (!(dateD.equals("")) && !(hourD.equals(""))) {
long nbQ = dataSnapshot.child("quiz").child("questions").getChildrenCount();
int dureeQ = Integer.valueOf(dataSnapshot.child("quiz").child("duree").getValue().toString());
String[] D = dateD.split("-", 3);
String[] H = hourD.split(":", 3);
Calendar calDebut = Calendar.getInstance();
calDebut.set(Integer.valueOf(D[2]), Integer.valueOf(D[1]) - 1, Integer.valueOf(D[0]), Integer.valueOf(H[0]), Integer.valueOf(H[1]), Integer.valueOf(H[2]));
Date dateDebutQ = calDebut.getTime();
long timeQFinInMillis = dateDebutQ.getTime() + (nbQ + 1) * dureeQ * 1000;
if (timee > timeQFinInMillis) {
try {
final SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm");
Calendar caldateQ = Calendar.getInstance();
String[] dateDT = dateD.split("-", 3);
String[] hourDT = hourD.split(":", 3);
caldateQ.set(Integer.valueOf(dateDT[2]), Integer.valueOf(dateDT[1]) - 1, Integer.valueOf(dateDT[0]), Integer.valueOf(hourDT[0]), Integer.valueOf(hourDT[1]), Integer.valueOf(hourDT[2]));
long c = caldateQ.getTimeInMillis();
List<Date> listPast = new ArrayList<>();
List<Date> listFuture = new ArrayList<>();
for (DataSnapshot ds : dataSnapshot.child("next quizs").getChildren()) {
String dateNext = ds.getKey();
try {
Date dateNx = formatter.parse(dateNext);
Date dateQQQ = caldateQ.getTime();
Date dateQQ = formatter.parse(formatter.format(dateQQQ));
long timeNx = dateNx.getTime();
if (timeNx < timee) {
listPast.add(dateNx);
}
else
{
listFuture.add(dateNx);
}
} catch (Exception e) {
}
}
for (int i = 0; i < listPast.size(); i++) {
myNextQuiz.child(formatter.format(listPast.get(i))).removeValue();
}
if (listFuture.size()==0) {
myQuiz.child("dateD").setValue("");
myQuiz.child("heureD").setValue("");
myQuiz.child("duree").setValue(10);
myQuiz.child("questions").setValue("This will be removed anyways");
} else
//I get ANR error in this case
{
Date minuD = listFuture.get(0);
for (int k = 1; k < listFuture.size(); k++) {
if ((listFuture.get(k).compareTo(minuD) < 0)) {
minuD = listFuture.get(k);
}
}
String date = formatter.format(minuD);
String[] DH = date.split(" ", 2);
myQuiz.child("dateD").setValue(DH[0]);
myQuiz.child("heureD").setValue(DH[1] + ":00");
String ddd = dataSnapshot.child("next quizs").child(date).child("duree").getValue().toString();
myQuiz.child("duree").setValue(ddd);
myQuiz.child("questions").removeValue();
int j = 1;
for (DataSnapshot ds : dataSnapshot.child("next quizs").child(date).child("questions").getChildren()) {
String quest = ds.child("question").getValue(String.class);
String sol = ds.child("sol").getValue(String.class);
String answA = ds.child("A").getValue(String.class);
String answB = ds.child("B").getValue(String.class);
String answC = ds.child("C").getValue(String.class);
String answD = ds.child("D").getValue(String.class);
myQuiz.child("questions").child("" + j).child("question").setValue(quest);
myQuiz.child("questions").child("" + j).child("sol").setValue(sol);
myQuiz.child("questions").child("" + j).child("A").setValue(answA);
myQuiz.child("questions").child("" + j).child("B").setValue(answB);
myQuiz.child("questions").child("" + j).child("C").setValue(answC);
myQuiz.child("questions").child("" + j).child("D").setValue(answD);
j++;
}
}
myPreQuiz.child(dateD + " " + hourD).child("dateD").setValue(dateD);
myPreQuiz.child(dateD + " " + hourD).child("heureD").setValue(hourD);
for (DataSnapshot ds : dataSnapshot.child("current quiz").child("number").getChildren()) {
userID = ds.getKey();
nom = dataSnapshot.child("utilisateurs").child(userID).child("Nom").getValue(String.class);
prenom = dataSnapshot.child("utilisateurs").child(userID).child("Prenom").getValue(String.class);
myPreQuiz.child(dateD + " " + hourD).child("gagnants").child(userID).setValue(nom + " " + prenom);
}
myCurrQuiz.child("currentQ").setValue("0");
myCurrQuiz.child("number").removeValue();
} catch (Exception e) {
//show Exception
} }}}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});}
And here's my async Task :
private class getNetworkTime extends AsyncTask<Void, Void, Long> {
#Override
protected Long doInBackground(Void... params) {
String TIME_SERVER = "2.android.pool.ntp.org";
try{
NTPUDPClient timeClient = new NTPUDPClient();
InetAddress inetAddress = InetAddress.getByName(TIME_SERVER);
TimeInfo timeInfo = timeClient.getTime(inetAddress);
long returnTime = timeInfo.getMessage().getTransmitTimeStamp().getTime(); //server time
return returnTime;
} catch (Exception e) {
Date d = new Date();
long l=d.getTime();
return l;
}
}
protected void onPostExecute(Long result) {
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
If it is helpful, before I use the NTP server, my code used to work perfectly, and I tested without the AlarmManager part and it worked fine too, and also, in the function finishQuiz(), as I mentioned in a comment, only that particular case gives the ANR error(which happens to be the most common case for my app), I mean without entering that block, there's no ANR error.
Even though you start executing your finishQuiz method on a background thread, the firebase callbacks are called back on the main (UI) thread. This is likely causing your ANR.
Try executing the code in the onDataChange() callback on a background thread.
new Thread(new Runnable() {
public void run(){
// PUT YOUR CODE FROM onDataChange() HERE, or use AsyncTask
}
}).start();
See this: Firebase Android: onDataChange() event always executed in Main UI Thread?

array list adds the elements then remove them alone

I am using arrayList of object in my app. I made a methods to check if an element exists in the list or no. The element is coming from firebase database. After adding these methods I found that the elements appears in the recycler view then disappears again. I debugged my code and I found that the elements are added to the list then removed again, but I can't understand why this behavior happens.
These are the methods I made :
boolean existsInCompletedChallengesList(String currentChallengeId) {
for (Challenge c : completedChallengesList) {
Log.v("completedChallengesList", "id of challenge in completedChallengesList : " + c.getId() + " current challengeId " + currentChallengeId);
if (c.getId().equals(currentChallengeId)) {
return true;
}
}
return false;
}
boolean existsInUncompletedChallengesList(String currentChallengeId) {
no++;
Log.v("check", "number of times is : " + no);
for (Challenge c : uncompletedChallengesList) {
Log.v("uncompletedChallengesLi", "id of challenge in uncompletedChallengesList : " + c.getId() + " current challengeId " + currentChallengeId);
if (c.getId().equals(currentChallengeId)) {
Log.v("uncompletedChallengesLi", "id of challenge in uncompletedChallengesList : " + c.getId() + " returned true" + currentChallengeId);
return true;
}
}
Log.v("uncompletedChallengesLi", "returned false" );
return false;
}
and this is the code that brings the data from the firebase database :
public void startAsynkTask() {
//TODO : search for a solution to this error
AsyncTask asyncTask = new AsyncTask() {
#Override
protected Boolean doInBackground(Object[] objects) {
try {
Socket sock = new Socket();
sock.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
sock.close();
return true;
} catch (IOException e) {
return false;
}
}
#Override
protected void onPostExecute(Object o) {
if ((boolean) o) {
clearLists();
ChildEventListener generalChallengesListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Log.v("onChildAdded", "child added");
getChallengeData(dataSnapshot, "onChildAdded");
view.onDataFound();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
//TODO : note that the only changing handled is when challenge moves from uncompleted to completed state
if(!dataSnapshot.getKey().equals("questionsList")){
getChallengeData(dataSnapshot, "onChildChanged");
}
for (int i = 0; i < uncompletedChallengesList.size(); i++) {
if (uncompletedChallengesList.get(i).getId().equals(dataSnapshot.getKey())) {
uncompletedChallengesList.remove(i);
view.notifyAdapters(completedChallengesList.size(), uncompletedChallengesList.size());
break;
}
}
checkListsSizeAndAdjustViews();
view.hideProgressBar();
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
startAsynkTask();
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
//Toast.makeText(getActivity(), "فشل تحميل البيانات من فضلك تأكد من الاتصال بالانترنت", Toast.LENGTH_SHORT).show();
view.hideProgressBar();
Log.v("Logging", "error loading data : " + databaseError);
}
};
//this code gives data where current user is player 1
player1Listener = challengesReference.orderByChild("player1Uid").equalTo(currentUserUid).addChildEventListener(generalChallengesListener);
//this code gives data where current user is player 2
player2Listener = challengesReference.orderByChild("player2Uid").equalTo(currentUserUid).addChildEventListener(generalChallengesListener);
challengesReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
onInitialDataLoaded();
Log.v("ChallengesFragPresenter", "completed list size :" + completedChallengesList + " , uncompleted list size : " + uncompletedChallengesList);
challengesReference.removeEventListener(this);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
} else {
view.onNoInternetConnection();
}
}
};
asyncTask.execute();
}
public String getChallengeData(DataSnapshot dataSnapshot, String tag) {
Log.v("ChallengesFragPresenter", "get challenge data called");
Log.v("ChallengesFragPresenter", "completedChallengesList : " + completedChallengesList.size()
+ ", uncompletedChallengesList " + uncompletedChallengesList.size());
view.startCompletedChallengesAdapter(completedChallengesList);
view.startUnCompletedChallengesAdapter(uncompletedChallengesList);
GenericTypeIndicator<List<Question>> t = new GenericTypeIndicator<List<Question>>() {
};
challenge = new Challenge();
String challengeDate = dataSnapshot.child("date").getValue().toString();
String challengeSubject = dataSnapshot.child("subject").getValue().toString();
String challengeState = dataSnapshot.child("state").getValue().toString();
String challengeId = dataSnapshot.getKey();
ArrayList challengeQuestionsList = (ArrayList) dataSnapshot.child("questionsList").getValue(t);
long player1Score = (long) dataSnapshot.child("player1score").getValue();
long player2Score = (long) dataSnapshot.child("player2score").getValue();
String player1Name = dataSnapshot.child("player1Name").getValue().toString();
String player1Image = dataSnapshot.child("player1Image").getValue().toString();
String player1Uid = dataSnapshot.child("player1Uid").getValue().toString();
String player2Name = dataSnapshot.child("player2Name").getValue().toString();
String player2Image = dataSnapshot.child("player2Image").getValue().toString();
String player2Uid = dataSnapshot.child("player2Uid").getValue().toString();
String challengerName, challengerImage;
if (player1Uid.equals(currentUserUid)) {
currentPlayer = 1;
challengerName = player2Name;
challengerImage = player2Image;
challenge.setSecondChallengerUid(player2Uid);//second means that it is not the player who starts the challenge
if (tag.equals("onChildAdded")) {
player1childrenCount++;
}
} else {
currentPlayer = 2;
challengerName = player1Name;
challengerImage = player1Image;
challenge.setSecondChallengerUid(player1Uid);//second means that it is not the player who starts the challenge
if (tag.equals("onChildAdded")) {
player2childrenCount++;
}
}
challenge.setCurrentPlayer(currentPlayer);
challenge.setChallengerName(challengerName);
challenge.setDate(challengeDate);
challenge.setImage(challengerImage);
challenge.setSubject(challengeSubject);
challenge.setState(challengeState);
challenge.setId(challengeId);
challenge.setPlayer1Score(player1Score);
challenge.setPlayer2Score(player2Score);
challenge.setQuestionsList(challengeQuestionsList);
String score;
if (currentPlayer == 1) {
score = player1Score + " : " + player2Score;
} else {
score = player2Score + " : " + player1Score;
}
challenge.setScore(score);
if (challenge.getState().equals("اكتمل")) {
Log.v("loggingC1", "value is " + !existsInCompletedChallengesList(challengeId));
if (!existsInCompletedChallengesList(dataSnapshot.getKey())) {
view.showCompletedChallengesTv();
completedChallengesList.add(0, challenge);
view.notifyAdapters(completedChallengesList.size(), uncompletedChallengesList.size());
}
}
else if (challenge.getState().equals(refusedChallengeText)) {
Log.v("loggingC2", "value is " + !existsInCompletedChallengesList(challengeId));
if (!existsInCompletedChallengesList(dataSnapshot.getKey())) {
view.showCompletedChallengesTv();
completedChallengesList.add(0, challenge);
view.notifyAdapters(completedChallengesList.size(), uncompletedChallengesList.size());
}
}
else if (challenge.getState().equals(uncompletedChallengeText)) {
Log.v("loggingC3", "value is " + !existsInUncompletedChallengesList(dataSnapshot.getKey()));
if (!existsInUncompletedChallengesList(challengeId)) {
view.showUncompletedChallengesTv();
uncompletedChallengesList.add(0, challenge);
view.notifyAdapters(completedChallengesList.size(), uncompletedChallengesList.size());
}
}
return player1Uid;
}
private void checkListsSizeAndAdjustViews() {
if (uncompletedChallengesList.size() == 0) {
view.hideUncompletedChallengesTv();
} else {
view.showUncompletedChallengesTv();
}
if (completedChallengesList.size() == 0) {
view.hideCompletedChallengesTv();
} else {
view.showCompletedChallengesTv();
}
if (completedChallengesList.size() == 0 && uncompletedChallengesList.size() == 0)
view.showNoChallengesTv();
else {
view.hideNoChallengesTv();
}
}
I am using asynk task at the begging to check if there is internet connection or no

Java Android modifies member variables from Callback thread

Basically, I am trying to get some value from the Api callback response, then assign those value to some of my member variables, but It seems like the program has to run over my getPatientRecord() method each time before it could go to my call, which I have never encountered before.
The Log output result is :
viewPatient: paitient method
viewPatient: secondHello worldnullnull
100SN9 - David Hello H M H 1971-08-09
This is my code:
public class ViewPatientRecord extends AppCompatActivity{
TextView tvName, tvGender, tvBirthDate, tvAddress;
String pGender, pAddress, pBirthdate;
String pName = "Hello world";
Patient myPatient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_patient_record);
tvName = findViewById(R.id.tvFullName);
tvGender = findViewById(R.id.tvGender);
tvBirthDate = findViewById(R.id.tvDb);
tvAddress = findViewById(R.id.tvAddress);
myPatient= new Patient();
try {
getPatientRecord();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void getPatientRecord() throws InterruptedException {
SharedPreferences myPre = getSharedPreferences("PatientRecord", MODE_PRIVATE);
if(myPre.getString("uuid",null)!=null){
retrievePatientByUuid(myPre.getString("uuid",null));
Log.d("viewPatient", "second"+pName+pGender+pBirthdate);
tvName.setText(pName);
tvGender.setText(pGender);
tvBirthDate.setText(pBirthdate);
tvAddress.setText(pAddress);
}else{
Toast.makeText(ViewPatientRecord.this, "Something went wrong, please contact the administrator for help!", Toast.LENGTH_SHORT).show();
}
}
private void retrievePatientByUuid(String uuid) throws InterruptedException {
RestApi api = RetrofitInstance.getRetrofitInstance().create(RestApi.class);
Log.d("viewPatient", "paitient method");
Call<Patient> call = api.getPatientByUUID(uuid, null);
call.enqueue(new Callback<Patient>() {
private volatile Patient obj = new Patient();
#Override
public void onResponse(Call<Patient> call, Response<Patient> response) {
if (response.body() != null) {
Patient patient = response.body();
if (patient != null) {
if (!patient.getDisplay().isEmpty()) {
pName = patient.getDisplay();
pGender = patient.getPerson().getGender();
pBirthdate = patient.getPerson().getBirthdate();
Log.d("viewPatient", pName.toString() + " H " + pGender.toString() + " H " + pBirthdate.toString() + " ?? ");
pAddress = "";
} else {
Log.d("viewPatient", "no results");
}
} else {
Toast.makeText(ViewPatientRecord.this, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(ViewPatientRecord.this, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<Patient> call, Throwable t) {
t.printStackTrace();
}
});
}
}
I don't see the problem. The call is done in retrievePatientByUuid which is called by getPatientRecord. So yes, you have to go through getPatientRecord. The call is async. It's in the callback that you should set your TextViews :
tvName.setText(pName);
tvGender.setText(pGender);
tvBirthDate.setText(pBirthdate);
tvAddress.setText(pAddress);

Barcode scanning pause and resume on android

I am starting to experience on java in android.
I have 3 EditText on the layout.
I setup a barcode scanning window to scan the barcode.
After getting the first barcode, i pause the scanning and place it on the first EditText View.
Then i resume.
The problem is that after the first scan, the camera does not scan again.
I tried many method, pause then resume and it still does not work.
Can someone help?
The code look like this.
private CompoundBarcodeView barcodeView;
private BarcodeCallback callback = new BarcodeCallback() {
#Override
public void barcodeResult(BarcodeResult result) {
String code = null;
if (result.getText() != null) {
code = result.getText();
if (code != null) {
barcodeView.pause();
job01 = (EditText) findViewById(R.id.jobTicket01);
if (job01.getText().toString().trim().equals("")) {
job01.setText(code);
code = null;
}else {
if (job02.getText().toString().trim().equals("")) {
job02.setText(code);
code = null;
} else{
}
}
}
}
barcodeView.resume();
}
#Override
public void possibleResultPoints(List<ResultPoint> resultPoints) {
}
};
Thank in advance.
Teddy
I just avoid parsing data from the scan for a few seconds.
I set up 2 values one for the data and another for the timestamp.
String barcodeData = "";
Long scanTime = 0L;
#Override
public void receiveDetections(Detector.Detections<Barcode> detections) {
final SparseArray<Barcode> barcodes = detections.getDetectedItems();
if (barcodes.size() != 0) {
txtBarcodeValue.post(new Runnable() {
#Override
public void run() {
if(barcodeData.equals("") && scanTime.equals(0L)){
barcodeData = barcodes.valueAt(0).displayValue;
scanTime = System.currentTimeMillis();
Log.d(TAG, "Barcode" + barcodeData);
}else if (!barcodeData.equals(barcodes.valueAt(0).displayValue)){
barcodeData = barcodes.valueAt(0).displayValue;
scanTime = System.currentTimeMillis();
Log.d(TAG, "New Barcode Scanned" + barcodeData);
}else if (barcodeData.equals(barcodes.valueAt(0).displayValue) && scanTime>(System.currentTimeMillis()-2500)) {
//Do Nothing
Log.d(TAG, "Barcode Ignored ---------------" + barcodeData);
}else{
barcodeData ="";
scanTime = 0L;
}
}
});
}
}

Categories

Resources