Send constantly data from service to activity - android

I'm getting data in a service, and this data is constantly updating.
I can see this data in Log, but I want to see it in an activity to display it. So what should I add to my service so that my activity would be instantly notified with updated data?
I can see and get data in the service when the task is completed, with the onTaskCompleted method, and this how I'm using it in my service.
(PS: I can send data from activity to service).
EDIT
I added some code to resolve the problem, but I have an error in the "SEND_DATA_INTENT": SEND_DATA_INTENT cannot be resolved to a variable
public class DownloadService extends Service implements OnTaskCompleted {.....
#Override
public void onTaskCompleted(String result){
results.add(result);//Ici on ajoute a chaque appel du service le debit
Intent intent = new Intent(SEND_DATA_INTENT);//i have an error here :SEND_DATA_INTENT cannot be resolved to a variable
intent.putExtra("type", "message");
sendBroadcast(intent);
}
//i would like to send data to the activty here ,because i'm sure that the task is end, and i have the data that i need.
}
}
In the main Activity i add DataReciver class
private class DataReciver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(DownloadService.SEND_DATA_INTENT)) //i have an error here :SEND_DATA_INTENT cannot be resolved to a variable
{
Bundle bdl = intent.getExtras();
String type = bdl.getString("type");
}
}
}

Add Broadcast reciever in the service and catch the data into broadcast reciever after that through a reciever event from this service with particular action and catch the action to the activity which you want to get it send the data through intent.

Related

handling packet listeners in xmpp

I am trying to develop a android chat application using asmack api and server is openfire.
I am at the stage of handling incoming messages from users and representing them corresponding user chat screen (i.e. activity).
So for that, I developed 2 activities i.e.
public class ResultActivity extends Activity
public class UserActivity extends Activity
resultactivity is the one which maintains roster presence information like online , away etc. so this would be only one instance.
useractivity is the one which maintain chat list with the corresponding user. This activity starts with onclick event on list in ResultActivity. so this can be more than one based on no of users on Result activity..
So to listen to incoming packets (i.e. incoming messages) I added a listener in the ResultActivity which adds messages into global arraylist.
In Result Activity:
PacketFilter filter = new MessageTypeFilter(Message.Type.chat);
MainActivity.connection.addPacketListener(receive_message, filter);
PacketListener receive_message = new PacketListener() {
public void processPacket(Packet packet) {
message = (Message) packet;
String sender=null,body=null,sender_final=null;
if (message.getBody() !=null) {
Log.d("UA", "message from "+StringUtils.parseBareAddress(message.getFrom()));
Log.d("UA", "message is "+message.getBody());
sender = StringUtils.parseBareAddress(message.getFrom());
sender_final=sender.substring(0, sender.indexOf('#'));
body = message.getBody();
Log.d("UA", "Sender : "+sender_final+" body : "+body);
userMessage = new UserMessage("In", sender_final, body);
userMessage_list.add(userMessage);
userMessage_list.add(userMessage);
}
}
};
After adding the message in the global message list (i.e. userMessage_list) I need to update the user activity with incoming message. userMessage_list is the array list used as array in the getview method of base adapter extended class.
So Now I need the update the userActivity list with notifydatasetchanged method.
In UserActivity :
private class UserActivityThread extends Thread {
#Override
public void run() {
UserActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
userAdapter.notifyDataSetChanged();
}
});
}
}
So how to call the notifydatasetchanged method in the another activity.
I am curious to know how this scenario is handled in whatsapp or any chat applications.
I have solved this problem in my chat app by using a ContentProvider class and a CursorLoaderwhich will be automatically notified everytime certain URI has new records.
In your case I would recommend you launching a broadcast message. Your class which has a ListView with the messages will have registered a BroadcastReceiver and it will be listening to possible updates. Everytime your BroadcastReceiver.onReceive is triggered in your activity, refresh your adapter.
Hope it helps :)
EDIT
How to achieve this:
Create a BroadcastReceiver object in your activity.
BroadcastReceiver mReceiver;
Code your broadcast receiver (on your onCreate for example)
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//extract our message from intent
String extra= intent.getStringExtra("extra");
Log.i("msg received: ", extra);
}
};
Add IntentFilter (in your onResume could be valid)
IntentFilter intentFilter = new IntentFilter("com.myproject.myintentfilter");
4.1 register your receiver
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
registerReceiver(mReceiver,intentFilter);
}
4.2 Unregister your receiver
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
this.unregisterReceiver(mReceiver);
}
Make sure your receiver will receive the message, cheking that your sendBroadcast matches the IntentFilter.
Finally:
Intent i = new Intent("com.myproject.myintentfilter").putExtra("extra", "This is a new value");
this.sendBroadcast(i);
EDIT 2
In the case of receiving a message during your activity rotation (receiver is not registered) I have found 2 solutions which I am not very satisfied with, but they work.
Reload your listview after orientation change, as the activity destroys itself, you can just reload the information of your listview, your new message should appear anyway.
Put a static field in your activity, everytime you receive a message, put such variable to TRUE. If your broadcastReceiver triggers, put that variable to false, and when your onResume / onCreate method is called after a change of orientation, check your static variable and do your reload if the variable was true (put it to false after reloading the ListView).

