I'm building an android app that access a server. I'm using a full google solution. The backend is in GAE and I'm using endpoints to expose my API, I'm also using GCM. I use the auto generate tools that are offered by android studio to get my classes.
In my app module I have a class called offer, this is where I put data to be sent to the server, I have also an AsyncTask class that allows to make the api call.
In my backend module I have the exposed API and I also I have a class offer from which the API is generated by android studio and app engine sdk.
Now my problem is I made an attempt, but it resulted in failure, its like the classes in app and backend are not compatible. Whereas they are the same, in fact the one in backend is a simple copy from the one in app, the difference is the "objectify" annotation that I added. Below are pieces from my code and screenshots of my project structure.
public class InsertOfferAsyncTask extends AsyncTask <Offer, Void, Boolean>{
private static OfferApi offer_service;
private Context context;
public InsertOfferAsyncTask(Context context) {
this.context = context;
}
protected Boolean doInBackground(Offer... offer) {
if (offer_service == null) {
OfferApi.Builder builder = new OfferApi.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null)
.setRootUrl("https://flawless-snow-95011.appspot.com/_ah/api/");
offer_service = builder.build();
}
try {
offer_service.insert(offer[0]); //this where I make the actual API call, I know I shouldn't use Object, it was an attempt to make it work
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
This is a part from where I call the AsyncTask, which is the code above.
Log.i("offer", offer.getUsr_id());
Log.i("offer_id", String.valueOf(offer.getId()));
Log.i("offer_date", offer.getPost());
new InsertOfferAsyncTask(getActivity().getBaseContext()).execute(offer);
getActivity().finish();
All the code above is taken from my app module, the following is the endpoint code that code generated, I am posting only the part I make a call to.
#ApiMethod(
name = "insert",
path = "offer",
httpMethod = ApiMethod.HttpMethod.POST)
public Offer insert(Offer offer) {
ofy().save().entity(offer).now();
logger.info("Created Offer with ID: " + offer.getId());
return ofy().load().entity(offer).now();
}
What I need now is how I can use what I have to send my data to the server. I know that I can connect to the server, I tested.
This is the error message, that i get when I try to build.
Error:(233, 73) error: no suitable method found for execute(.model.Offer)
method AsyncTask.execute(Runnable) is not applicable
(actual argument .model.Offer cannot be converted to Runnable by method invocation conversion)
method AsyncTask.execute(backend.model.offerApi.model.Offer...) is not applicable
(argument type app.model.Offer does not conform to vararg element type backend.model.offerApi.model.Offer)
Any help?? should I use JSON (I doubt, the job is done by the auto-generated classes, as it is shown in the builder)
Could it be that you are using two different "Offer" objects
app.model.Offer and backend.model.offerApi.model.Offer?
The type backend.model.offerApi.model.Offer appears to be the one generated for your Endpoints API, you need to use that type everywhere on the client (android) side.
I believe that you should create a separate project that contains all classes that are shared between the android app and your api.
Related
I'm using Expo's SecureStore to securely store a user identification respectively API key.
The app also sets up an Android Service that subscribes to the ACTION_SCREEN_ON intent. In this Service I need to access the API key that I've saved with SecureStore to perform authenticated API calls. What I've tried:
As described by the docs, SecureStore on Android uses SharedPreferences. This way I am able to get a value for the token from the default SharedPreferences, however it's encrypted as it should be.
I tried to use the implementation of SecureStore because I thought all the logic would already be there to get me the decrypted value. However, I'm unable to successfully use the module. getValueWithKeyAsync expects an implementation of ReadableArguments which operates on a Collection<String> and I don't understand where to get it from. Passing a new Collection, of course, misses relevant data.
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(!Intent.ACTION_SCREEN_ON.equals(intent.getAction())) return;
SecureStoreModule secureStoreModule = new SecureStoreModule(context);
Promise tokenPromise = new Promise() {
#Override
public void resolve(Object value) {
// Perform authenticated API call
}
#Override
public void reject(String code, String message, Throwable e) {
...
}
};
ReadableArguments readableArguments = new ReadableArguments() {
// How to correctly implement this or where to get the correct implementation from?
}
secureStoreModule.getValueWithKeyAsync("TOKEN", readableArguments, tokenPromise);
}
I'd appreciate anything guiding me in the right direction. If you can think of other solutions for secure storage in React Native and accessing this secure storage in custom native code, I'm open for suggestions.
We have developed some lambda function and deployed on AWS which are working fine,
Anyhow, client is now planning for AZURE.
They may even switch back to AWS or any other vendor in future.
We have a separate maven project for AWS related stuff.
Hence, our business logic and classes remains same.
What I have done is created a maven project and added individual lambda functions to this project as dependencies.
Then made a factory class which will get impl based on property AZURE or AWS(using class.forName and reflection).
SO, I can switch to Azure by just removing maven dependency and adding AZURE dependency.
According to picture my plan was to create new AzureUtils and AzureWrapper project and Directly use Azure Cloud, by switching cloud in cloudFactory which is present in Generic utils and that would even work hopefully (Not tested) AWS is working anyhow like that.
Now the problem is client does not want everything packed up in 1 jar, i.e no no to all lambdas in a single jar. He want some layer where the switching should take place.
Now Which design patter would be useful, what would be the approach.
Currently my Lambda function looks like below
public class Hello implements RequestHandler<S3Event, Context > {
public String handleRequest(S3Event s3event, Context context) {
.................
call to business processor as in diag
}
}
And azure function looks somewhat like a simple class with annotations
public class Function {
#FunctionName("hello")
public HttpResponseMessage run(
#HttpTrigger(name = "req", methods = { HttpMethod.GET, HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
// Parse query parameter
String query = request.getQueryParameters().get("name");
String name = request.getBody().orElse(query);
if (name != null) {
call to business processor as in diagram
}
}
}
After all this I have only 2 questions
I would like to know first if the design in diagram is right thing to do.
And what my client is asking for a wrapper something magical which should handle both type of cloud implementations. is this even possible?
if possible guide me in right direction
Any help is greatly appreciated.
about you secound question how to handle both type of cloud, please check this 3rd part solution serverless.com. It's a company that create own serverless wrapper, so that you can be free of vendor lock
I'm attempting to compile a Google Cloud Endpoints project in Java, but I'm getting the following error:
There was an error running endpoints command get-client-lib: Object type K not supported.
I don't have any public methods in any of my API classes that take in or return a generic type (K or otherwise), nor any class specifically named K. My body types should all be entity types by the documentation's definitions.
The biggest change I've made recently is that I moved my model (which defines the entity types) to a separate project and I'm including those classes as a JAR dependency.
I'm on the App Engine SDK version 1.9.51 (recently upgraded to this), though using previous versions doesn't seem to change anything. I'm using Gradle with the gradle-appengine-plugin (eventually planning to migrate to the newer app-gradle-plugin).
Any thoughts on why this is happening, and what steps I might take to resolve?
EDIT:
I seem to have isolated the problem, but it hasn't resolved the issue.
I have a list method in my API that returns an object containing a list of other objects. Something like:
public class ListWrapper() implements Serializable {
private List<Object> list;
public List<Object> getList() { return list; }
public void setList(List<Object> list) { this.list = list; }
}
It seems to be this List type which is suddenly the problem. If I remove it from the class, it works fine. If I edit the method to return something else, it works fine. But, in a previous version of the code, this LsitWrapper object existed and was returned exactly as it is and worked fine. What has changed? (Reverting back to earlier versions of the App Engine SDK doesn't seem to help.)
read Where to place the Asynctask in the Application
and http://android-developers.blogspot.com/2009/05/painless-threading.html
Android Studio will generate Endpoint class and Client Libraries for a POJO class with 5 useful methods (get, insert, list, remove, and update).
Attempting these methods on the UI thread is disallowed to protect latency, so calling these methods has to happen on another thread. Many examples show extending AsyncTask as a solution.
For example, I generate endpoints etc for a class called Doctor, and add this private class inside MainActivity in order to add a new Doctor to the database:
private class insertDoctorTask extends AsyncTask<Doctor, Integer, Long> {
protected Long doInBackground(Doctor... ds) {
long res = 1;
try {
Doctor result = endpoint.insertDoctor(ds[0]).execute();
} catch (IOException e) {
e.printStackTrace();
res = 0;
}
return res;
}
}
I will need the same code in other Activities and I'm reluctant to copy and paste it all over the place. What's an elegant way to make this and its companion Tasks (getDoctorTask, listDoctorTask, removeDoctorTask, updateDoctorTask) available to the Activities so that the code is only in one place? And where's the proper place to initialize the endpoint?
Here are a couple of points:
I would tend to keep AsyncTask as private withing the specific Activity, since it is better to link it to the lifecycle of the Activity.
If you are trying to reuse the code in general from different parts (activities) in your Android application, I believe you should look at writing a Service
google docs have a tutorial on how to make an AIDL service. However, when I tried to do the same, I got an error "The method registerCallback(IRemoteInterface) is undefined for the type IRemoteInterface.
I have not seen this "registerCallback" method in any tutorial that I have been googling and my question is why is this not working/why do other places not use it?
I feel like part of my issue is a fundamental misunderstanding about services and their 'callback' to send information to what it is bound to it.
Thanks!
AIDL:
package com.mine.ben;
import com.mine.servicenexus.RelPoint;
interface IRemoteInterface {
Location getLastLocation();
RelPoint getRelPoint();
int logControlActivity(in String text,in int severity);
int getRunningStatus();
}
Updated question:
I get a syntax error in my AIDL file when i add
void registerCallback(IRemoteServiceCallback);
void unregisterCallback(IRemoteServiceCallback);
I have cleaned my workspace and it builds automatically. Is this a problem with the gen file?
Few lines from my application:
interface IGpsService {
Bundle getNavigationMessage();
void resetStatistics();
void recordingEnable(boolean recordingEnabled, boolean continueLastTrack);
void registerCallback(IGpsChanged cb);
void unregisterCallback(IGpsChanged cb);
boolean isRecordingEnabled();
void setGhost(int trackId);
void startGhost();
void sendUserEvent(int eventId);
}
second file for calback interface itself:
interface IGpsChanged{
oneway void onLocationChanged(out Bundle message);
}
Best of all - usually you do not need those .aidl definitions. This is necessary only when exposing service methods outside of the application.
It's also helpful to understand how it works - forst aidl defines basic service's methods. registerCallback is not a "special" method, it's as oridinary as any other, just enables defining callbacks for two-way communication (in this particular case - to send some position info from sesrvice to binded activity (or other component).
As you mentioned in comment - you do not want to create service, just consume some service from outside of application. In that case you need those external aidl file, not the one written by you. Stubs for consuming service's method will be generated in the /gen directory.
google docs have a tutorial on how to make an AIDL service.
That is not a tutorial. It is just ordinary documentation.
However, when I tried to do the same, I got an error "The method registerCallback(IRemoteInterface) is undefined for the type IRemoteInterface.
That is because you do not have a method named registerCallback() in your AIDL.
I have not seen this "registerCallback" method in any tutorial
It is not in a tutorial. The only occurrences of registerCallback() in the Web page that you linked to are from "some sample code demonstrating calling an AIDL-created service, taken from the Remote Service sample in the ApiDemos project". The ApiDemos project is in your SDK installation, if you elected to download sample code from the SDK Manager.
Code example from AIDL guide that you have referenced is taken from the Remote Service sample in the ApiDemos project.
And registerCallback() in it is implemented by using android.os.RemoteCallbackList<E extends android.os.IInterface> object.
Make an .aidl file like:
package com.example;
oneway interface IRemoteServiceCallback {
/**
* Goes to client.
*/
void valueChanged(int value);
}
Make another .aidl file where you import this interface and use it as a method's parameter like:
package com.example;
import com.example.IRemoteServiceCallback;
interface IRemoteService {
/**
* Goes to service.
*/
void registerCallback(IRemoteServiceCallback cb);
}
Generate code from .aidl on both sides.
Implement IRemoteService.Stub in service and return it in onBind()
Implement IRemoteServiceCallback.Stub in client and pass it in ServiceConnection's onServiceConnected() callback to the received from IRemoteService.Stub.asInterface() instance of IRemoteService.
Now you service can talk back to the client over the passed IRemoteServiceCallback implementation.