I have a custom title bar used in every activity in my app. I have a broadcast receiver that I want manipulating said title bar,
I have this in my custom application class,
public class MyApplication extends Application {
public static final String ACTION_RESPONSE = "org.company.com.action.MESSAGE_PROCESSED";
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
MyApplication.log("received");
//hide the visible progress dialog spinner in title bar
}
};
public BroadcastReceiver getBroadcastReceiver() {
return receiver;
}
}
I have this in every one of my Activities' onCreate,
MyApplication application = ((MyApplication) getApplication());
registerReceiver(application.getBroadcastReceiver(), new IntentFilter(MyApplication.ACTION_RESPONSE));
What I am trying to do is to find a nice OOP way to do this. I realize that in every activity I can bind a broadcastreceiver that manipulates the view as long as the braodcastreceiver is declared in the activity, but copy pasting that same code 15+ times doesn't make sense to me. Then the next issue is that inside of the MyApplication class, I don't have access to any of the views. Has anyone experienced this issue?
Related
I have an Android app that contains a users list with an Avatar for each user. The avatar image file is stored as a local .png file in the apps cache folder. From time to time, another service updates the avatar png files with more current ones (but in no regular order), and I would like to have my list of avatar ImageView update with the new .png files as they are saved to disk.
I have tried subclassing ImageView and adding a FileObserver property to it, however, this isn't seeming to be the most effective.
Does anyone have any recommendations on how to "live" bind a .png to an ImageView so that it will updates if/when the image file on disk changes?
I'm not sure if I should be looking into DataBinding or not because this seems overkill to me.
You can register BroadcastReceiver at activity and receive notifications from your service.
Firstly, you need to create an implementation of BroadcastReceiver like this:
public class YourBroadcastReceiver extends BroadcastReceiver {
/**
* Listener interface for received broadcast messages.
*/
public interface YourBroadcastListener {
void receivedBroadcast();
}
/**
* The Intent action that this Receiver should filter for.
*/
public static final String ACTION = "com.your.package.IMAGES_UPDATED";
private final YourBroadcastListener mListener;
public YourBroadcastReceiver(YourBroadcastListener listener) {
mListener = listener;
}
#Override
public void onReceive(Context context, Intent intent) {
if (mListener != null)
mListener.receivedBroadcast();
}
}
Next, you need to register YourBroadcastReceiver in your activity:
public class MainActivity extends Activity implements YourBroadcastListener {
private YourBroadcastReceiver mReceiver;
#Override
protected void onResume() {
super.onResume();
if(mReceiver == null){
mReceiver = new YourBroadcastReceiver(this);
registerReceiver(mReceiver, new IntentFilter(YourBroadcastReceiver.ACTION));
}
}
#Override
protected void onPause() {
super.onPause();
if(mReceiver != null){
unregisterReceiver(mReceiver);
mReceiver = null;
}
}
#Override
public void receivedBroadcast() {
// Received a broadcast notification that the images has changed - reload it
}
}
And the last, your service need to send brodcast notifications to your activity:
Intent i = new Intent("com.your.package.IMAGES_UPDATED");
sendBroadcast(i);
Take a note: your action string need to be unique to avoid collisions with another applications.
The application that I'm working on has an activity with three fragments. Each fragment needs to show some data that is received from an IntentService.
Fragment 1 - the icon, the name and the description
Fragment 2 - a list of articles
Fragment 3 - a list of items
public class Activity extends SherlockFragmentActivity implements Actionbar.Tablistener
{
public void onCreate(..) {
....
performSearch();
setupTabs(); // 3 tabs are setup, their clicks and swipes init'ed
...
}
#Override
public void onResume() {
IntentFilter intentFilter = new IntentFilter(SearchRequestReceiver.ACTION);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
searchRequestReceiver = new SearchRequestReceiver(this);
registerReceiver(searchRequestReceiver, intentFilter);
}
#Override
public void onPause() {
unregisterReceivers();
}
...
public void performSearch() {
Intent intent = new Intent(this, SearchRequest.class);
intent.putExtra("searchTerm", this.searchTerm); // declared and initialised earlier
startService(intent);
}
...
}
What is the best way for me to push this data from my receiver to my fragments or am I approaching this the wrong way? I didn't use AsyncTasks because I wanted to decouple my services from the context or was that the wrong decision?
An EventBus is one of the neatest solutions in this situation. EventBus and Otto are both very easy to use.
An example using Otto...
Your IntentService
new Handler(Looper.getMainLooper()).post(new Runnable() {
bus.post(new DataLoadCompleteEvent());
});
Note the necessity to post the event on Android's main thread with Otto. In this case, a DataLoadCompleteEvent could contain whatever you wanted.
Your Fragment
#Subscribe public void onLoad(DataLoadCompleteEvent event) {
//Do stuff with event
}
Just make sure your Fragments register on the bus in their onResume(), and unregister in their onPause().
I've managed to get it working by having the different receivers within my fragments but it seems like an awful lot of repetition.
public class FragmentName extends SherlockFragment
{
private SearchRequestReceiver searchRequestReceiver;
..
public class ServiceRequestReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
...
}
}
}
Is there a better way?
I was wondering how to keep a record of launched activites for logging purposes. what broadcast receiver I have to subscribe to intercept this intent? or what intent-filter to use? I figure that I must use some type of long-running service in the background.
My first objetive is to track main-focus applications, some sort of history.
Want to get finally some similar to:
- Launched app com.android.xxx
- Launched app xx.yy.zz
- App xx.yy.zz lost focus
Thanks in advance
EDIT - Just see that app MyAppRank , that does exactly what i mean
What i'm able to figure out from your question is that you want to keep track of all the activities when they are launched in your application. If that is correct, the solution may work for you:
Crate a BaseActivity which all of your Activities should extend
public class BaseActivity extends Activity
{
private Activity activity;
public static final String INTENTFILTER_TRACK_MY_ACTIVITIES="INTENTFILTER_TRACK_MY_ACTIVITIES";
public static final String INTENTFILTER_REMOVE_MY_ACTIVITIES="INTENTFILTER_REMOVE_MY_ACTIVITIES";
public void setActivity(Activity act)
{
activity = act;
}
public Activity getActivity()
{
return activity;
}
#Override protected void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
Intent intent = new Intent();
intent.setAction(INTENTFILTER_TRACK_MY_ACTIVITIES);
intent.putExtra("activityName", activity.getClass().getSimpleName());
sendBroadcast(intent);
}
#Override protected void onDestroy()
{
// TODO Auto-generated method stub
super.onDestroy();
Intent intent = new Intent();
intent.setAction(INTENTFILTER_REMOVE_MY_ACTIVITIES);
intent.putExtra("activityName", activity.getClass().getSimpleName());
sendBroadcast(intent);
setActivity(null);
}
}
Now extend above BaseActivity for all your activities. i.e instead of extending your Activities should extend BaseActivity and call setActivity(this); in onCreate like below:
public class MyActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setActivity(this);
//write your other code form here
}
}
3.Then write a BroadcastReceiver like below:
class TrackActivitiesReceiver extends BroadcastReceiver
{
private static final Object SEPERATOR = ",";// use , as seperator
String sb="";
#Override
public void onReceive(Context context, Intent intent)
{
if(intent.getAction().equalsIgnoreCase(BaseActivity.INTENTFILTER_TRACK_MY_ACTIVITIES))
{
sb+=intent.getStringExtra("activityName");
sb+=SEPERATOR;
}
else if(intent.getAction().equalsIgnoreCase(BaseActivity.INTENTFILTER_REMOVE_MY_ACTIVITIES))
{
sb=sb.replace(intent.getStringExtra("activityName")+SEPERATOR, "");
}
}}
4Finally, Register above Receiver in your AndroidManifest.xml
<receiver
android:name="TrackActivitiesReceiver"
android:exported="false" >
<intent-filter>
<action android:name="INTENTFILTER_TRACK_MY_ACTIVITIES" />
</intent-filter>
</receiver>
Hope this solves your problem. cheers!
There are no Intents broadcast when applications are started or when applications come to the foreground. There isn't anything that you can hook into as a listener to get these events.
The way you can do this (which is the way apps like MyAppRank do it) is to use the methods of the ActivityManager:
getRunningTasks()
getRunningAppProcesses()
getRecentTasks()
You create a Service which runs all the time and at regular intervals calls methods of the ActvityManager to determine which task is in the foreground and you can "infer" what the user has done (or is doing). It isn't an exact science.
Note: You will need android.permission.GET_TASKS and none of this works anymore as of API 21 (Android 5, Lollipop). As of API 21 the security has been tightened and an application can only get information about its own tasks, not other tasks in the system.
I have several activities which use several audio features. For that, I have a MediaPlayer in a singleton java class, so the activities interact with that class and just exist on the media player.
One of the features is to stop automatically the media player after X minutes. So I created a timer in the singleton class and stops perfectly the radio streaming. the problem is that there is no feedback or callback to the running activity. There is a play/stop button wich has to change the image and I do not know how can I capture that onStop event or whatever....or can be called from a single java class the current activity class running, so I could call a function of the activity in order to change the image?
You probably want to use a broadcast receiver for this.
From your singlton class which does the stopping, when your timer stops the music, call this method:
public void broadcastMusicPaused(View v){
Intent broadcast = new Intent();
broadcast.setAction("MUSIC_STOPPED");
sendBroadcast(broadcast);
}
Then, from your controlling activity, set up your receiver like this:
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "Music Paused", Toast.LENGTH_SHORT).show();
displayMusicStopped(); //switches images
}
};
#Override
protected void onResume() {
IntentFilter filter = new IntentFilter();
filter.addAction("MUSIC_STOPPED");
registerReceiver(receiver, filter);
super.onResume();
}
#Override
protected void onPause() {
unregisterReceiver(receiver);
super.onPause();
}
First of all, thanks jameo for his answer, sounds pretty good, but i do not know if i will have time to try, i promise i will if i can this week or next time i have a similar issue.
Finally i did the trick this way:
1 - Create a Interface with Method onStopMediaPlayer(); //For example call MediaPlayerStopInterface
public interface MediaPlayerStopInterface {
/**
* Called when the player timer ends
*/
public void onStopMediaPlayer();
}
2 - My activities classes implements the interface switching images.
public class PortadaActivity extends Activity implements MediaPlayerStopInterface{
public void onStopMediaPlayer(){
//Switch images or whatever
}
}
3 - My singletton class has an object of the type of the interface MediaPlayerStopInterface
public class AudioControllerClass { //The Singletton Java Class
private MediaPlayerStopInterface currentActivity;
public void setCurrentActivity(MediaPlayerStopInterface mpsi){
currentActivity=mpsi;
}
}
4 - My activities classes in onResume() do a Singlettonclass.setStoppedPlayerInterface(this), so i always have a reference of the running activitie.
public class PortadaActivity extends Activity implements MediaPlayerStopInterface{
public void onResume() {
AudioControllerClass.getInstance(getApplicationContext()).setCurrentActivity(this); //In every resume the singletton class knows who was the last one in being active
}
}
5 - when timer execute, as i have the activitie class reference, i just call object_StoppedPlayerInterface.stoppedPlayer();
public class AudioControllerClass { //The Singletton Java Class
class TimerRadio extends TimerTask {
public void run() {
if(whatever==true){
currentActivity.onStopMediaPlayer();
}
}
}
}
Finally, i didn't code it, but the callback to onStopMediaplayer in activities must be done with a Handler, if you do not want a "Only UI thread can touch his views" exception :P
It works perfectly :). But i don't know if it is a really bad practice or is not so horrible xD
Anyway thanks Jameo. Yours sound much more elegant :P
I have a parent application with this:
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//hide view
}
};
each activity has a reference to the parent application after casting getApplication. So in each activity I'm binding the receiver like this:
registerReceiver(application.getBroadcastReceiver(), new IntentFilter(MyApplication.ACTION_RESPONSE));
How can I hide a view, which is used globally within a title bar, using calls within the listed onReceive method?
You can save the current activity's context in application class, let say in CurrentActivity variable. Then use this context to hide the views of current activity.