How to wait for an IntentService to finish its task

I'm using an intent service to communicate with a server to get data for an app. I'd like the app to wait until the data it requests has been sent back (hopefully meaning that the IntentService the data has been requested from has finished running) before the app attempts to access or use the variables the data is to be stored in. How would I go about doing this? thanks!
Easiest way is to have your IntentService send a Broadcast once it is done gathering data from the server, which you can listen to in your UI thread (e.g. Activity).
public final class Constants {
...
// Defines a custom Intent action
public static final String BROADCAST_ACTION =
"com.example.yourapp.BROADCAST";
...
// Defines the key for the status "extra" in an Intent
public static final String EXTENDED_DATA_STATUS =
"com.example.yourapp.STATUS";
...
}
public class MyIntentService extends IntentService {
#Override
protected void onHandleIntent(Intent workIntent) {
// Gets data from the incoming Intent
String dataString = workIntent.getDataString();
...
// Do work here, based on the contents of dataString
// E.g. get data from a server in your case
...
// Puts the status into the Intent
String status = "..."; // any data that you want to send back to receivers
Intent localIntent =
new Intent(Constants.BROADCAST_ACTION)
.putExtra(Constants.EXTENDED_DATA_STATUS, status);
// Broadcasts the Intent to receivers in this app.
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
}
}
Then create your broadcast receiver (either a separate class or inner class within your Activity)
E.g.
// Broadcast receiver for receiving status updates from the IntentService
private class MyResponseReceiver extends BroadcastReceiver {
// Called when the BroadcastReceiver gets an Intent it's registered to receive
#
public void onReceive(Context context, Intent intent) {
...
/*
* You get notified here when your IntentService is done
* obtaining data form the server!
*/
...
}
}
Now the final step is to register the BroadcastReceiver in your Activity:
IntentFilter statusIntentFilter = new IntentFilter(
Constants.BROADCAST_ACTION);
MyResponseReceiver responseReceiver =
new MyResponseReceiver();
// Registers the MyResponseReceiver and its intent filters
LocalBroadcastManager.getInstance(this).registerReceiver(
responseReceiver, statusIntentFilter );

How to let Activity know that cyclic Service has finished its task once?

I have some problems working with Android Services. I already have a Service which downloads a file from a server. (The Service checks cyclic for new data) Aftwerwards it parses the file and adds values to an ArrayList wich will be saved to SharedPreferences.
In my Activity there are two methods. One will display the values from the ArrayList/SharedPreferences in UI and the second method sets a Notification if needed.
But how do I now when my Service completed its task so the two methods can be started?
Register a BroadcastReceiver in your Activity something like:
myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do my stuff
}
};
registerReceiver(myReceiver , new IntentFilter("com.myapp.DOWNLOADCOMPLETE"));
Then in your service send the broadcast:
Intent i = new Intent("com.myapp.DOWNLOADCOMPLETE");
sendBroadcast(i);
You can also putExtras on your intent if you need to pass some values:
Documentation BroadcastReceiver

