I just changed my external broadcast receiver class to my service since..some android method could not be used in static context. Now i receive an error Unable to instantiate activity ComponentInfo{com...}: java.lang.NullPointerException. How is it possible to fix? Below is my code for nested BroadcastReceiver class.
public class ServiceX extends Service {
private SharedPreferences settings = getSharedPreferences(PREFS, 0);
private SharedPreferences.Editor editor = settings.edit();
private static void setEnableNotification(int command) {
if (command == 1)
enableNotification = true;
else
enableNotification = false;
editor.putBoolean("enableNotification", enableNotification);
editor.commit();
}
public static class ReceiverX extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int enableNotification = intent.getIntExtra("EnableNotification", 0);
if (enableNotification == 0)
context.
setEnableNotification(0);
else if (enableNotification == 1)
setEnableNotification(1);
}
}
Below is how i instansiated the inner class:
public class ActivityX extends Activity{
private BroadcastReceiver receiver = security365Service.new NotifyServiceReceiver();
Here below is my mainfest which i changed after looking at some sources online:
<receiver android:name="com.milanix.services.ServiceX$ReceiverX" android:enabled="true">
</receiver>
Sorry if my question is dumb.
You cannot use a regular inner class here. It would need to be a static inner class, which will get you back to your original problem. So, you need to solve your "some android method could not be used in static context" problem one way or another.
Related
My Discovery class extends Service class. When I try to get its singletone from other class this way:
Discovery discovery = Discovery.getInstance();
I get a NullPointerException. This is the Discovery code:
public static Discovery getInstance(){
if (discovery == null){
discovery = new Discovery();
discovery.initDiscovery ();
}
Log.i(TAG, "get discovery instance");
return discovery;
}
public Discovery() {
}
private void initDiscovery(){
mDiscoveredDevices = new ArrayList<String>();
BluetoothManager bluetoothManager = (BluetoothManager) discovery.getSystemService(Context.BLUETOOTH_SERVICE);<--NullPointerException
....
}
This is not Android my friend.
To create a service you need to declare it in manifest:
<service
android:name=".DiscoveryService" />
After which you can instantiate it but never using operator new. Instead you need to call:
startService(context, new Intent(context, DiscoveryService.class);
There are other ways of firing a service intent but this will suffice for now.
The service's construction code should be placed at onCreate:
class DiscoveryService extends Service {
#Override
public void onCreate() {
service construction code here
}
}
And its request handling code in onStartCommand:
public int onStartCommand(Intent intent, int flags, int startId) {
handle incoming intent
}
Now, if you do need to access a service instance probably the simplest way
of achieving it would be to declare and maintain a static instance reference within
the service. Do it like this:
class DiscoveryService extends Service {
private static DiscoveryService inst; // <-----------------
public DiscoveryService getInstance() {
return inst;
}
#Override
public void onCreate() {
service construction code here
inst = this;
}
#Override
public void onDestroy() {
cleanup code here
inst = null;
}
}
This approach has its shortcomings, but unlike yours, it will work. Still use with care.
Finally - years of writing & reviewing Android code have led me to the conclusion
that what most novice developers want when they ask for Service, is in fact an IntentService..
Please read the docs and make sure you got your class right.
Good luck.
I have two activities: one is the main (A), and the second one which is started from A (B). I start B with startActivityForResult(intent, id).
I know I can send the result back to A via the setResult() method, but as far as I know, the result isn't sent until finish() is called. I need to send data from B to A without closing B (even several times before closing). Is there a way to achieve that?
As far as I've read, there are not many options to achieve this. I could use SharedPreferences but then I'd need also some kind of event to inform A that it has to read a value!
Any ideas appreciated.
------ FINAL SOLUTION ------
Finally I got it thanks to #Nathaniel Waggoner's advice. Here's what I did:
Inside my activity I declared the extension of BroadcastReceiver:
class ActivityBroadcast extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
final String txt2send = intent.getStringExtra("txt2send");
if ((txt2send != null) && (!txt2send.isEmpty())) {
// Do the needed stuff
...
}
}
}
So now I declared the ActivityBroadcast instance in my class and initialized it:
private static ActivityBroadcast broadcast_signal;
broadcast_signal = new ActivityBroadcast();
The way I control that it's just my Intent the one who triggers the onReceive method is with an IntentFilter set to the SENDTXT2SOCK customized action, this way:
// CustomActions.SENDJOIN2CHAN is just a constant from a customized public class
// where I define my own constants to not interfere with the "official" ones
registerReceiver(broadcast_signal, new IntentFilter(CustomActions.SENDTXT2SOCK));
This way I'm saying that on broadcast_signal will just be registered the CustomActions.SENDTXT2SOCK action, so any other is ignored. Now we just have to send a signal from the desired activity to that receiver:
final Intent intentResult = new Intent(CustomActions.SENDTXT2SOCK);
intentResult.putExtra("txt2send", "blabla");
sendBroadcast(intentResult);
And that's all, works like a charm!
Use broadcasts and intents.
Broadcast Receivers:
http://developer.android.com/reference/android/content/BroadcastReceiver.html
You can also give a shot to OnsharedPreferenceChangelistner
you can use eventBus simple library.
first register eventbus in receiver activity
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
then set a subscriber method
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
then in other activity post your entity like this
EventBus.getDefault().post(new MessageEvent());
You can use broadcasts and observers to call a method of one activity from another activity. You will use an intent to call a broadcast from activity B, and then you will use an observer to call a method in activity A from the broadcast.
For example, if you want to call ActivityA.someMethod from ActivityB, you can do the following (don't forget implements Observer on ActivityA):
public class ActivityA extends AppCompatActivity implements Observer{
//This is the method you want to call from ActivityB
public void someMethod(Intent intent){
//intent will be the Intent object created in ActivityB, you can pass data to this method by setting extras in the intent
}
//Define the observer and broadcast receiver classes
private static class MyObservable extends Observable{
private static final MyObservable instance = new MyObservable();
public void updateValue(Object data){
synchronized(this){
setChanged();
notifyObservers(data); //This method calls ActivityA.update
}
}
}
public static class MyBroadcastReceiver extends BroadcastReceiver{
//This class must be public and static and must be added to the manifest
//To add this class to the manifest in Android Studio put the cursor on the name of the class, press Alt+Enter and choose "Add to manifest"
#Override
public void onReceive(Context context, Intent intent){ //This method will be called when the broadcast is sent from ActivityB
MyObservable.instance.updateValue(intent);
}
}
//Connect the observer to the activity in the onCreate method
#Override
protected void onCreate(Bundle savedInstanceState){
MyObservable.instance.addObserver(this);
//Do everything else in onCreate as usual
}
//This method will be called when the notifyObservers method is called from the oberver
#Override
public void update(Observable observable, Object data){
this.someMethod((Intent) data); //Call the method that you need
}
}
public class ActivityB extends AppCompatActivity{
public void callSomeMethodOnActivityB(){
Intent intent = new Intent(this, ActivityA.MyBroadcastReceiver.class);
//Add some extras to the intent to pass data
sendBroadcast(intent); //Calls ActivityA.MyBroadcastReceiver.onReceive
}
}
Most of this answer is based on ilw's answer to "Communication between BroadcastReceiver and Activity", credits to them.
I have a function with an increment counter and I call it when the user click a button.
I want to make a new button when user press it call this function every second.
I used alarm manager and works fine.But when I try to call this function from broadcast receiver give me error because is not static.What can i do?
public class MyStartServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Send ....",Toast.LENGTH_LONG).show();
//Intent service = new Intent(context, AlarmService.class);
//context.startService(service);
//String msg = intent.getStringExtra("data");
//String msg="data";
a1class.function1();
}
public void function1(){
counter++;
//Toast.MakeText( counter );
}
Either make function1() static or, assuming a1class is the class its in, create an instance of the class and call the function that way
a1class a1class = new a1class();
a1class.function1();
If you want to call a non static method you need a instance of the class to call it on.
You can make a static method that returns the instance like this
private static ClassName instance;
public static ClassName getInstance(){
if (instance == null){
instance = new ClassName();
}
return instance;
}
You can also set the instance in the onCreate method.
I've implemented GCM in my app and I've come across a strange issue.
When my overriding IntentService for GCMBaseIntentService sits in my root package it works fine. I reference it in my manifest with .MyGCMIntentService.
The root package would be com.example.rootpackage
When I move my intent service to a different package, such as com.example.rootpackage.service the intent service is never called. At this point I would update my manifest to point to com.example.rootpackage.service.MyGCMIntentService and no dice.
Am I missing something in Google's documentation on locating it or is this just how it works?
Yes, it should be in the root package :
This intent service will be called by the GCMBroadcastReceiver (which is provided by the GCM library), as shown in the next step. It must be a subclass of com.google.android.gcm.GCMBaseIntentService, must contain a public constructor, and should be named my_app_package.GCMIntentService (unless you use a subclass of GCMBroadcastReceiver that overrides the method used to name the service).
(quote taken from here)
EDIT :
As the documentation says, you can change it if you use a subclass of GCMBroadcastReceiver which overrides getDefaultIntentServiceClassName :
public class GCMBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "GCMBroadcastReceiver";
private static boolean mReceiverSet = false;
#Override
public final void onReceive(Context context, Intent intent) {
Log.v(TAG, "onReceive: " + intent.getAction());
// do a one-time check if app is using a custom GCMBroadcastReceiver
if (!mReceiverSet) {
mReceiverSet = true;
String myClass = getClass().getName();
if (!myClass.equals(GCMBroadcastReceiver.class.getName())) {
GCMRegistrar.setRetryReceiverClassName(myClass);
}
}
String className = getGCMIntentServiceClassName(context);
Log.v(TAG, "GCM IntentService class: " + className);
// Delegates to the application-specific intent service.
GCMBaseIntentService.runIntentInService(context, intent, className);
setResult(Activity.RESULT_OK, null /* data */, null /* extra */);
}
/**
* Gets the class name of the intent service that will handle GCM messages.
*/
protected String getGCMIntentServiceClassName(Context context) {
return getDefaultIntentServiceClassName(context);
}
/**
* Gets the default class name of the intent service that will handle GCM
* messages.
*/
static final String getDefaultIntentServiceClassName(Context context) {
String className = context.getPackageName() +
DEFAULT_INTENT_SERVICE_CLASS_NAME;
return className;
}
}
I am testing a simple widget in android and using Alarms to update a TextView at regular intervals. The problem is that in the BroadcastReceiver class I cannot access the TextView element, which I want to get updated when the alarm expires. The class is being called properly because the Toast i have put there is giving the appropriate message. The following code is from the class where I configure the widget and set the timers.
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if(extras != null){
mWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(WidgetConfigure.this);
RemoteViews views = new RemoteViews(WidgetConfigure.this.getPackageName(), R.layout.widget_layout);
views.setTextViewText(R.id.quote, "Widget Loaded From Activity");
appWidgetManager.updateAppWidget(mWidgetId, views);
setTimer(); //set the timers...
setResult();// set the result...
}
}
Now i want to update the same TextView when the BroadCastReceiver is called after the timer expires. I have tried the code provided in the ExampleAppWidget example provided in android api demos and that isnt working out. How can i set the required text?
You cannot directly change something in an Activity from a BroadcastReceiver. Because when a broadcast receiver get called, the activity maybe not exist. YOu can send messages to an activity (if the activity exists), or if the activity does not exist you can start it and put some flags in Intent
update:
Here is an ugly way:
class YourActivity extends xxxx {
private static YourActivity mInst;
public static YOurActivity instance() {
return mInst;
}
/// Do your task here.
public void setViewText(xxxx) ;
#Override
public void onStart() {
...
mInst = this;
}
#Override
public void onStop() {
...
mInst = null;
}
}
And in your BroadcastReceiver:
YOurActivity inst = YOurActivity.instance();
if(inst != null) { // your activity can be seen, and you can update it's context
inst.setViewText...
}