Android comunicate between library and app - android

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();

Related

How to access data from a Roomdatabase inside a BroadcastReceiver class

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();
}

Xposed - I can print inner class methods, but method hooking doesn't work

I'm trying to hook a method in inner class, but nothing happen, while I can print all the methods of that class.
All of the logs printed except which is in the replaceHookedMethod.
public class Keyguard implements IXposedHookLoadPackage {
#Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
if (!lpparam.packageName.equals("com.android.keyguard"))
return;
XposedBridge.log("we are in keyguard!");
Class HwClockView = XposedHelpers.findClass("com.android.keyguard.AbsClockView$HwClockView",
lpparam.classLoader);
for (Method m : HwClockView.getDeclaredMethods()) {
XposedBridge.log("method: " + m.getName());
}
XposedHelpers.findAndHookMethod(HwClockView, "getDateString",
TimeZone.class, new XC_MethodReplacement() {
#Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("we are in getDateString!");
return String.format("%s", Utils.getPersianDateShort());
}
});
}
Update:
After second comment changed code to this, but same as before nothing happens:
public class Keyguard implements IXposedHookLoadPackage {
#Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
if (!lpparam.packageName.equals("com.android.keyguard"))
return;
XposedBridge.log("we are in keyguard!");
Class HwClockView = XposedHelpers.findClass("com.android.keyguard.AbsClockView$HwClockView",
lpparam.classLoader);
for (Method m : HwClockView.getDeclaredMethods()) {
XposedBridge.log("method: " + m.getName());
if ("getDateString".equalsIgnoreCase(m.getName())) {
XposedBridge.hookMethod(m, new XC_MethodReplacement() {
#Override
protected Object replaceHookedMethod(MethodHookParam param) {
XposedBridge.log("we are in getDateString!");
return String.format("%s", Utils.getPersianDateShort());
}
});
}
}
}
Target class:
public class AbsClockView extends RelativeLayout {
protected Calendar mCalendar;
private HwCustKeyguardStatusViewEx mCustKeyguardStatusViewEx;
protected TextView mDateView;
protected TextView mDescriptionView;
protected Factory mFactory;
protected final AtomicBoolean mFixedTimeZone;
protected FrameLayout mTimeParent;
protected TextView mTimeView;
public interface Factory {
void refreshDate();
void setHwDateFormat();
void updateHwTimeStyle();
}
private class HwClockView implements Factory {
protected Context mContext;
public HwClockView(Context context) {
...
}
private CharSequence getDateString(TimeZone timeZone) {
return someString;
}
}
public AbsClockView(Context context) {
this(context, null);
}
}

My Class in not an enclossing class

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();
// ...
}
}
}

RoboSpice + Google HTTP Client + GSON = failed to parse JSON to object

I'm using RoboSpice with Google HTTP Client & GSON this way:
ApiSpiceService:
public class ApiSpiceService extends GoogleHttpClientSpiceService {
private static final int THREAD_COUNT = 3;
#Override
public CacheManager createCacheManager(Application application) throws CacheCreationException {
CacheManager cacheManager = new CacheManager();
GsonObjectPersisterFactory gsonObjectPersisterFactory = new GsonObjectPersisterFactory(application);
cacheManager.addPersister(gsonObjectPersisterFactory);
return cacheManager;
}
#Override
public int getThreadCount() {
return THREAD_COUNT;
}
}
Request:
public class InfoRequest extends GoogleHttpClientSpiceRequest<Contact> {
private final String url;
public InfoRequest() {
super(Contact.class);
this.url = "some-url/path.json";
}
#Override
public Contact loadDataFromNetwork() throws Exception {
HttpTransport httpTransport = new NetHttpTransport();
HttpRequestFactory httpRequestFactory = httpTransport.createRequestFactory(new InfoHttpRequestInitializer());
HttpRequest httpRequest = httpRequestFactory.buildGetRequest(new GenericUrl(url));
httpRequest.setParser(new GsonFactory().createJsonObjectParser());
return httpRequest.execute().parseAs(Contact.class);
}
private class InfoHttpRequestInitializer implements HttpRequestInitializer {
#Override
public void initialize(HttpRequest request) throws IOException {
}
}
}
Model (Contact.java):
public class Contact {
private String data;
}
BaseActivity:
public abstract class BaseActivity extends ActionBarActivity {
protected SpiceManager spiceManager = new SpiceManager(ApiSpiceService.class);
#Override
protected void onStart() {
super.onStart();
spiceManager.start(this);
}
#Override
protected void onStop() {
spiceManager.shouldStop();
super.onStop();
}
}
And MainActivity:
public class MainActivity extends BaseActivity {
private InfoRequest infoRequest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
infoRequest = new InfoRequest();
}
#Override
protected void onStart() {
super.onStart();
spiceManager.execute(infoRequest, "txt", DurationInMillis.ALWAYS_EXPIRED, new TextRequestListener());
}
private class TextRequestListener implements RequestListener<Contact> {
#Override
public void onRequestFailure(SpiceException spiceException) {
//
}
#Override
public void onRequestSuccess(Contact s) {
//
}
}
It seems to be valid code, but, unfortunately, when it finish the request execution, field data in returned Contact instance is null.
There are no errors in logcat.
The requested content is 100% valid JSON. Why it is not being parsed?
Ok, I've found the solution. I need to add #Key annotation to fields in model. It's strange, because pure Gson does not require this.
public class Contact {
#Key
private String data;
}

