I have a chatting application that saves the messages in a Sqlite database. I need to load all messages for each chat when clicked by user and show them in ListView in an activity. So i was wondering how to do this ?
I thought of a couple of ways to do that
First option: get the data from database (messages i.e. Strings) before opening the messaging screen for the user in arrays and pass them through the intent when starting the messaging activity and then show the messages on onCreate() method.
Second Option: get the data (messages i.e. Strings) from database when activity is being created and show them.
Third option: Saving Persistent State according to Sqlite
Any other ideas are appreciated.
Thanks.
use 2nd option.just send the unique chat id to the chat screen and load all the messages of that chat from database in oncreate() method and then bind all messages to the listview.
In Activity, loading sqlite db in others thread, and when it load finish, print it in your list view.
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
//loading database
mHandler.sendMessage(msg);
}
}).start();
Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
//update listview
};
};
What I would do is to load them when you open the Activity, but I wouldn't load all messages but just the last X items. Most users won't scroll up to older messages 99% of the times.
You could for example load the last 10 messages and then (if the users make scroll up) load the other messages.
Luck!!
Related
As title what I want to do is only when database had change than run notification for it but a problem is when I run app the notification appear even the data is not change
here is my code:
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v= inflater.inflate(R.layout.main,container,false);
result= (TextView) v.findViewById(R.id.textView3);
notificationmanager = NotificationManagerCompat.from(ct.getcontext());
if (user != null) {
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
String post = dataSnapshot.getValue(String.class);
result.setText(post);
Notification notification = new NotificationCompat.Builder(ct.getcontext(), CHANNEL_1_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(post)
.setContentText("test")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_EVENT)
.setDefaults(Notification.DEFAULT_ALL)
.build();
notificationmanager.notify(2,notification);
}
}
#Override
public void onCancelled(DatabaseError error) {
}
});
}
else
{
Toast.makeText(getActivity(),"not yet login",Toast.LENGTH_LONG).show();
}
return v;
}
Save the value in your local preferences, then on next change, verify if the value if it is really changed by comparing with previously saved value.
You need to use addValueEventListener(), from the docs:
public ValueEventListener addValueEventListener (ValueEventListener listener)
Add a listener for changes in the data at this location. Each time time the data changes, your listener will be called with an immutable snapshot of the data.
Using addValueEventListener, everytime there is a change in the database it will be triggered.
From #mikasaloli's explanation, I suspect the problem lies more in in a mix of the way firebase RTDB( realtime database) / Firestore functions and the wrong listener.
The first problem is, firebase RTDB/firestore by default keeps a local cache copy of the references( not all of them) you've accessed on your phone. From their docs, they say, and I quote:
"Asynchronous listeners: Data stored in a Firebase Realtime Database is retrieved by attaching an asynchronous listener to a database reference. The listener is triggered once for the initial state of the data and again anytime the data changes. An event listener may receive several different types of events. This mode of data retrieval is supported in Java, Node.js and Python Admin SDKs."
What you need to do is bypass the local cache when reading data for the first time after app startup.
here's how I've been able to do that( with some slight tweaking)
The second problem is as previously mentioned by the others, addListenerForSingleValueEvent will get triggered only once. So, assuming you receive the notification change for the first time, your listener will automagically unregister itself implying you won't receive the subsequent onDataChange events.
Now, conjecturing from the previous paragraphs, the problem with the above code is:
it attaches a listener for single value event. which then gets triggered with the local ( cached ) version of the data which forcibly isn't the latest state of the server database ( if the application was offline while some changes took place online). But then, upon attaching this listener, it gets triggered with the local version of the data and unregisters itself afterwards. Implying, the above code will get triggered once at most and might never get triggered during it's lifetime while attached.
What I suggest, is you bypass the local cache and use a addValueEventListener.
I'm working on an basic reminder application which has a user interface capable to log user set dates to an sqlite database. To complete my application I'd like to have a service which starts and keep running in the background when the phone is restarted, so I can periodically check the database and display a notification message to the user if any of the dates are close.
I can start my service on startup (I can send LOG messages to Android Studio) but I can't display notifications. It seems the examples I have found always rely on an activity, but how would I have an activity without having the main app running? (and ofcourse thats the point of my background service, the user doesnt have to open the main app).
Q1: How can I display a Toast message from this service?
Q2: How can I display a notification from this service?
public class autostartservice extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
for (int i = 0; i < 40; i++) {
synchronized (this) {
try {
wait(1000);
} catch (Exception e) {}
Log.i("myDebug", "Just wait here couple second until the phone boots all the way");
}
}
Toast.makeText(context, "Look at this Toast! Cool uh?", Toast.LENGTH_SHORT).show();
}
}
}
All these kind of things uses a Context to show a Toast or a Notification. A Service "acts as" a Context, so you can do quite the same things as you do in an Activity. You only have to pay attention that a normal Service runs in the same Thread of the UserInterface, so if the Service is blocking (waiting some event in a Blocking way) even the UserInterface is blocked and Notifications or Toasts cannot be displayed while blocked/frozen.
How can I retrieve all data values from Firebase's real-time database when I load onStart event from my Android app without run any listener of Firebase?
Because I don't want to run any listener such as ("ondataChange, childAdded, childRemoved and etc ...") I don't need it.
From the Firebase documentation, the onDataChange method of the listener fires once when being attached and then every time there is a change. So, yes there is a way to fetch the data without an event. Though, this fetch would happen using listener only.
https://firebase.google.com/docs/database/android/read-and-write
Listen for value events To read data at a path and listen for changes,
use the addValueEventListener() oraddListenerForSingleValueEvent()
method to add a ValueEventListener to a DatabaseReference.
You can use the onDataChange() method to read a static snapshot of the
contents at a given path, as they existed at the time of the event.
This method is triggered once when the listener is attached and again
every time the data, including children, changes. The event callback
is passed a snapshot containing all data at that location, including
child data. If there is no data, the snapshot will return false when
you call exists() and null when you call getValue() on it.
There is no way to get the data from a Firebase real-time database or from Cloud Firestore without using a listener. Everything in Firebase is about listeners, even if you are getting data in real-time or if you are getting only once, you need to attach a listener on a particular location. Without it, there is no way you can get it.
Edit: From the official documentation regarding reading data in Android, here is a code snippet that demonstrates a social blogging application retrieving the details of a post from the database:
ValueEventListener postListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
Post post = dataSnapshot.getValue(Post.class);
// ...
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
};
mPostReference.addValueEventListener(postListener);
Though, it is late to reply here, but I am choosing to post here only rather than creating another thread on this.
IMO, the basic expectation from any database is to be able to read a selected set of data which is available in DB. It does not matter whether I have to attach a listener or write a custom code.
While I understand that the added benefit of real-time DB is that it is event driven and UI does not need to wait for user to initiate an action for getting the data, but how come there is no way to retrieve data if there is a need !! I have spent hours looking for this one way to fetch data. OOh :(
I have an app that has three activities, the user will be constantly tabbing between these three activities. Right before the user closes the app, my code downloads the current time from the internet and stores it. The problem is that i have my code for downloading the time in the onPause() method. This causes the data to be downloaded over and over each time the user switches activities. I tried using onDestroy() but the download would never start. is there a method that is called when the user minimizes or closes the app altogether instead of one that is called on an activity switch?
Thank you very much, any help is appreciated!
We can achieve this using the Application class. There we can implement the ActivityLifecycleCallbacks to identify when our app goes to the background and based on that result we can perform our required task. Here, a sample code:
public class MyApplication extends Application implements ActivityLifecycleCallbacks {
private Handler mHandler;
#Override
public void onCreate() {
super.onCreate();
mHandler = new Handler();
}
...
#Override
public void onActivityResumed(Activity activity) {
Log.i("Activity Resumed", activity.getLocalClassName());
// cancel scheduled download operation (if any)
mHandler.cancelCallbacksAndMessages(null);
}
#Override
public void onActivityPaused(Activity activity) {
Log.i("Activity Paused", activity.getLocalClassName());
// schedule a download operation after 5 seconds
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
performDownloadOperation()
}
}, 5000);
}
... // other lifecycle callbacks
private void performDownloadOperation() {
// perform download operation here
}
}
In the above code, we are basically giving the user [and the system] a grace time of 5 seconds to switch from one activity to another. Otherwise, we note that the app went to background and do our stuff there. So, even if the user switches to a different app for 4 seconds and then come back, we'd still not download the data, which should be fine in most cases.
Note that to use the above class, you need to provide the class reference to the android:name property as android:name=".MyApplication" under the <application> tag in the manifest file.
You can make use of Activity::isFinishing(). This will return false when you (1) launch another activity or when (2) the app is put on background, but it will return true when (3) the back button is pressed or if (4) somebody calls finish on the activity.
If it is important to distinguish between (1) and (2), then you can always keep a flag that you can switch every time you launch an activity and reset it in onPause.
I am most concerned about Performance issue and don't want users to wait for progress.
I have a chatActivity, where i show a ListView.
Here i send a chatMessage
Chats chat = new Chats(chatBox.getText().toString(),Chats.TYPE_MINE, dt.format(now));
chat.personId = chatee.getMyId();
chat.isDelievered = Chats.DELIEVERED_NONE;
chats.add(chat);
mAdapter.notifyDataSetChanged();
Notice that Chat delievery is set to NONE Right now. So basically the message is being added to the Chat List even its not delivered yet.
Now on back thread here is what's happening
It takes few seconds to send message where i do this
boolean bool = sendMessage(m);
if (bool)
chatee.isDelievered = Chats.DELIEVERED_DONE; (MESSAGE SENT)
if (chatee.isDelievered == Chats.DELIEVERED_DONE)
{
app.mDbHelper.saveMessage(chatee); // SAVING TO DATABASE
Intent i = new Intent(Constants.REFRESH_NOTIF).putExtra("refresh",Constants.REFRESH_NOTIF);
context.sendBroadcast(i);
}
It will send a broadcast to the activity.
Now here is the problem.
Broadcast call this function
public void callUIMethodForRefresh(Intent intent)
{
String ref = intent.getStringExtra("refresh");
if (ref == null)
{
}
else if (ref.equals(Constants.REFRESH_NOTIF))
{
}
}
Here i am confused of how can I reset that previous Chat object added to my List.
Points to be noted , i can be sending messages at a very fast speed and the refresh could be called for an old message whereas a new message is already typed.
ONE way is i make a For loop and check for all the "ChatList" array for the message sent and then replace its delivery notice, but again this is very low performance incase i have 1000+ objects in the list.
Is there any way, i can attach the sqlite database with my listView adapter that automatically detects the changes and reset the listView etc and etc?
What could be the best strategies here to avoid performance issues.
I would suggest looking into ContentProviders and Loaders (specifically a CusorLoader). Combining these with a CursorAdapter, you can use the ContentProvider which inserts/deletes/updates your sqlite database and notifies your loader to reload it's dataset and update the CursorAdapter/ListView.