-1

I have an issue, I need to access views in an activity from a service. I thought a good way to do that was to pass the activity context and then use it to access the views. Yet, when i run it, it throws a null error, meaning the object (the view) is null. This is the code, i would like to know how to fix this:

public class Purchase extends AppCompatActivity {
   private TextView purchaseAmount;
   private Button but;

   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_purchase);
      but = (Button) findViewById(R.id.makePurBut);
      purchaseAmount = (TextView) findViewById(R.id.purchaseAmout);
      Intent i = new Intent(Purchase.this, MyHostApduService.class);
      MyHostApduService myHostApduService = new MyHostApduService(Purchase.this);
      startService(i);
  }
}


public class MyHostApduService extends HostApduService {
static Context context;
   public MyHostApduService(Context context)
   {
      this.context = context;
   }

   public int onStartCommand(Intent intent, int flags, int startId) {
      textView = (TextView)((Activity)context).findViewById(R.id.purchaseAmout);
      but = (Button)((Activity)context).findViewById(R.id.makePurBut);
      return flags;
  }
}
  • 1
    Possible duplicate of [What is a NullPointerException, and how do I fix it?](https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – Zoe Apr 14 '19 at 20:03
  • I'm surprised android even lets you create a service inside a nested class like that - were you able to declare it in your manifest? – PPartisan Apr 14 '19 at 20:10

2 Answers2

2

Service has it's own context, and it can't interact with UI directly.

But you can create bound service or use ResultReceiver. That options described, for example, here: https://medium.com/@ankit_aggarwal/ways-to-communicate-between-activity-and-service-6a8f07275297

For example, to create bound service, as shown in the example:

  1. Add listener interface:
interface Callback {
  void sendMes(Object payload); // or more specific signature
}
  1. In service:
    private final IBinder mBinder = new LocalBinder();

    public class LocalBinder extends Binder {
        List<Callback> listeners;

        LocalService getService() {
            return LocalService.this;
        }
        void addListener(Callback listener) {
             listeners.add(listener);
        }
        void removeListener(Callback listener) {
             listeners.remove(listener);
        }
    } 
  1. In activity (that implements Callback):
private LocalService mBoundService;
private LocalService.LocalBinder mBinder;

private ServiceConnection mConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className, IBinder service) {
        mBinder = ((LocalService.LocalBinder)service);
        mBoundService = ((LocalService.LocalBinder)service).getService();
        ((LocalService.LocalBinder).addListener(MyActivity.this);
    }

    public void onServiceDisconnected(ComponentName className) {
        mBoundService = null;
    } 
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    bindService(new Intent(MyActivity.this, LocalService.class),
                mConnection,
                Context.BIND_AUTO_CREATE);
    mIsBound = true;
}

@Overrride 
public void sendMes(Object payload) { ... }

@Override
protected void onDestroy() {  
 super.onDestroy(); 
 if (mIsBound) {
        mBinder.removeListener(this);
        unbindService(mConnection);
        mIsBound = false;
    }
}
S-Sh
  • 3,564
  • 3
  • 15
  • 19
1

The simplest way to solve your problem would be to use LocalBroadcastManager.

Send a broadcast from Service to Activity, then in onReceive you can manipulate your views within Activity itself.

Make sure to register/unregister a Receiver in onStart/onPause instead of onCreate/onDestroy like inside link.

solidogen
  • 591
  • 5
  • 12