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.
Related
I want to sent a message from a Fragment to an Activity (not the Fragment parent Activity, just another one).
Actually I do the same from a Service to the same Activity and it works great.
This is my code:
Fragment:
private void sendBroadcastMessage() {
Intent intent = new Intent("my_event");
// add data
intent.putExtra("message", "test");
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent);
}
Activity:
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
}
};
#Override
protected void onPause() {
// Unregister since the activity is not visible
LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver);
super.onPause();
}
#Override
protected void onResume() {
super.onResume(); LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver, new IntentFilter("my_event"));
}
I've just followed that great post, but it only works from Service to Activity
I think it has something to do with the Context from the Fragment, maybe getActivity() is not the right way...
Any ideas?
Thanks.
Register broadcast in onCreate and unregister in onDestroy of your activity.
In your case it may be unregister in onPause. so unregister in onDestroy instead of onPause.
Thanks,
So right now I have swipe to refresh in my app. When it is activated, a service which runs an async background task is executed. Problem is, the swipe to refresh indicator disappears immediately. How do I keep it displayed (and update my recycler view) when the service has finished running?
Here is some code:
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.activity_main_swipe_refresh_layout);
mSwipeRefreshLayout.setColorSchemeResources(R.color.StatusbarColor,R.color.Accent);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
db = new DatabaseHelper(getApplicationContext());
callRefreshService();
}
});
Here is the callRefreshService method:
public void callRefreshService() {
try{
Intent service = new Intent(getApplicationContext(), UpdateScoresService.class);
startService(service);
}
finally {
list.clear();
list.addAll(db.getTracked());
db.closeDB();
adapter.notifyDataSetChanged();
mSwipeRefreshLayout.setRefreshing(false);
}
}
As you can see I tried using try and finally but that doesn't help.
startService(Intent) does not block, it returns immediately.
You got two options:
Ditch the Service for AsyncTask
Allow the Service to communicate with your Activity
Choose 1 for something trivial like a one-off JSON download task. Call mSwipeRefreshLayout.setRefreshing(false) in the onPostExecute (Result result) block.
Choose 2 if you got something complex setup already.
Communication between Activity and Service is slightly complicated, what you need is a bind service. If you want something simple, you can look take a look at event bus, it decouple things quite nicely.
Here are some implementations of an event bus:
Otto
EventBus
Create a BroadcastReceiver inside your activity
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// stop refreshing the layout
mSwipeRefreshLayout.setRefreshing(false);
}
};
register it to your activity inside onResume() to listen to some Intenet and unregister it inside onPause()
#Override
protected void onResume() {
super.onResume();
// register the receiver
registerReceiver(receiver, new IntentFilter("com.example.app.STOP_REFRESH"));
}
#Override
protected void onPause() {
super.onPause();
// unregister the receiver
unregisterReceiver(receiver);
}
then inside your AsyncTask onPostExecute() send the message with the Intent
Intent intent = new Intent("com.example.app.STOP_REFRESH");
// you can also add extras to this intent
// intent.putExtra("key", value);
sendBroadcast(intent);
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.
I have written a simple activity to test out services and broacast receivers and a service to go along with it. In order to know whether or not it's working I've set up a Toast within the main activity to be showed once the OnReceive() method is called. But for the life of me I can't get this to work.
These are the codes:
public class ServicesAndBroadcastIntentActivity extends Activity {
private Toast test;
private Intent intent;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
intent = new Intent(this,serviceD.class);
test = Toast.makeText(this,"Test",Toast.LENGTH_LONG);
test.setGravity(Gravity.CENTER,0,0);
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
test.setText((intent.getStringExtra("EXTRA_MSG")));
test.show();
}
};
#Override
public void onResume(){
super.onResume();
startService(intent);
registerReceiver(broadcastReceiver, new IntentFilter(serviceD.BROADCAST_ACTION));
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(broadcastReceiver);
stopService(intent);
}
}
public class serviceD extends Service{
private Intent intent;
static final String BROADCAST_ACTION = "com.mejg.ServicesAndBroadcastIntent";
public void onCreate() {
super.onCreate();
intent = new Intent(BROADCAST_ACTION);
}
public void onStart(){
intent.putExtra("EXTRA_MSG","hola");
sendBroadcast(intent);
stopSelf();
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
You are calling startService() before registerReceiver(). Both are asynchronous operations, but they will still likely occur in sequence. Hence, onStart() of your service will be called before registerReceiver() does its work, which means your broadcast goes out before your receiver is set up.
For this sort of experimentation, I recommend setting up a basic UI (e.g., one really big button) and doing the startService() call when the button is pressed.
Also, since the service calls stopSelf(), you do not need to call stopService() from the activity.
Also also, you might consider using LocalBroadcastManager for this -- same basic syntax with better performance and security, since it all stays within your process.
UPDATE
Also also also, onStart() has been deprecated for two-plus years, and your method signature for it is wrong, anyway. Please use onStartCommand(), with the right parameters.
Also also also also, use #Override when overriding methods, to help you catch these sorts of problems.
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");
}
}