I have a simple application where I am trying to learn how to:
1) Call a web service
2) Parse the Data
3) Save it to SQLiteDatabase
4) Set-up a ContentObserver/Broadcaster to detect changes in an Activity and change the UI
So far, I have done everything but having trouble with step 4.
Code:
LaunchActivity which shows the layout containing the UI which I eventually want to change launches the Service class:
Intent intent = new Intent(this, DataService.class);
intent.putExtra("restMethodType", 0);
startService(intent);
The DataService class then runs the desired AsyncTask Rest Method:
public class DataService extends IntentService {
public DataService() {
super("DataService");
}
public DataService(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent intent) {
RestMethodType restMethodType = RestMethodType.values()[intent.getIntExtra("restMethodType", 0)];
switch (restMethodType) {
case UPCOMING_MATCH:
UpcomingMatchRestMethod restMethod = new UpcomingMatchRestMethod(getApplicationContext(), intent);
restMethod.execute();
break;
}
}
}
Within the onPostExecute method of the AsyncTask, I save the retrieved data in to the database and then broadcast the event:
long newRowId = database.insert(MatchContract.MatchEntry.TABLE_NAME, MatchContract.MatchEntry.COLUMN_NAME_LOCATION, values);
if(newRowId != -1){
mIntent.putExtra("matchId", newRowId);
LocalBroadcastManager.getInstance(mContext).sendBroadcast(mIntent);
}
Back in the LaunchActivity, I set-up a receiver object:
DataReceiver mDataReceiver;
#Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter("What Goes In Here?");
registerReceiver(mDataReceiver, intentFilter);
}
This is what the receiver looks like:
private class DataReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Do Stuff like update the UI
// Make sure to wrap any View objects in runOnUIThread
}
}
So what goes in the IntentFilter? And what else am I missing? I followed the Google Docs but getting a little confused.
Thank you in advance.
Related
I created a Broadcast Receiver (BR) in a service that will react to incoming SMS with specific number and body. I only need it to receive for a few seconds/minutes after user action, that's why I didn't registered it in manifest or activity (user may close it). BR has two parts, automatic (which works fine) and manual which should launch MainActivity and start a Dialog. I know that Dialog can't be started from BR and thats why I created a Listener, but my problem is that it is always null after service starts. It has value in onCreate of my MainActivity, but when service starts it changes to null, and I understand why (serivce re-initalize the Listener listener). I even tryed to put initialised listener value to SharedPrefs and restore it after, but when I try to store it with json it only stores null again. So how do I make my listener != null??? These are the relevant parts of my code:
MainActivity
onCreate {
SMSService smsReceiver = new SMSService();
smsReceiver.setListener(new SMSService.Listener() { //here listener from service is != null
#Override
public void onTextReceived(String s) {
dialogS(s); // totaly different dialog
}
});
...
mDialogBuilder = new AlertDialog.Builder(this);
...
.setPositiveButton(new OnClick...
Intent servisIntent = new Intent(MainActivity.this, SMSService.class);
startService(servisIntent);
...
}
SMSService
private Listener listener; // and here it get null which is the problem
public int onStartCommand(Intent intent, int flags, int startId) {
...
SMSReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, MainActivity.class);
context.startActivity(i);
if (listener != null) {
listener.onTextReceived("4333");
}
}
void setListener(Listener listener) {
this.listener = listener; }
interface Listener {
void onTextReceived(String text);
}
Btw I also tried to put smsReceiver.setListener block of code in my Dialog .setPossitive onClickListener after calling startService hoping it would initiate after service but nothing
Installing a listener mechanism with setter method in service is bad practice. You can use ResultReceiver to receive callback results from service. It is Parcelable, so it can be passed in an intent before service started
I am trying to implement an Async task that gets a string from a url inside a service.
I am using a startedService which calls the Async task get the correct string, update a public DB class content and return to the main activity, the problem is that the list adapter which i need to notify of the change in the DB is at the main activity and i don't have access to it from the Service , I am a a noobie so I am not familiar with what better to use , started or bind service for that job, any sugestions ?
thank you
You can use BroadcastReceiver :
In your Activity:
#Override
public void onResume() {
super.onResume();
// Register mMessageReceiver to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("mybroadcast"));
}
// handler for received Intents for the "my-event" event
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
#Override
protected void onPause() {
// Unregister since the activity is not visible
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onPause();
}
And to Broadcast from service use:
Intent intent = new Intent();
intent.setAction("mybroadcast");
sendBroadcast(intent)
So i have this receiver in my Fragment.class
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(WeekplanHepler.ACTION_SERVICE_BINDED) && getUpdateService() != null) {
getCounts();
}
if (intent.getAction().equals(Helper.UpdateCounts)) {
HashMap<String, Integer> counts = (HashMap<String, Integer>) intent.getSerializableExtra(Helper.PARAM_LIST_COUNTS);
// Updating counts
}
}
};
For registering/uregistering this receiver i'm using this code:
#Override
public void onStart() {
super.onStart();
getCounts(true);
getActivity().registerReceiver(receiver, getIntentFilter());
}
#Override
public void onStop() {
super.onStop();
getActivity().unregisterReceiver(receiver);
}
getCounts() is a RetrofitRequest puted in UpdateService, which is getUpdateService() here
So, when retrofit request has been finished, it returns counts through Intent and then, as you see, i'm updating them. But if i go to next Activity and then returns, request will work fine, and it will send intent, but receiver wont get it. I think this can be caused by method service is binded in first place. So i have BaseFragment, which binds service for all Fragments needed
public abstract class BaseFragment<T> extends CustomListFragment<T> {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().getApplicationContext().bindService(new Intent(getActivity().getApplicationContext(),
WeekplanUpdateService.class), connection, Context.BIND_AUTO_CREATE);
}
}
When i go to next activity, it fragment will bind service, and my previous fragment will call request again, and will have counts. Maybe receiver has some limitations for how much he can get same intents, but i don't think so. Please help
Oh, i forgot to mention how i'm sending intent
sendBroadcast(new Intent(Helper.UpdateCounts).putExtra(Helper.PARAM_LIST_COUNTS, counts));
So, when i've started to use
sendStickyBroadcast(new Intent(Helper.UpdateCounts)
.putExtra(Helper.PARAM_LIST_COUNTS, counts));
instead of
sendBroadcast(new Intent(Helper.UpdateCounts)
.putExtra(Helper.PARAM_LIST_COUNTS, counts));
it worked.
I am having problem with my android IntentService. When I first open the application, the service gets started by intent from the profile activity and data is fetched from this service. If I switch to other activity and then back service is still running and that is ok.
However if you press back, so that activity is finished and put in the background, the service is still working as the application is in background but If I get it back to foreground service stops. I do not know why. Bellow is my code, please help.
I have read activity life cycle couple of times and still do not get it why this is happening.
What is weird is that Service receive data one more time before it stops when MainActivity is brought back to running state. Service is not crashing.
Service
public class SomeService extends IntentService
{
public static final String extra = "someData";
public SomeService()
{
super(SomeService.class.getSimpleName());
}
#Override
protected void onHandleIntent(Intent intent)
{
Log.e("SomeService", "starting service");
while (true)
{
SomeData data = Api.getNewSocketData();
//Broadcast data when received to update the view
Intent broadcastData = new Intent();
broadcastData.setAction(dataBroadcastReceiver.ACTION_DATA_RECEIVED);
broadcastData.addCategory(Intent.CATEGORY_DEFAULT);
broadcastData.putExtra(extra, " ");
sendBroadcast(broadcastData);
Log.e("SomeService", "received from socket");
}
}
}
Receiver
public class dataBroadcastReceiver extends BroadcastReceiver
{
public final static String ACTION_DATA_RECEIVED = "net.bitstamp.intent.action.ACTION_SOMEDATA_RECEIVED";
#Override
public void onReceive(Context context, Intent intent)
{
Log.e("receiver", "data received");
}
}
Main Activity
#Override
public void onPause()
{
super.onPause();
unregisterReceiver(dataBroadcastReceiver);
}
#Override
public void onResume()
{
super.onResume();
IntentFilter intentFilter = new IntentFilter(dataBroadcastReceiver.ACTION_DATA_RECEIVED);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
dataBroadcastReceiver = new dataBroadcastReceiver();
registerReceiver(dataBroadcastReceiver, intentFilter);
Intent someService = new Intent(this, SomeService.class);
startService(someService);
}
I really need help on this. Thanks
You don't want to the up the IntentService in an infinite loop. It will block all other incoming requests. From the documentation:
All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.
Your Service is likely still happily running along, it just isn't processing your new request because your old one is still being handled in the infinite loop.
When i have a broadcastReceiver say android.intent.action.MEDIA_BUTTON and i want to update the current activity's UI without creating a new activity, is there any good practice on this one?
What i know (might not be correct)
1) I can put the BroadcastReceiver in the same class as the activity and call the updateUI function after certain activity
2) Create a ContentObserver?
3) Communicate to a service created by the activity, use aidl. (I dont know how to get the current service if its registered from an activity)
4) Create a custom filter on the broadcastReceiver located on the same class as the activity, and use context.sendBroadcast(msg of custom filter) and in the custom filter call updateUI (same as one but more generic?)
The final flow is it would come from a BroadcastReceiver and ends up updating the UI without renewing the activity (unless the activity is dead?)
Kindly provide links/source code on your how you tackle this kind of problem. Thanks a lot in advance :)
The easiest way to provide this functionality is to put the broadcast receiver in you Activity and bind / unbind it using registerReceiver and unregisterreceiver:
public class MyActivity extends Activity {
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
MyActivity.this.receivedBroadcast(intent);
}
};
#Override
public void onResume() {
super.onResume();
IntentFilter iff = new IntentFilter();
iff.addAction("android.intent.action.MEDIA_BUTTON");
// Put whatever message you want to receive as the action
this.registerReceiver(this.mBroadcastReceiver,iff);
}
#Override
public void onPause() {
super.onPause();
this.unregisterReceiver(this.mBroadcastReceiver);
}
private void receivedBroadcast(Intent i) {
// Put your receive handling code here
}
}
Depending on the intent you wish to receive, you may need to add the appropriate permissions to your AndroidManifest.xml file.
What I recently had to do to change a Button's text after receiving data from a LocalBroadcastManager is to store the value in a private field and then do the UI stuff in my onResume() method.
public class myClass extends Activity {
private String myString;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// register to receive data
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, new IntentFilter("myAction"));
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// get the extra data included in the intent
myString = intent.getStringExtra("myString");
}
};
#Override
public void onResume() {
super.onResume();
System.out.println("onResume");
// do something to the UI
myButton.setText(myString != null ? myString : "Default");
}
}