ContentProvider, Loader and ProgressBar

I have a ContentProvider which fetches data from sqlite database and loads it via Loader. It's updated by a Service which runs an AsyncTask to download data from server and update it in the ContentProvider. I hope it's clear but to be sure:
ListFragment takes data from ContentProvider via Loader,
ContentProvider gets updated with a Service.
Now, when my local sqlite database is empty the first time I launch the app, it shows that it has no events, even though they're being currently downloaded via Service. I would rather have a ProgressBar shown at this moment (the infinite spinning wheel, not a bar). But if I show a ProgressBar when there are no results from database, it would be there even after fetching data from sever in this specific case when there are no records in the external database (and it occurs quite often in my case). So:
When the data is downloaded for the first time by the Service I
would like to show a ProgressBar until ContentProvider gives
non-empty result OR the Service finished it's job.
When ContentProvider returned nothing AND Service finished
it's job (and fetched empty result) I would like the app to show
"no results found".
My problem is probably: how to notify the ListFragment that the Service is still running or that it finished ts job. I mean - I shouldn't store any reference to the calling Fragment inside the Service. It goes against the idea of ContentProviders, doesn't it? So how?
Note: I don't really know which fragment of code would be helpful here, so if you feel that you need to see some specific frag, just tell me in comments. Thanks!
Since you're not so much interested in posting actual progress back to the UI, the simplest way to implement this would be using a pair of custom broadcasts, and maybe a static boolean to show run state as well.
Basically, your service can notify any component of your application that's interested when it is beginning a download and when it has finished it. So you can define two custom action strings:
public static final String ACTION_DOWNLOADSTART = "com.mypackage.intent.ACTION_DOWNLOADSTART";
public static final String ACTION_DOWNLOADCOMPLETE = "com.mypackage.intent.ACTION_DOWNLOADCOMPLETE";
Then have your service broadcast them at the proper points in the code:
Intent start = new Intent(ACTION_DOWNLOADSTART);
sendBroadcast(start);
//...Service does its work
Intent finish = new Intent(ACTION_DOWNLOADCOMPLETE);
sendBroadcast(finish);
You can register for these callbacks anywhere in your application with a BroadcastReceiver and act accordingly (i.e. check the status of the ContentProvider and show/hide progress if necessary).
Another common practice, if you want to be able to check if a Service is running at any given point, is simply to include a private static boolean member that you can toggle when the Service is active (perhaps between onCreate()/onDestroy() but perhaps elsewhere) and an accessor method like isRunning(). Then your application can also check at any time if the Service is running by just calling that method.
There are various techniques how to communicate between Fragment / Activity and a Service.
One of them is using ResultReceiver and sending it to IntentService in Intent extra.
You create custom receiver ServiceResultReceiver extending ResultReceiver.
public class ServiceResultReceiver extends ResultReceiver {
private Receiver mReceiver;
public ServiceResultReceiver(Handler handler) {
super(handler);
}
public void setReceiver(Receiver receiver) {
mReceiver = receiver;
}
public interface Receiver {
public void onReceiveResult(int resultCode, Bundle resultData);
}
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (mReceiver != null) {
mReceiver.onReceiveResult(resultCode, resultData);
}
}
}
Make your Fragment implement ServiceResultReceiver.Receiver interface. Create receiver
and initialize it to your Fragment. You than pass the receiver to service and in service just get the receiver from intent and call receiver.send() to send anything back to the receiver.
public class MyFragment extends ListFragment implements ServiceResultReceiver.Receiver {
private ServiceResultReceiver mReceiver;
....
#Override
public void onCreate(Bundle savedInstanceState) {
...
mReceiver = new ServiceResultReceiver(new Handler());
mReceiver.setReceiver(this);
}
public void startMyService() {
final Intent intent = new Intent(getActivity(), MyService.class);
intent.putExtra("receiver", mReceiver);
getActivity().startService(intent);
}
#Override
public void onReceiveResult(int resultCode, Bundle resultData) {
// service finished
}
}
public class MyService extends IntentService {
...
#Override
protected void onHandleIntent(Intent intent) {
// download data and update database
....
final ResultReceiver receiver = intent.getParcelableExtra("receiver");
if (receiver != null) {
receiver.send(0, null);
}
}
}

