I'm using Google's mobile backend starter for a project and I want to set the key name myself for some of entities instead of using the auto-generated one.
If I were doing this without the backend I could do something like it describes in the datastore documentation which creates an employee entity with the key name "asalieri":
Entity employee = new Entity("Employee", "asalieri");
Here's the code I'm using to create the entity. I've been trying to use the CloudEntity.setId() function. Upc is a string and it doesn't work when I use a hardcoded string either.
CloudEntity avg = new CloudEntity("Aggregate");
avg.setId(upc);
avg.put("averagePrice", sum/count);
insertAverage(avg);
private void insertAverage(CloudEntity avg) {
CloudCallbackHandler<CloudEntity> handler = new CloudCallbackHandler<CloudEntity>() {
#Override
public void onComplete(final CloudEntity result) {
Toast.makeText(AddProduct.this, "Average updated.", Toast.LENGTH_LONG).show();
}
#Override
public void onError(final IOException exception) {
handleEndpointException(exception);
}
};
// execute the insertion with the handler
getCloudBackend().insert(avg, handler);
}
When I run the app everything works fine except that the new entity doesn't have the custom ID that I set.
The only thing I can think of is that setId() isn't supposed to do what I think it does but I've been digging through the code and haven't been able to find another way to do what I want.
Does anyone know why this isn't working?
I'm a Googler on the MBS project. I recreated your issue and first glance shows this as a bug on our side. I'll edit my response with updates.
Would this workaround be ok until we push a fix?
avg.put("samId", upc)
Related
while observing the upload function that sets Ids for pictures in some table I need to set those Ids for profilePictreId and wallpaperPictureId properties. I didn't find any solutions and flatMap or other functions were too hard to understand. I can get the ids as I mentioned below but I need them to be saparated so I can put them in different fields. either give me a solution or a good document.
don't worry about other functions in code I only need the separation function for Rx while subscribing. thank you
More Explain:
after uploading I need two properties to be set but I only should do it in subscribing method onSuccessUpload. I tried many ways but I get both Ids set to profilePictureId and wallpaperPictureId that is a problem they should be separated.
response for s1 variable:
E/PictureIds###>>>: [4e6a3956bf8743b78fe4ffa546f627f0.png]
E/Utils: {"attachments":"4e6a3956bf8743b78fe4ffa546f627f0.png","status":"SUCCESS","message":"-"}
E/PictureIds###>>>: [7712b7f081d045e8b94f077e40994290.png]
E/Utils: {"attachments":"7712b7f081d045e8b94f077e40994290.png","status":"SUCCESS","message":"-"}
private Disposable picture; // this varaibale is set in onSuccessUpload to subscribe
private void onSuccessUpload(){
setPicture(RxBus.sendResponseUploadLink()
.subscribe(s1 -> {
String[] id = new String[]{s1.getString("attachments")};
Timber.tag("PictureIds###>>>").e(Arrays.toString(id));
setProfilePictureId(id[0]); // problem is here
setWallpaperPictureId(id[1]); // problem is here
}));
}
private void uploadPicture(String path){
Upload uploadPicture = new Upload();
uploadPicture.upload(getToken(), path);
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.channel_profile_image:
selectProfileImage();
break;
case R.id.channel_cover_image:
selectCoverImage();
break;
case R.id.submit_social_channel:
onSuccessUpload();
uploadPicture(getProfileFilePath());
uploadPicture(getWallpaperFilePath());
}
}
The subscribe function returns a Subscription object that allows you to manage the created relationship between the observable and the subscriber.
You have only one subscriber so the best thing you can do is to add imageType in your API response like,
{
"attachments":"4e6a3956bf8743b78fe4ffa546f627f0.png",
"imageType":"Wallpaper"
"status":"SUCCESS",
"message":"-"
}
so in the subscriber you can differentiate between your uploaded images and call different functions accordingly.
I have created an app which is relied on my local server which fetch profile image and information about user..Code works fine without any problem but when I change my data in the local server (for example profile picture )the updated profile is not reflecting in the application until activity is restarted but this should not be happened because live data should reflect the change immediately as soon as changes occurred in the database.
below is the code of live data class
private MutableLiveData<Profile> profileMutableLiveData;
public void init(String token){
if (profileMutableLiveData!=null){
return;
}
repository=Repository.getInstance();
profileMutableLiveData=repository.getProfile(token);
}
public LiveData<Profile> getProfile(){
return profileMutableLiveData;
}
here is my Repository code
public class Repository {
private static Repository instance;
public static Repository getInstance(){
if (instance==null){
instance=new Repository();
}
return instance;
}
public MutableLiveData<Profile> getProfile(String token){
MutableLiveData<Profile> data=new MutableLiveData<>();
RetrofitApi retrofitApi=RetrofitInstance.getInstance();
Call<Profile> call=retrofitApi.getProfile(token);
call.enqueue(new Callback<Profile>() {
#Override
public void onResponse(Call<Profile> call, Response<Profile> response) {
Profile profile=response.body();
if (response.isSuccessful()){
data.setValue(profile);
}
}
#Override
public void onFailure(Call<Profile> call, Throwable t) {
}
});
return data;
}
}
Code in main activity to observe changes....
actually I am showing profile image in navigation drawer ... like telegram app
viewModelClass = new ViewModelProvider(this).get(ViewModelClass.class);
viewModelClass.init(token);
viewModelClass.getProfile().observe(this, new Observer<Profile>() {
#Override
public void onChanged(Profile profile) {
Picasso.get().load("http://192.168.43.216:8000" + profile.getProfile_photo()).into(profileImage);
fName = profile.getFirst_name();
lName = profile.getLast_name();
image = profile.getProfile_photo();
nameView.setText("Hello " + profile.getFirst_name());
}
});
}
The code is working fine but I want the data must be updated as soon as changes made in my server...
but data is updated when I restart the activity or opening app again after closing the activity...
May be the problem - is that you begin to observe in your activity one instance of MutableLiveData, and then you replace it with another one.
In your ViewModel:
profileMutableLiveData=repository.getProfile(token);
you override it instead of setting new value with "postValue"
In your Repository:
MutableLiveData<Profile> data=new MutableLiveData<>();
you make another instance of LiveData
You can try to change your return value from a Repository to a "Profile" and set it as a new value of MutableLiveData in your ViewModel with "postValue"
UPDATED
I've read your question more carefully. I think my answer above wouldn't give you what you expect (in case you expect Retrofit should update LiveData instantly like ROOM does)
So my thoughts:
You expect too much using LiveData+Retrofit. Just using them doesn't mean you'll get on-line updates of your data on your server. To achieve that you have to change mechanism of your interaction with your server, not just fix few lines in code you've shown.
There is mechanism LiveData+ROOM that works with local DB (Sqlite) in a way, that you expect from LiveData+Retrofit. But there is no magic there. Room is using mechanic, that built-in in Sqlite for notifying (triggering) when there are some changes in DB tables occur. But Retrofit doesn't implement similar mechanism with Rest Api and actually it's not its responsibility.
To achieve what you want you can look at several possibilities:
To use some Cloud Service API, that contains that built-in mechanism for notifying your device when data changes (Firebase, for example)
To implement some kind of periodic synchronisation of your app data with server. After this synchronisation you'll have all data on device and depending on where you put your data you could observe changes with LiveData+Room or FileObserver.
To simplify your case and refresh your data from the server at activity explicitly after click on Button "Refresh" on your activity. In that case you can implement steps that I wrote at first version of my answer.
I am implementing an Android app that is responsible for some data exchange with other services such as credentials. I then want to use that information to automatically fill in the input fields of other applications on the device such as Spotify.
Is there any way to fill the input fields of another app, like the username and password to remove the chore for the user to manually input it?
Also I noticed that at least on iOS, Spotify recognizes 1Password to be installed and displays a small icon next to the input fields with which I can fill the fields from the data stored in 1Password - how is this done as it seems to be another solution to my problem?
Thanks in advance
You might want to implement Autofill Service https://developer.android.com/guide/topics/text/autofill-services.html
There is a ready to use sample app which will get you started https://github.com/googlesamples/android-AutofillFramework
Android will invoke onFillRequest() method giving your service a chance to show autofill suggestions. Here is a sample code from above link:
#Override
public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal, FillCallback callback) {
// Get the structure from the request
List<FillContext> context = request.getFillContexts();
AssistStructure structure = context.get(context.size() - 1).getStructure();
// Traverse the structure looking for nodes to fill out.
ParsedStructure parsedStructure = parseStructure(structure);
// Fetch user data that matches the fields.
UserData userData = fetchUserData(parsedStructure);
// Build the presentation of the datasets
RemoteViews usernamePresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1);
usernamePresentation.setTextViewText(android.R.id.text1, "my_username");
RemoteViews passwordPresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1);
passwordPresentation.setTextViewText(android.R.id.text1, "Password for my_username");
// Add a dataset to the response
FillResponse fillResponse = new FillResponse.Builder()
.addDataset(new Dataset.Builder()
.setValue(parsedStructure.usernameId,
AutofillValue.forText(userData.username), usernamePresentation)
.setValue(parsedStructure.passwordId,
AutofillValue.forText(userData.password), passwordPresentation)
.build())
.build();
// If there are no errors, call onSuccess() and pass the response
callback.onSuccess(fillResponse);
}
class ParsedStructure {
AutofillId usernameId;
AutofillId passwordId;
}
class UserData {
String username;
String password;
}
I have a project where I am reading some json through GSON and Volley. I want to save my data in a database, and I was hoping that Realm would be a good solution. I took my first class which has seven member variables, all Strings and ints and had it extend RealmObject and identified one of the ints as the primary key. It compiles fine, but when it runs, I get tons and tons of output in the logs, and eventually the app just crashes before showing the main activity. It seems that GSON does not like parsing a class that has extended RealmObject.
So I did some searching and I found this post from the Realm site, but it is for an older version of Realm (I am currently using 0.87)
https://realm.io/docs/java/0.77.0/#other-libraries
It gives a solution, but I can't get that solution working for me because they are parsing their GSON differently that I am. Maybe we can solve this by just helping me here, but I wonder if this soltution won't work not matter since it is for an older version?? Anyway, I am parsing my GSON like this:
private void DisplayData(int count, final ArrayList<TwoLineSummaryCardDataObject> tlscdo,
final TwoLineSummaryViewAdapter lsva) {
final String url = "https://mydata.com/mydata";
final GsonRequest gsonRequest =
new GsonRequest(url, MyData.class, null, new Response.Listener<MyData>() {
#Override
public void onResponse(MyData myData) {
tlscdo.clear();
// Disable Realm stuff for now
//Realm realm = Realm.getDefaultInstance();
//realm.beginTransaction();
for (int i = 0; i < myData.getData().size(); i++) {
tlscdo.add(new TwoLineSummaryCardDataObject(myData.getData().get(i)));
//realm.copyToRealmOrUpdate(myData.getData().get(i));
}
//realm.commitTransaction();
lsva.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
if(volleyError != null) Log.e("MainActivity", volleyError.getMessage());
Toast.makeText(MainActivity.this, "Error in Volley", Toast.LENGTH_SHORT).show();
}
}
);
// Add the request to the queue
Volley.newRequestQueue(this).add(gsonRequest);
VolleyHelper.getInstance(getApplicationContext()).addToRequestQueue(gsonRequest);
1) How do I update my code so I can use a GsonBuilder like the example on the Realm javadoc page?
2) Am I wasting my time because that code is for an older version of Realm and there is now a different/better/no way to make GSON and Realm play together?
Edit: There was a req to see the MyData class. It's really simple:
public class MyData {
#PrimaryKey
private Integer id;
private String name;
private String abbrev;
private String countryCode;
private Integer type;
private String infoURL;
private String wikiURL;
// followed by a bunch of getters and setters
}
To clarify, it runs fine like this. If I add "extends RealmObject", it will still compile, but when running, it just spews out all kinds of messages and then the app eventually crashes (out of memory, I presume) after a few seconds without ever showing the activity.
Edit 2, adding in the logcat as requested.
When I do run it with the "extends RealmObject", this is the logcat.
http://pastebin.com/raw/1VZq8bQD
And if I take the "extends RealmObject" out, it runs perfectly.
1) How do I update my code so I can use a GsonBuilder like the example on the Realm javadoc page?
You can create a new class that extends Request<T> and apply it to your existing code. In your case, the quickest way is to copy the GsonRequest class source code to a new one, and modify the line that intialize the Gson object in the constructor:
mGson = new Gson();
with the code as written in realm.io's website.
2) Am I wasting my time because that code is for an older version of Realm and there is now a different/better/no way to make GSON and Realm play together?
As of writing this answer, the lastest version of realm is 0.87.1, and the method of working with GSON is the same. So this should still be the proper way.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I am developing a client-server application which requires remote database connection.
I know that tutorials on the web and more people are using PHP to interact with MySQL. But, I am not so good at PHP and my prior experience is with Core Java, Swing and JDBC.
Can anyone guide me if it is possible to connect remote MySQL database using JAVA JDBC APIs in Android application?
Basically: you can connect to your MySQL (or whatever you use) server, but you should not do this directly from your Android application.
Reasons:
Android applications can be decompiled, and the client will have credentials to access to your database. If using the right hacking tools like Backtrack, then this malicious client can access, connect and exploit the data in your database.
If your application is for clients all around the world, then the clients should open and maintain a connection to your database per operation or set of operations. Opening a physical database connection takes a lot of time, even when your pc client is in a LAN next to the database engine server. Now, imagine opening a connection from a country in the other side of the world e.g. China or Japan or from a country in South America like Brazil or Peru (where I live).
For these 2 reasons I can come up with, it's a bad idea even trying to connect to MySQL or any other database engine directly from your phone device.
How to solve this problem? Use a service oriented architecture where you will have at least two applications:
Service provider application. This application will create and publish web services (preferably RESTful) and may establish policies to consume the web services like user authentication and authorization. This application will also connect to the database and execute CRUD operations against it.
Service consumer application. This would be your Android (or any other mobile) application.
From your question, you're focusing on the point 1. As I've said in my comments, you can create a Web application in Java, create a RESTful service there, which boils down to a POJO (plain old java object) that has a method per service. In this method, since it's plain Java after all, you can add other functionality like JDBC usage.
Here's a kickoff example using Jersey, Jackson (JSON library) and JDBC:
#Path("/product")
public class ProductRestService {
#GET
#Path("/list")
#Produces(MediaType.APPLICATION_JSON)
public List<Product> getProducts() {
List<Product> productList = new ArrayList<>();
Connection con = ...; //retrieve your database connection
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id, name FROM product");
while (rs.next()) {
Product product = new Product();
product.setId(rs.getInt("id"));
product.setName(rs.getString("name"));
productList.add(product);
}
//ALWAYS close the resources
rs.close();
stmt.close();
conn.close();
return productList;
}
}
You can check for further configurations of the Java web application in a tutorial like mkyong's or Vogella's or any other of your like (it's too much info to place in this answer).
Note that then this application can evolve into a layered application, and the JDBC code will go in a DAO class, and then the ProductRestService class will access to the database through this DAO class. Here's another kickoff example:
public class ProductDao {
public List<Product> getProducts() {
List<Product> productList = new ArrayList<>();
Connection con = ...; //retrieve your database connection
//the rest of the code explained above...
return productList;
}
}
#Path("/product")
public class ProductRestService {
#GET
#Path("/list")
#Produces(MediaType.APPLICATION_JSON)
public List<Product> getProducts() {
ProductDao productDao = new ProductDao();
return productDao.getProducts();
}
}
And you can apply other changes to this project as well as is evolving.
Can you say me what PHP does here? (if I develop with PHP)
Instead of writing the Service provider application in Java (as shown above), you can do it in PHP. Or in Python, Ruby, C#, Scala or any other programming language that provides this technology to you. Again, I'm not sure what kind of tutorial you're reading, but this should be explained somewhere and explain that for the purposes of that tutorial you will create the services using PHP. If you feel more comfortable writing these services in Java rather than in PHP or any other language, there's no problem. Your android app doesn't really care which technology is used to produce the web services, it will only care about consuming the services and that the data from them can be consumed.
It is possible to do it but not recommended. I have done it before as I was in the same boat as you so I will share some code.
I used this jdbc jar specifically: https://www.dropbox.com/s/wr06rtjqv0q1vgs/mysql-connector-java-3.0.17-ga-bin.jar?dl=0
now for the code:
package com.example.test.databaseapp;
import java.sql.DriverManager;
import java.sql.SQLException;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
public class MainActivity extends Activity {
static final String url = "jdbc:mysql://x.x.x.x:xxxx/DBNAME";
static final String user = "client";
static final String pass = "password";
public static List<objClass> objList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Download(MainActivity.this, internalUrl).execute(); //async task for getting data from db
}
}
Now for my async task:
public class Download extends AsyncTask<Void, Void, String> {
ProgressDialog mProgressDialog;
Context context;
private String url;
public Download(Context context, String url) {
this.context = context;
this.url = url;
}
protected void onPreExecute() {
mProgressDialog = ProgressDialog.show(context, "",
"Please wait, getting database...");
}
protected String doInBackground(Void... params) {
try {
Class.forName("com.mysql.jdbc.Driver");
java.sql.Connection con = DriverManager.getConnection(url, user, pass);
java.sql.Statement st = con.createStatement();
java.sql.ResultSet rs = st.executeQuery("select * from table");
list = new ArrayList<objClass>();
while (rs.next()) {
String field= rs.getString("field");
MainActivity.playerList.add(new objectClass(field));
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return "Complete";
}
protected void onPostExecute(String result) {
if (result.equals("Complete")) {
mProgressDialog.dismiss();
}
}
}
Make sure to include internet permissions in the manifest.
Feel free to ask more questions about my code if you have any.
You can't access a MySQL DB from Android natively. EDIT: Actually you may be able to use JDBC, but it is not recommended (or may not work?) ... see Android JDBC not working: ClassNotFoundException on driver
See
http://www.helloandroid.com/tutorials/connecting-mysql-database
http://www.basic4ppc.com/forum/basic4android-getting-started-tutorials/8339-connect-android-mysql-database-tutorial.html
Android cannot connect directly to the database server. Therefore we
need to create a simple web service that will pass the requests to the
database and will return the response.
http://codeoncloud.blogspot.com/2012/03/android-mysql-client.html
For most [good] users this might be fine. But imagine you get a hacker that gets a hold of your program. I've decompiled my own applications and its scary what I've seen. What if they get your username / password to your database and wreak havoc? Bad.