issue with calling Fragment class' method

I have a class "HomeActivity", which is as follows:
public class HomeActivity extends FragmentActivity implements OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
// Create the list fragment and add it as our sole content.
if (fm.findFragmentById(android.R.id.content) == null) {
HomeFragment list = new HomeFragment();
fm.beginTransaction().add(android.R.id.content, list).commit();
}
}
public static class HomeFragment extends Fragment {
webServiceTask = WebServiceTask.getInstance(
getActivity(), Constants.METHOD_NAME_PRODUCTS,
Constants.PRODUCT_NAME, null);
public void Work() {}
}
}
I have another class WebServiceTask, which is as follows:
final public class WebServiceTask extends AsyncTask<String, String, String> {
private WebServiceTask(final Activity activity, final String methodName,
final String productName, final String addInfo[]) {
super();
this.activity = activity;
this.methodName = methodName;
this.productName = productName;
this.addInfo = addInfo;
}
public static WebServiceTask getInstance(final Activity activity,
final String methodName, final String productName,
final String additionalInfo[]) {
webServiceTask = new WebServiceTask(activity, methodName, productName,
additionalInfo);
return webServiceTask;
}
protected void onPostExecute() {
// Here I am trying to call the work() method in HomeFragment, How can I do that?
}
My question is how can i call the work() method in HomeFragment class from onPostExecute().
I would propose making a listener for you task, and invoke its method in post execute. It will geve you a lot more flexibility and control on what you want to deafter the task finishes. Here is sample code I would use:
public class MyTask extend AsyncTask<Void, Void, Boolean> {
public interface MyTaskListener {
void onSuccess();
void onFailure();
void onError(Throwable t);
}
private Throwable error;
private MyTaskListener listener;
public MyTask(MyTaskListener listener) {
this.listener = listener;
}
#Overrride
public Boolean doInBackground(Void... params) {
try {
if (workCompleted()) {
//work completed without error - return true
return Boolean.TRUE;
} else {
//work failed to complete - return false
return Boolean.FALSE;
}
} catch(Exception e) {
//unexpected error happened - remember error and return null
this.error = e;
return null;
}
}
#Override
public void onPostExecute(Boolean result){
if (!isCancelled()) { //you only want to process if task wasn't cancelled
if (this.error != null && result == null) { //we have error, process it
if (listener != null) {
listener.onError(this.error);
}
}
if (Boolean.FALSE.equals(result)) { //we have faile, process it
if (listener != null) {
listener.onFail();
}
}
if (Boolean.TRUE.equals(result)) { //we have success
if (listener != null) {
listener.onSuccess();
}
}
}
}
}
And then, in you activit/fragment/service/ use something like this:
public class MyActivity extends Activity {
private void someInstanceMethod() {/ *do your work here */}
#Override
public void onCreate(Bundle savedInstanceState) {
//setup ui, or do whatever you need
//create MyAsyncTask with proper listener
MyAsyncTask task = new MyAsyncTask(new MyAsyncTask.MyAsyncTaskListener() {
#Override
public void onSuccess() {
//call your instance method here
someInstanceMethod();
}
#Override
public void onFailure() {
//process fail
}
#Override
public void onError() {
//process error
}
});
}
}
This is one method. I don't know if it is the best one:
Make work function as public static void. Call it from Asynctask onpostexecute as
HomeActivity.Work();
Edit:
One more way( again not sure if this is the best way):
If you cant make this work, consider putting your asynctask class inside the home activity class
Well using the FragmentManger findFragmentById() or findFragmentByTag() you can get an instance of the current fragment and call your fragment method.
Create an interface file
public interface AsynAction
{
public void Work();
}
Implements AsynAction in HomeActivity
public class HomeActivity extends FragmentActivity implements OnClickListener,AsyncAction {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
// Create the list fragment and add it as our sole content.
if (fm.findFragmentById(android.R.id.content) == null) {
HomeFragment list = new HomeFragment();
fm.beginTransaction().add(android.R.id.content, list).commit();
}
}
public static class HomeFragment extends Fragment {
webServiceTask = WebServiceTask.getInstance(
getActivity(), Constants.METHOD_NAME_PRODUCTS,
Constants.PRODUCT_NAME, null);
#Override
public void Work()
{
}
}
}
Then make changes in you asynctask to receive asyncAction object as reference
final public class WebServiceTask extends AsyncTask<String, String, String> {
private WebServiceTask(final AyscAction asycAction,final Activity activity, final String methodName,
final String productName, final String addInfo[]) {
super();
this.activity = activity;
this.asycAction=asycAction;
this.methodName = methodName;
this.productName = productName;
this.addInfo = addInfo;
}
public static WebServiceTask getInstance(final AyscAction asycAction,final Activity activity,
final String methodName, final String productName,
final String additionalInfo[]) {
webServiceTask = new WebServiceTask(asycAction,activity, methodName, productName,
additionalInfo);
return webServiceTask;
}
protected void onPostExecute() {
// You can call work from here
if(asynAction!=null)
asyncAction.Work();
}

Categories

Resources