Passing Data from Broadcast Receiver to another Activity

Hi I've been having an issue with Broadcast Receivers and passing information to another activity. I'm trying to create an application that will capture incoming SMS messages, look for a website in the text, then pop up an Alert Dialog box asking if the user wants to go to the website.
public class TextReceiver extends BroadcastReceiver{
public void onReceive(Context context, Intent intent)
{
// .. other code that
// sets received SMS into message
Toast toast = Toast.makeText(context,
"Received Text: " + message.getMessageBody(), Toast.LENGTH_LONG);
toast.show();
}
So that code works fine, receive a text it pops up a toast with the message. The toast is useless but it shows the receiver works. But I want to communicate with an activity to show an Alert Dialog and start up a webView. I already programmed the code that will take a string search for the website and open the webView. Is it possible to get the string from the broadcast receiver and do something like this?:
public class ReceiveText extends Activity{
public void onCreate(Bundle savedInstanceState) {
// Somehow pass the string from the receiver into this activity,
//stored in variable messages
findOpen(messages);
// is that possible?
}
public class findOpen(string messages){
// do stuff ... open alert...open site if OK
}
So basically I just want to pass a string from a Broadcast Receiver to another activity that will use that string. The rest of the code is basically in place all I need is that string... I'm new to this and Java and any help would be much appreciated. Thanks
Instantiate a BroadcastReceiver in the activity you want to get your data to, for example:
private BroadcastReceiver mServiceReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent)
{
//Extract your data - better to use constants...
String IncomingSms=intent.getStringExtra("incomingSms");//
String phoneNumber=intent.getStringExtra("incomingPhoneNumber");
}
};
Unregister your receiver on onPause():
#Override
protected void onPause() {
super.onPause();
try {
if(mServiceReceiver != null){
unregisterReceiver(mServiceReceiver);
}
} catch (Exception e) {
e.printStackTrace();
}
}
Register it on onResume():
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.SmsReceiver");
registerReceiver(mServiceReceiver , filter);
}
Broadcast your data from the service via an Intent, for Example:
Intent i = new Intent("android.intent.action.SmsReceiver").putExtra("incomingSms", message);
i.putExtra("incomingPhoneNumber", phoneNumber);
context.sendBroadcast(i);
and that's it! goodLuck!
If you have your activity named ReceiveText, then in your BroadcastReceiver, you should do the following:
Intent i = new Intent(context, ReceiveText.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra("message", message.getMessageBody());
context.startActivity(i);
Then, in your activity, you will need to getExtra as so:
Intent intent = getIntent();
String message = intent.getStringExtra("message");
And then you will use message as you need.
If you simply want the ReceiveText activity to show the message as a dialog, declare <activity android:theme="#android:style/Theme.Dialog" /> in your manifest for ReceiveText and then set the message to a textview in the activity.
EDIT: This restarts your activity. this answer is likely a better solution for most people.
We can send the data from onReceive to another activity using LocalBroadcastManager.
It means you are again broadcasting the data using the context
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Broadcast", "wifi ConnectivityReceiver");
Bundle extras = intent.getExtras();
Intent intent = new Intent("broadCastName");
// Data you need to pass to another activity
intent .putExtra("message", extras.getString(Config.MESSAGE_KEY));
context.sendBroadcast(intent );
}

Categories

Resources