I need to access data from my Room database inside a BroadCastReceiver class, but as you know we need a lifecycle owner to get an instance of ViewModel class as shown below.
public class AlertReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NotificationHelper.sendFinanceLoggingNotification(context);
RecurrenceInfoViewModel recurrenceInfoViewModel = new ViewModelProvider(this).get(RecurrenceInfoViewModel.class);
}
}
when passing "this" as the lifecycle owner android studio is throwing error. Can anyone please guide me from where I can get a lifecycle owner inside a BroadCastReceiver or if you can suggest any other way of accessing the data. Below are my ViewModel and Repository classes
public class RecurrenceInfoViewModel extends AndroidViewModel {
private LiveData<List<RecurrenceInfoEntity>> allRecurrenceInfos;
private RecurrenceInfoRepository recurrenceInfoRepository;
public RecurrenceInfoViewModel(#NonNull Application application) {
super(application);
recurrenceInfoRepository=new RecurrenceInfoRepository(application);
}
public void insertRecurrenceInfo(RecurrenceInfoEntity recurrenceInfoEntity) {
recurrenceInfoRepository.insertRecurrenceInfo(recurrenceInfoEntity);
}
public void updateRecurrenceInfo(RecurrenceInfoEntity recurrenceInfoEntity) {
recurrenceInfoRepository.updateRecurrenceInfo(recurrenceInfoEntity);
}
public void deleteRecurrenceInfo(RecurrenceInfoEntity recurrenceInfoEntity) {
recurrenceInfoRepository.deleteRecurrenceInfo(recurrenceInfoEntity);
}
public void deleteAllRecurrenceInfos() {
recurrenceInfoRepository.deleteAllRecurrenceInfo();
}
public LiveData<RecurrenceInfoEntity> getAllRecurrenceInfos(String recurrenceInfoKey) {
return recurrenceInfoRepository.getRecurrenceInfoEntityList(recurrenceInfoKey);
}
}
public class RecurrenceInfoRepository {
private RecurrenceInfoDao recurrenceInfoEntityDao;
private LiveData<List<RecurrenceInfoEntity>> recurrenceInfoEntityList;
public RecurrenceInfoRepository(Context context) {
MoneyManagerDatabase moneyManagerDatabase = MoneyManagerDatabase.getInstance(context);
recurrenceInfoEntityDao = moneyManagerDatabase.getRecurrenceInfoDao();
recurrenceInfoEntityList = recurrenceInfoEntityDao.getAllRecurrenceInfo();
}
public void insertRecurrenceInfo(RecurrenceInfoEntity data) {
new PerformSingleColumnDataOperations(recurrenceInfoEntityDao,
Constants.INSERT_SINGLE_NODE_DATABASE_OPERATION).execute(data);
}
public void updateRecurrenceInfo(RecurrenceInfoEntity data) {
new PerformSingleColumnDataOperations(recurrenceInfoEntityDao,
Constants.UPDATE_SINGLE_NODE_DATABASE_OPERATION).execute(data);
}
public void deleteRecurrenceInfo(RecurrenceInfoEntity data) {
new PerformSingleColumnDataOperations(recurrenceInfoEntityDao,
Constants.DELETE_SINGLE_NODE_DATABASE_OPERATION).execute(data);
}
public void deleteRecurrenceInfo(String type) {
new PerformSingleColumnDataOperations(recurrenceInfoEntityDao,
Constants.DELETE_SINGLE_NODE_DATABASE_OPERATION).execute();
}
public void deleteAllRecurrenceInfo() {
new PerformSingleColumnDataOperations(recurrenceInfoEntityDao,
Constants.DELETE_ALL_NODES_DATABASE_OPERATION).execute();
}
public LiveData<RecurrenceInfoEntity> getRecurrenceInfoEntityList(String key) {
return recurrenceInfoEntityDao.getAllRecurrenceInfo(key);
}
private static class PerformSingleColumnDataOperations extends AsyncTask<RecurrenceInfoEntity, Void, Void> {
private RecurrenceInfoDao dataDao;
private String operationType;
PerformSingleColumnDataOperations(RecurrenceInfoDao dataDao, String operationType) {
this.dataDao = dataDao;
this.operationType = operationType;
}
#Override
protected Void doInBackground(RecurrenceInfoEntity... recurrenceInfoEntities) {
switch (operationType) {
case Constants.INSERT_SINGLE_NODE_DATABASE_OPERATION:
dataDao.insertRecurrenceInfo(recurrenceInfoEntities[0]);
break;
case Constants.UPDATE_SINGLE_NODE_DATABASE_OPERATION:
dataDao.updateRecurrenceInfo(recurrenceInfoEntities[0]);
break;
case Constants.DELETE_SINGLE_NODE_DATABASE_OPERATION:
dataDao.deleteRecurrenceInfo(recurrenceInfoEntities[0]);
break;
case Constants.DELETE_ALL_NODES_DATABASE_OPERATION:
dataDao.deleteAllRecurrenceInfo();
}
return null;
}
}
}
Thanks in advance.
I have solved the above problem by NOT using LiveData.
You can access data from Room anywhere by just providing the ApplicationContext as shown below.
DAO:
#Query("SELECT * FROM reference_info where recurrenceInfoPrimaryKey=:recurrenceinfoprimkey")
RecurrenceInfoEntity getAllRecurrenceInfoWithOutLiveData(String recurrenceinfoprimkey);
Repository:
public RecurrenceInfoEntity getRecurrenceInfoEntityWithOutLiveData(String key) {
return recurrenceInfoEntityDao.getAllRecurrenceInfoWithOutLiveData(key);
}
BroadCastReceiver:
public class AlertReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
new Thread(() -> {
RecurrenceInfoEntity recurrenceInfoEntity =
recurrenceInfoRepository.getRecurrenceInfoEntityWithOutLiveData(Constants.LOG_FINANCES_RECURRENCE_KEY);
}).start();
}
Related
I'm new in android architecture component. this is my code , i'm at the point that I don't know how to notify my activity and get the results back
these are my codes:
Activity:
private void iniViewModels() {
Observer<List<User>>usersObserver=new Observer<List<User>>() {
#Override
public void onChanged(#Nullable List<User> users) {
Log.v("this","LiveData: ");
for (int i=0;i<users.size();i++){
Log.v("this",users.get(i).getName());
}
}
};
mViewModel = ViewModelProviders.of(this)//of-->name of act or fragment
.get(AcActivityViewModel.class);///get -->the name of viewModelClass
mViewModel.mUsers.observe(this,usersObserver);
}
this is my viewModel Class:
public class IpStaticViewModel extends AndroidViewModel {
public LiveData<List<Ipe>> ips;
private AppRepository repository;
public IpStaticViewModel(#NonNull Application application) {
super(application);
repository=AppRepository.getInstance(application.getApplicationContext());
}
public void getIpStatics() {
repository.getStaticIps();
}
}
this is my repository class:
public class AppRepository {
private static AppRepository ourInstance ;
private Context context;
private IpStaticInterface ipInterface;
public static AppRepository getInstance(Context context) {
if (ourInstance == null) {
ourInstance=new AppRepository(context);
}
return ourInstance;
}
private AppRepository(Context context) {
this.context=context;
}
public void getStaticIps() {
ipInterface= ApiConnection.getClient().create(IpStaticInterface.class);
ipInterface.getIpes()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new SingleObserver<IpStaticList>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onSuccess(IpStaticList ipStaticList) {
List<Ipe>ips=ipStaticList.getIpes();
}
#Override
public void onError(Throwable e) {
Log.v("this","Eror "+ e.getMessage());
}
});
}
}
I'm using retrofit for fetching the data ,it fetch the data successfully but I don't know how to notify my activity
can you help me?
Have a MutableLiveData
final MutableLiveData<List<Ipe>> data = new MutableLiveData<>();
In onSucess
public MutableLiveData<List<Ipe>> getStaticIps() {
ipInterface= ApiConnection.getClient().create(IpStaticInterface.class);
ipInterface.getIpes()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new SingleObserver<IpStaticList>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onSuccess(IpStaticList ipStaticList) {
List<Ipe>ips=ipStaticList.getIpes();
data.setValue(ips);
}
#Override
public void onError(Throwable e) {
Log.v("this","Eror "+ e.getMessage());
}
});
return data;
}
In repository expose this to viewmodel
public LiveData<List<Ipe>> getIpStatics() {
return repository.getStaticIps();
}
In Activity you observe the livedata
IpStaticViewModel viewmodel = ViewModelProviders.of(this
.get(IpStaticViewModel.class)
viewModel.getIpStatics().observe(this, new Observer<List<Ipe>>() {
#Override
public void onChanged(#Nullable List<Ipe> ipes) {
if (ipes != null) {
// dosomething
}
}
});
If you want to generalize your response in case you have a error or something have a look at https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/vo/Resource.kt
so I have class constructor:
public class HealthDataStore { // this class is 3rd party api - can't modify
public HealthDataStore(Context context, HealthDataStore.ConnectionListener listener){ /* bla... */ }
/* bla... */
// with Listener Interface:
public interface ConnectionListener {
void onConnected();
void onConnectionFailed(HealthConnectionErrorResult var1);
void onDisconnected();
}
}
and in my repository class i have:
public class HealthRepository {
private string DSConnectionStatus;
public void connectDataStore(HealthDSConnectionListener listener) {
mStore = new HealthDataStore(app, listener);
mStore.connectService();
}
// with inner class:
public class HealthDSConnectionListener implements HealthDataStore.ConnectionListener{
#Override public void onConnected() { DSConnectionStatus = "Connected"; }
#Override public void onConnectionFailed(HealthConnectionErrorResult healthConnectionErrorResult) { DSConnectionStatus = "Connection Failed"; }
#Override public void onDisconnected() { DSConnectionStatus = "Disconnected"; }
};
}
and in my view model class i have below object:
public class SplashViewModel extends AndroidViewModel {
public void connectRepoDataStore(){
// repo is object of class HealthRepository
repo.connectDataStore(mConnectionListener)
// other things to do here
}
private final HealthRepository.HealthDSConnectionListener mConnectionListener = new HealthRepository.HealthDSConnectionListener(){
#Override public void onConnected() {
super.onConnected(); // i need this super to set DSConnectionStatus value
// other things to do here
}
#Override public void onConnectionFailed(HealthConnectionErrorResult error) {
super.onConnectionFailed(error); // i need this super to set DSConnectionStatus value
// other things to do here
}
#Override public void onDisconnected() {
super.onDisconnected(); // i need this super to set DSConnectionStatus value
// other things to do here
}
}
why is private final HealthRepository.HealthDSConnectionListener mConnectionListener = new HealthRepository.HealthDSConnectionListener() throw me error that the class is not enclosing class?
then how should i achieve this? to have my final listener class have capability to set DSConnectionStatus in healthrepository class?
Always try to avoid using inner classes if you know you'll have to extend them. Instead use a separate class, and swap the outer class with a field. If you need to modify a private field that you do not want to expose then create a package-private setter.
public class HealthRepository {
private String DSConnectionStatus;
public void connectDataStore(HealthDSConnectionListener listener) {
mStore = new HealthDataStore(app, listener);
mStore.connectService();
}
void setConnectionStatus(String status) {
DSConnectionStatus = status;
}
}
// create another class in the same package
public class HealthDSConnectionListener implements HealthDataStore.ConnectionListener {
private final HealthRepository repo;
public HealthDSConnectionListener(HealthRepository repo) {
this.repo = repo;
}
#Override public void onConnected() { repo.setConnectionStatus("Connected"); }
#Override public void onDisconnected() { repo.setConnectionStatus("Disconnected"); }
#Override public void onConnectionFailed(HealthConnectionErrorResult error) {
repo.setConnectionStatus("Connection Failed");
}
};
public class SplashViewModel extends AndroidViewModel {
private final HealthRepository repo;
public void connectRepoDataStore() {
// repo is object of class HealthRepository
repo.connectDataStore(mConnectionListener)
// other things to do here
}
private final HealthDSConnectionListener mConnectionListener = new HealthDSConnectionListener(repo) {
#Override public void onConnected() {
super.onConnected();
// ...
}
#Override public void onConnectionFailed(HealthConnectionErrorResult error) {
super.onConnectionFailed(error);
// ...
}
#Override public void onDisconnected() {
super.onDisconnected();
// ...
}
}
}
I am trying to send an update to my Activity from my GCMServiceListener so, I am using RxJava/RxAndroid And created a BusClass for handling sending and Observers
public class ClientBus {
//private final PublishSubject<Object> _bus = PublishSubject.create();
// If multiple threads are going to emit events to this
// then it must be made thread-safe like this instead
private final Subject<Object, Object> _bus = new SerializedSubject<>(PublishSubject.create());
public void send(Object o) {
_bus.onNext(o);
}
public Observable<Object> toObserverable() {
return _bus;
}
public boolean hasObservers() {
return _bus.hasObservers();
}
}
And in my Application Class I did this to initialize the BusClass
private ClientBus clientBus;
public ClientBus getRxBusSingleton() {
if (clientBus == null) {
clientBus = new ClientBus();
}
return clientBus;
}
In the activity I want to receive the message, I registered a CompositeSubscription and get a reference to my ClientBus class from the Application Class
clientBus = ((MyApplication) getApplicationContext()).getRxBusSingleton();
#Override
protected void onStart() {
super.onStart();
initSubscriptions();
}
#Override
protected void onStop() {
super.onStop();
_subscriptions.unsubscribe();
}
void initSubscriptions() {
_subscriptions = new CompositeSubscription();
_subscriptions.add(clientBus.toObserverable().subscribe(new Action1<Object>() {
#Override
public void call(Object event) {
Log.e("New Event", "Event Received");
if (event instanceof MyGcmListenerService.Message) {
String msg = ((MyGcmListenerService.Message) event).getMessage();
if (msg.equals("Update Available")) {
scheduleArrayList = getSchedules();
scheduleAdapter = new ScheduleAdapter(getApplicationContext(), scheduleArrayList, ScheduledUberActivity.this);
scheduledList.setAdapter(scheduleAdapter);
scheduleAdapter.notifyDataSetChanged();
} else if (msg.equals("Refresh")) {
fetchTrips();
}
}
}
}));
}
And from the MyGcmListenerService class I did this when I get a new notification
private void sendRefreshNotif() {
if (clientBus.hasObservers()) {<--It enters the if cause the Log prints. But, the activity doesn't get the message
Log.e("Obervers", "Observers aren't null");
clientBus.send(new Message("Refresh"));
}
}
What I don't understand is why isn't it working here? I use it to interact between activities and fragments. I closed my application to check if the notification comes in, It'll enter this block if (clientBus.hasObservers()) { but it didn't and starting the app and testing the Observer, it notices there's an active Observer. Any help? Thanks.
It seems like you used different instances of the ClientBus class in CompositeSubscription and MyApplication.
Try to make a singleton from ClientBus class, it works fine for me.
public class ClientBus {
public ClientBus(SingletonAccessor accessor) {}
private static ClientBus instance;
private static class SingletonAccessor{}
public static ClientBus getInstance() {
if (instance == null) instance = new ClientBus(new SingletonAccessor());
return instance;
}
private final Subject<Object, Object> mBus = new SerializedSubject<>(PublishSubject.create());
public void send(Object o) {
mBus.onNext(o);
}
public Observable<Object> toObserverable() {
return mBus;
}
public boolean hasObservers() {
return mBus.hasObservers();
}
}
I'm creating a library in Android and I want to pass some values (strings) from the library to the app that is using the library after some events. The app that uses the library has only one screen to display the strings sent by the library.
My app has a MainActivity that will populate an listView with the events received by the library.
It also have an MyApp that extends Application.
Here I'm doing this:
public class MyApp extends Application{
private static MyApp sMyApp;
public MyApp() {
}
#Override
public void onCreate() {
super.onCreate();
sMyApp= this;
MyLibrary.getInstance().setApplication(sMyApp);
}
public static MyApp getInstance() {
return sMyApp;
}
}
In my library:
public class MyLibrary {
private static MyLibrary sInstance = new MyLibrary();
private Application mMyApp;
public static MyLibrary getInstance() {
return sInstance;
}
private MyLibrary() {
}
public void setApplication(Application myApp) {
mMyApp = myApp;
}
public void sendEventMessage(String message) {
mMyApp.setEvent(message);
}
}
I've tried to implement an interface in MainActivity so that mMyApp.setEvent(message); could send a message that MainActivity could receive but with no success.
How can I achieve what I pretend?
You could try callback as this sample:
Firstly, declare your callback inside library
public interface ILibrary {
public void onStart(String msg);
public void onProcess(String msg);
public void onFish(String msg);}
public class SDK {
private static final String START = "I'm started";
private static final String PROCESSING = "I'm running";
private static final String STOP = "I'm done";
private ILibrary mCallback;
// Make it easy for demo
public SDK(ILibrary callback) {
mCallback = callback;
}
public void start() {
mCallback.onStart(START);
}
public void process() {
mCallback.onProcess(PROCESSING);
}
public void stop() {
mCallback.onFish(STOP);
}}
And then do something like that:
SDK sdk = new SDK(new ILibrary() {
#Override
public void onStart(String msg) {
Log.d("TAG", msg);
}
#Override
public void onProcess(String msg) {
Log.d("TAG", msg);
}
#Override
public void onFish(String msg) {
Log.d("TAG", msg);
}
});
AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
sdk.process();
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
sdk.stop();
}
#Override
protected void onPreExecute() {
super.onPreExecute();
sdk.start();
}
};
asyncTask.execute();
How can i make a callback to an Activity form a Java Class?
Example:
public class TestClass{
String text = "Test";
public TestClass(Context context){
startActivity(new Intent(context, SomeActivity.class));
}
private void sendToSomeActivity(){
//Call some method of SomeActivity and pas text as string
}
}
When sendToSomeActivity() is called, i want to make a callback to the already started SomeActivity and pass some text to the Activity. In SomeActivity i want to use the text.
Note: The TestClass object that i want to use is already created in another class.
How can this be done?
The solution I chose is as follows:
Use BroadcastReceivers to communicate between Java classes and Activities.
Example:
public class SomeActivity extends Activity{
private MyBroadcastReceiver receiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
receiver = new MyBroadcastReceiver();
this.registerReceiver(receiver, new IntentFilter(MyBroadcastReceiver.ACTION));
}
#Override
public void onDestroy() {
super.onDestroy();
this.unregisterReceiver(receiver);
}
private class MyBroadcastReceiver extends BroadcastReceiver{
public static final String ACTION = "com.example.ACTION_SOMETHING"
#Override
public void onReceive(Context context, Intent intent) {
String test = intent.getStringExtra("dataToPass");
}
}
}
public class TestClass{
private String test = "TEST";
private Context context;
public TestClass(Context context){
this.context = context;
}
private void sendToSomeActivity(){
Intent intent = new Intent();
intent.setAction(SomeActivity.MyBroadcastReceiver.ACTION);
intent.putExtra("dataToPass", test);
context.sendBroadcast(intent);
}
}
Try this..
public class TestClass{
interface Implementable{
public void passData(String text);
}
Implementable imple;
String text = "Test";
public TestClass(Context context){
startActivity(new Intent(context, SomeActivity.class));
}
private void sendToSomeActivity(){
if(imple != null){
imple.passData(text);
}
}
public void setListener(Implementable im){
imple = im;
}
}
class SomeActivity implements Implementable{
new TestClass().setListener(this);
#override
public void passData(String text){
//here is your text
}
}
In your java class create an interface like this
public class TestClass{
private MyInterface myInterface;
public interface OnSendSomething {
public void onSending(String sendWhateverYouWant);
}
public void setOnSendListener(MyInterface myInterface) {
this.myInterface = myInterface;
}
}
private void sendToSomeActivity(){
//Call some method of SomeActivity and pas text as string
myInterface.onSending(sendWhateverYouWant);
}
And in your activity do something like this:
TestClass tclass = new TestClass(context);
tclass.setOnSendListener(new OnSendSomething () {
#Override
public void onSending(String sendWhateverYouWant) {
//sendWhateverYouWant is here in activity
}
});
You can also visit these links for better understanding.
How to create our own Listener interface in android?
Observer Design Pattern in Java