I have added a BroadcastReceiver in my manifest file to detect the network changes. Here is the class that extends BroadcastReceiver.
public class NetworkConnectivityReceiver extends BroadcastReceiver {
static FirstService firstService;
public static void initServiceObj (FirstService serviceObj) {
if (serviceObj == null) {
CommonUtils.printLog("service obj is null.. returing");
return;
}
CommonUtils.printLog("setter called for serviceObj");
firstService = serviceObj;
}
public void onReceive(Context context, Intent intent) {
if (firstService == null) {
CommonUtils.printLog("service obj is null in onreceive.. returing");
return;
}
firstService.onNetworkChange();
}
}
I am starting a service called FirstService and in onCreate of that service I call the static method initServiceObj to init the FirstService obj. I see from the logs that the object is set. But when the network changes then in onReceive I find the service object to be null. Why is the static variable becoming null in onReceive? Any help is appreciated.
Probably I was using the wrong approach. As suggested in the comments Now I call startService with an intent with a flag set, and in my on onStartCommand I check for that flag. If the flag is set then I simply call onNetworkChange(). That solved the problem for me.
Inside my activity I have a broadcast receiver that I initialize as such:
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateViews();
}
};
updateViews() is a function inside the activity that is only used within the broadcast receiver. How can I create this receiver as a separate class that can play with the views (rotate, delete etc.) of my activity?
In addition, I have a compass within the activity. It works, however I would also like to make the compass a separate class that can send data to the activity. It will not change the views of the activity but only update certain double/float values.
#Override
public void onSensorChanged(SensorEvent event) { }
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
How can I create this receiver as a separate class...?
This answer assumes that "separate class" means you want a BroadcastReceiver that is defined in its own source file and is not an inner class of an activity. Before offering a solution, I'll ask, what do you expect to gain by this? Do you have multiple activities that will use the receiver? If not, it's best to leave it as an inner class of the single activity that uses it. If you don't like using the anonymous inner class in the code you posted, you can declare is as an inner class:
private class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// As an inner class of the activity, this receiver has
// access to all activity members.
updateViews();
}
}
If you really want it as a standalone receiver, the example code below is a starting point. Be sure to register/unregister the receiver in your activity's onResume/onPause callbacks. The example includes code for a less safe approach, using a plain activity reference, and a safer approach using a weak reference. Only one is needed.
public class MyBroadcastReceiver extends BroadcastReceiver {
// For less safe use
private MyClientActivity mActivity;
// For more safe use
private WeakReference<MyClientActivity> mActivityRef;
public MyBroadcastReceiver(MyClientActivity activity) {
mActivity = activity;
mActivityRef = new WeakReference<MyClientActivity>(activity);
}
#Override
public void onReceive(Context context, Intent intent) {
// Less safe
mActivity.findViewById(R.id.action_bar);
mActivity.someActivityMemberMethod();
// etc
// More safe. Guards against failure to unregister
// this receiver when activity is paused.
MyClientActivity act = mActivityRef.get();
if (act != null && !act.isDestroyed()) {
mActivity.findViewById(R.id.action_bar);
mActivity.someActivityMemberMethod();
// etc
} else {
// Error: Activity failed to unregister this receiver
}
}
}
I would also like to make the compass a separate class that can send
data to the activity
Same assumption and question as above: Will the compass be used by multiple activities? If not, it's probably best to make it an inner class of the single activity. If there are multiple client activities, consider using a started-service. It could notify activities of sensor events using a local broadcast or an event bus such as greenrobot.
Good day,
I have my main activity with an object,
public Network netConnection = null;
in my main activity i then call:
netConnection = new Network(new Network.OnMessageReceived() {
#Override
// here the messageReceived method is implemented
public void messageReceived(String message) {
// this method calls the onProgressUpdate
publishProgress(message);
}
});
netConnection.run();
Now i create a new activity and i run it with this code:
case R.id.menu_packet: {
Intent intent = new Intent(this, PacketActivity.class);
String id = "" + hashCode();
intent.putExtra("id", id);
startActivity(intent);
return true;
}
I have tried doing things with putExtra() in the intent etc. But i have not come right.
Is there not an easy way to just pass a reference to PacketActivity of my netConnection ?
I don't want to copy it or any thing. just be able to access the netConnection object from the PacketActivity?
Thanks
You can extend Application, create setter and getter method in your extended application, and then call it from new activity.
here a tutorial
useful links:
Extending Application
Extending Application to share variables globally
Android extends Application basics
e.g.
public class myApplication extends Application{
private myType myObj;
public void set_myObj(myType theThing){
myObj = theThing;
}
public myType get_myObj(){
return myObj;
}
}
then from you main activity:
((myApplication)getApplication()).set_myObj(myObj);
and from second activity:
myType myObj = ((myApplication)getApplication()).get_myObj();
and be careful with memory leaks..!
This sounds like a use case for a service:
http://developer.android.com/reference/android/app/Service.html
The thing is once the activity from which you created the Network object is destroyed e.g. to launch the new Activity then the Network object will also be garbage collected so I don't think passing a reference would help...
I often find myself needing to access methods that require referencing some activity. For example, to use getWindowManager, I need to access some Activity. But often my code for using these methods is in some other class that has no reference to an activity. Up until now, I've either stored a reference to the main activity or passed the context of some activity to the class. Is there some better way to do this?
If you already have a valid context, just use this:
Activity activity = (Activity) context;
Passing context is better way for refrence Activity.
You can pass Context to another class.
IN Activity ::
AnotherClass Obj = new AnotherClass(this);
IN Another Class
class AnotherClass{
public AnotherClass(Context Context){
}
}
You can implement the necessary methods in your activity and implement a Handler. Then, simply pass a handler instance to your classes, where you can obtain a message for handler and send it to target.
You can make you application instance a singleton, and use it when you need a Context
An example is in this question:
Android Application as Singleton
This way, when you need a Context, you can get it with
Context context = MyApplication.getInstance()
This might not be the cleanest solution, but it has worked well for me so far
I found a way to get the Activity to a non-activity class that I have not seen discussed in forums. This was after numerous failed attempts at using getApplicationContext() and of passing the context in as a parameter to constructors, none of which gave Activity. I saw that my adapters were casting the incoming context to Activity so I made the same cast to my non-activity class constructors:
public class HandleDropdown extends Application{
...
public Activity activity;
...
public HandleDropdown() {
super();
}
public HandleDropdown(Activity context) {
this.activity = context;
this.context = context;
}
public void DropList(View v,Activity context) {
this.activity = context;
this.context = context;
...
}
After doing this cast conversion of Context to Activity I could use this.activity wherever I needed an Activity context.
I'm new to android so my suggestion may look guffy but what if you'll just create a reference to your activity as private property and assign that in OnCreate method? You can even create your CustomActivity with OnCreate like that and derive all your activities from your CustomActivity, not the generic Activity provided by android.
class blah extends Activity{
private Activity activityReference;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityReference = this;
}
}
after that you could use that the way you want, i.e. in
Intent i = new Intent(activityReference, SomeOtherActivity.class)
etc
There are many ways for Activities communication.
you can use:
the startActivityForResult method
a system of broadcast message and receiver (you can broadcast an event from the actual activity, and register a receiver in the target activity. Remember that the target activity must be previously initialized and non finished)
as you say, store a reference of the target activity wherever you need.
We built a framework for this. We have a BaseActivity class that inherits from Activity and it overrides all the lifecycle methods and has some static (class) variables that keep track of the activity stack. If anything wants to know what the current activity is, it just calls a static method in BaseActivity that returns the activity on top of our privately-managed stack.
It is kinda hacky, but it works. I'm not sure I would recommend it though.
Handle the Intent in the class you want to do these methods, and send your information to it in a Bundle like so:
Intent i = new Intent("android.intent.action.MAIN");
i.setComponent(new ComponentName("com.my.pkg","com.my.pkg.myActivity"));
Bundle data = new Bundle();
i.putExtras(data);
startActivityForResult(i);
Then use an OnActivityResultListener to grab the new data.
I solved this by making a singleton class has an instance of the class below as a member.
public class InterActivityReferrer <T> {
HashMap<Integer, T> map;
ArrayList<Integer> reserve;
public InterActivityReferrer() {
map = new HashMap<>();
reserve = new ArrayList<>();
}
public synchronized int attach(T obj) {
int id;
if (reserve.isEmpty()) {
id = reserve.size();
}
else {
id = reserve.remove(reserve.size() - 1);
}
map.put(id, obj);
return id;
}
public synchronized T get(int id) {
return map.get(id);
}
public synchronized T detach(int id) {
T obj = map.remove(id);
if (obj != null) reserve.add(id);
return obj;
}
}
This class can get a T object and return a unique integer assigned to the object by attach(). Assigned integers will not collide with each other unless HashMap fails. Each assigned integer will be freed when its corresponding object is detached by detach(). Freed integers will be reused when a new object is attached.
And from a singleton class:
public class SomeSingleton {
...
private InterActivityReferrer<Activity> referrer = new InterActivityReferrer<>();
...
public InterActivityReferrer<Activity> getReferrer() {return referrer;}
}
And from an activity that needs to be referred:
...
int activityID = SomeSingleton.getInstance().getReferrer().attach(this);
...
Now with this, a unique integer corresponding to this activity instance is returned. And an integer can be delivered into another starting activity by using Intent and putExtra().
...
Intent i = new Intent(this, AnotherActivity.class);
i.putExtra("thisActivityID", activityID);
startActivityForResult(i, SOME_INTEGER);
...
And from the another activity:
...
id refereeID = getIntent().getIntExtra("thisActivityID", -1);
Activity referredActivity = SomeSingleton.getInstance().getReferrer().get(refereeID);
...
And finally the activity can be referred. And InterActivityReferrer can be used for any other class.
I hope this helps.
public static Activity getLaunchActivity()
{
final Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
final Method methodApp = activityThreadClass.getMethod("currentApplication");
App = (Application) methodApp.invoke(null, (Object[]) null);
Intent launcherIntent = App.getPackageManager().getLaunchIntentForPackage(App.getPackageName());
launchActivityInfo = launcherIntent.resolveActivityInfo(App.getPackageManager(), 0);
Class<?> clazz;
try
{
clazz = Class.forName(launchActivityInfo.name);
if(clazz != null)
return Activity.class.cast(clazz.newInstance());
}
catch (Exception e)
{}
return null;
}
Just a guess since I haven't done this but it might work.
1) Get your applicationContext by making your Android Application class a Singleton.
2) Get your ActivityManager class from the context.
3) Get a list of RunningTaskInfos using getRunningTasks() on the ActivityManager.
4) Get the first RunningTaskInfo element from the list which should be the most recent task launched.
5) Call topActivity on that RunningTaskInfo which should return you the top activity on the activity stack for that task.
Now, this seems like a LOT more work than any of the other methods mentioned here, but you can probably encapsulate this in a static class and just call it whenever. It seems like it might be the only way to get the top activity on the stack without adding references to the activities.
I have a static function that gets called whenever my background service gets a new location. In this function I want to take to coordinates passed in and save them in my database. Can I pass 'null' as the context to create an instance of the database helper or is there a better way to do this. Thanks.
public static void locationHasChanged() {
final wd_DatabaseHelper helper = new wd_DatabaseHelper(null, "myDB.db", null, 1);
}
Probably not. Usually your Database helper extends SQLiteOpenHelper and the context will be used to call the openOrCreateDatabase() or the getDatabasePath(). I can't say for sure without seeing the code of wd_DatabaseHelper but having a null context is never a good idea. See for your self ... Source of SQLiteOpenHelper
since an android Service is a context you can pass "this of the service" into your method
public class MyLocationHelper {
public static void locationHasChanged(Context context) {
final wd_DatabaseHelper helper = new wd_DatabaseHelper(context, "myDB.db", null, 1);
....
}
}
public class MyService extends Service {
private void onLocationHasChanged()
{
MyLocationHelper.locationHasChanged(this);
}
}