I'm trying to connect to another database on an Android App, and can't seem to see if I've successfully init the secondary database.
How I'm instantiating the second one.
public void initFirebase() {
//init the default db;
FirebaseApp.initializeApp(this);
//init the second db;
FirebaseOptions.Builder builder = new FirebaseOptions.Builder();
builder.setApplicationId("id");
builder.setApiKey("key");
builder.setDatabaseUrl("https://second-db.firebaseio.com");
try {
FirebaseApp.initializeApp(this, builder.build(), "second-db");
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
Then I try to read something here.
public static DatabaseReference getSecondDbRef(String child) {
FirebaseApp app = FirebaseApp.getInstance("second-db");
return FirebaseDatabase.getInstance(app).getReference(child);
}
Then this fails with some: Listen at /child/child/child/teams failed: DatabaseError: Permission denied, though I've allowed access at this location and can confirm with the rules simulator that this node can be read.
Is there a way to have this log: Listen to second-db/child/child/child/teams failed ..., notice the prefix second-db.
Related
My realtime-database has data persistence for offline use and recently a recording error recorded a String as HashMap and consequently the application crashed for all my clients. I quickly corrected the error, but now all clients can no longer open the application, as it loads offline before online and ends up slowing down the error and closing the application for all users, or a good part of them.
I'm instructing them to do data wiping manually, but this is a big problem for me and I need to find a way to force this data wiping of all users remotely or predict in the application that when there are some crashes it will clear the local data automatically.
Any code suggestions or how can I do this?
I solve this problem with an try/catch, like code below:
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
try {
User user = dataSnapshot.getValue(User.class); // error occurs here
//... some code ...//
} catch (DatabaseException databaseException) {
Log.e(TAG, "DatabaseException ****** The read failed: " + databaseException);
clearPreferences(context.getApplicationContext());
deleteCache(context.getApplicationContext());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) { Log.e(TAG, "onCancelled ****** The read failed: " + databaseError); }
public static void clearPreferences(Context context) {
try {
// clearing app data
Runtime runtime = Runtime.getRuntime();
runtime.exec("pm clear "+context.getPackageName());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void deleteCache(Context context) {
try {
File dir = context.getCacheDir();
deleteDir(dir);
} catch (Exception ignored) {}
}
Okay so, I am currently integrating chatSDK into a pre-existing app. This is all fine, but when i try to call ChatSDK.ui().startSplashScreenActivity(context); it throws an errors that it was invoked on a null pointer.
I managed to narrow this down to ChatSDK.initialize(context, builder.build(), FirebaseNetworkAdapter.class, BaseInterfaceAdapter.class);
Which was throwing java.lang.reflect.InvocationTargetException. In the stack trace this was also shown
at co.chatsdk.core.session.ChatSDK.initialize(ChatSDK.java:86)
--> which is :shared().setNetworkAdapter(networkAdapterClass.getConstructor().newInstance());
So from what I gather, there is something funky going on with the network adapter, i.e my connection to firebase (works with another chatsdk app), or internet connection?
I'm not quite sure how to go forward this this so would really appreciate your help.
Here is the code for reference.
Thank you
Context context = getApplicationContext();
try {
// Create a new configuration
Configuration.Builder builder = new Configuration.Builder();
// Perform any other configuration steps (optional)
builder.firebaseRootPath("prod");
// Initialize the Chat SDK
//Configuration.Builder config = new Configuration.Builder(context);
ChatSDK.initialize(context, builder.build(), FirebaseNetworkAdapter.class, BaseInterfaceAdapter.class);
// File storage is needed for profile image upload and image messages
FirebaseFileStorageModule.activate();
// Push notification module
//FirebasePushModule.activate();
// Activate any other modules you need.
// ...
} catch (Exception e) {
// Handle any exceptions
e.printStackTrace();
Log.e("chatsdkError",e.toString());
}
public class Messages extends AppCompatActivity {
#Override
protected void onCreate(Bundle onSavedInstance){
super.onCreate(onSavedInstance);
setContentView(R.layout.activity_messages);
Context context = getApplicationContext();
ChatSDK.ui().startSplashScreenActivity(context);
}
}
And lastly, here is some of the stack trace that i think is important
W/System.err: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
at co.chatsdk.core.session.ChatSDK.initialize(ChatSDK.java:86)
at com.ul.pinter.Home.onCreate(Home.java:101)
at android.app.Activity.performCreate(Activity.java:7815)
at android.app.Activity.performCreate(Activity.java:7804)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1318)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3349)
I'm testing out Realm for database storage.
I'm using a singleton for fetching and managing common data that needs to be refreshed fairly often. But it seems that the Realm defaultInstance that get in my singleton is not in the same scope as if I get it in my Activity. So when I fetch remote data via my singleton, then save to realm, I can't retrieve that data from an Activity (get an empty result set).
I have attempted to pass in the Realm instance I defined in the Activity to the singleton (and close it there as well), but I still cannot retrieve saved results via the Activity instance.
I'm setting the default configuration in my Application class if that makes a difference.
Any help would be appreciated in clearing this up.
**Edit
Here's some more code. I'm using retrofit and gson, and my relevant services are in a Utility class (which may be causing the issue).
private void fetchMyObjects(Context context) {
// Fetch the myObjects
UtilityServices utilityServices = new UtilityServices(context);
utilityServices.getMyObjects(new UtilityServices.MyObjectsListener() {
#Override
public void gotMyObjects(final ArrayList<MyObject> myObjects, Exception e) {
if(e == null) {
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.delete(MyObject.class);
realm.copyToRealm(myObjects);
Log.v("qwer", "LocalDataFragment fetchMyObjects: " + realm.where(MyObject.class).findAll().size());
}
});
} finally {
if(realm != null) {
realm.close();
}
}
} else {
// TODO: Handle a myObject error.
e.printStackTrace();
}
}
});
}
There is only one way that the results of a Realm transaction would not be visible after a transaction is executed and that is that the transaction takes place on a different thread.
It seems quite likely that this is the case, in your code, since, if getMyObjects ran on the UI thread, you would be getting the "no network activity on the UI thread exception"
I've been running into a problem using the AWS Mobile SDK version 2.2.15. After carefully looking at their own S3TransferUtilitySample, I have made a couple attempts to get a file uploaded to an Amazon S3 bucket on my own.
My first attempt was to try calling the TransferUtility's .upload() method from within Android's own AsyncTask, inside the doInBackground() method. No success there, and after reading about this issue, it inspired me to try moving the SDK calls outside of the AsyncTask and into the UI thread under onPostExecute() in suspicion that the call itself is asynchronous and the AsyncTask is running garbage collection on the AWS SDK objects. Still no luck, no exceptions are being thrown, and no indication of anything going wrong aside from the file not actually uploading.
My second attempt was following this exact example. I downloaded the source and was able to supply the application with the correct identity pool ID, region, bucket, key, and a test jpeg file. I ran the application and the calls were being made. The file made it to AWS S3 without any issues.
I copied their exact methods into a helper class of my application, and made all the AWS SDK objects a static field of the class, but I am still running into the same issue of no exceptions being thrown. I ended up making the fields non-static and instantiating the helper class as an object in my main activity, safely assuming that the object would not be treated with garbage collection. Still nothing! No indication of failure from these calls!
I decided to get really generous with logging using Android's Log.i() method, watching every step of the way, and it even makes it to the TransferUtility's .upload() method, but even having the TransferListener set and full of logging lines, there is no status change, onError() is not being called. TransferUtility's .upload() and its resulting TransferObserver object is not reporting anything like it was running the test application.
Here are a couple things to note:
* The correct identity pool ID is being used here, no issue with that
* I have tried using both version 2.2.15 as well as 2.2.13
* All dependencies included are .jar files, the project is not Gradle (yet)
* The service is declared in the manifest just as it was in the examples
* There are no build errors, Android Studio builds the project just fine
* The TransferListener object is not firing onStateChanged(), onProgressChanged(), nor onError()
Has anyone encountered such a strange issue with AWS S3 SDK? Any suggestions on how I can better debug this issue?
Here's the class right now:
public class AmazonS3Helper
{
Context context;
public String bucket;
public String key;
public File file;
public AmazonS3 s3;
public TransferUtility utility;
public AmazonS3Helper(JSONObject p, Context c)
{
Log.i("tag", "new AmazonS3Helper object");
this.context = c;
try
{
bucket = p.getString("bucket");
key = p.getString("key");
this.file = new File(
c.getExternalFilesDir(null),
"nn_temp_photo.jpg");
credentialsProvider();
setTransferUtility();
upload();
}
catch (Exception x)
{
Log.i("tag", "Error in new AmazonS3Helper object: " + x.getMessage());
}
}
public void credentialsProvider()
{
Log.i("tag", "Providing credentials");
try
{
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
this.context,
// This has been verified to return the correct identity pool
MyApplicationClass.getPreference("aws.credentials"),
Regions.US_EAST_1);
setAmazonS3Client(credentialsProvider);
}
catch (Exception x)
{
Log.i("tag", "Error in providing credentials: " + x.getMessage());
}
}
public void setAmazonS3Client(CognitoCachingCredentialsProvider credentialsProvider)
{
Log.i("tag", "Setting amazon s3 client");
try
{
s3 = new AmazonS3Client(credentialsProvider);
s3.setRegion(Region.getRegion(Regions.US_EAST_1));
}
catch (Exception x)
{
Log.i("tag", "Error in setting amazon s3 client:" + x.getMessage());
}
}
public void setTransferUtility()
{
Log.i("tag", "Setting transfer utility");
try
{
utility =
new TransferUtility(
s3,
this.context);
}
catch (Exception x)
{
Log.i("tag", "Error in setting transfer utility: " + x.getMessage());
}
}
public void upload()
{
Log.i("tag", "uploading");
try
{
TransferObserver transferObserver = utility.upload(
bucket,
key,
file
);
transferObserverListener(transferObserver);
}
catch (Exception x)
{
Log.i("tag", "Error in uploading: " + x.getMessage());
}
}
public void transferObserverListener(TransferObserver transferObserver)
{
Log.i("tag", "transferObserverListener");
try
{
transferObserver.setTransferListener(new TransferListener()
{
#Override
public void onStateChanged(int id, TransferState state)
{
Log.i("tag", state + "");
}
#Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal)
{
int percentage = (int) (bytesCurrent / bytesTotal * 100);
Log.i("tag", percentage + "");
}
#Override
public void onError(int id, Exception ex)
{
Log.i("tag", "error");
}
});
}
catch (Exception x)
{
Log.i("tag", "Error in transferObserverListener: " + x.getMessage());
}
}
}
Edit
I forgot to mention, but the version of Android this is being tested on is Android Lollipop 5.1.
This is a bug in 2.2.15. Some IO exceptions aren't reported. It is fixed in 2.2.16. Would you please try the latest version?
The issue has been solved and is entirely unrelated to the code itself. What was happening was that I was declaring the com.amazonaws.mobileconnectors.s3.transferutility.TransferService in the library's manifest, but the child apps also needed it in their manifest.
I found this out by dropping the sample Activity straight into my application, and realizing the child apps also needed this activity declaration. The child apps have no code themselves, but without the declaration in their own manifest, they are unaware the activities/services being referenced exist. In this case, Amazon was silently refusing to upload because the service wasn't declared for the specific application.
When I sign in on my application and try to get the size from the datastore's table, it is empty. But after I restart the application, it works as it should and gives back the size of the datastore's table.
In my case, there are two activities. The activity, and in-turn the fragment, SettingsFragment.java has the sign-in part. The activity MainActivity.java has the part with getting the datastore's table size.
SettingsFragment.java (Sign-in).
// Dropbox Signin
mAccountManager = DbxAccountManager.getInstance(getActivity().getApplicationContext(), APP_KEY, SECRET_KEY);
mDropBoxPreference = findPreference("preference_sync_dbx");
mDropBoxPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
if (mAccountManager.hasLinkedAccount()) {
mAccountManager.unlink();
} else {
mAccountManager.startLink(getActivity(), REQUEST_LINK_TO_DBX);
}
return true;
}
});
MainActivity.java (Get datastore size).
// Dropbox Get Datastore Size
mAccountManager = DbxAccountManager.getInstance(getApplicationContext(), APP_KEY, SECRET_KEY);
if (mAccountManager.hasLinkedAccount()) {
DbxAccount mDbxAccount = mAccountManager.getLinkedAccount();
try {
mDbxStore = DbxDatastore.openDefault(mDbxAccount);
mDbxNotesTable = mDbxStore.getTable("notes");
mDbxNotesCount = mDbxNotesTable.query().count();
Log.e("mDbxNotesCount", Integer.toString(mDbxNotesCount));
} catch (DbxException e) {
e.printStackTrace();
}
}
Let's say there are 3 records in the datastore.
After I sign in, this shows up from the Logcat.
E/mDbxNotesCount﹕ 0
Once I restart it, this shows up from the Logcat.
E/mDbxNotesCount﹕ 3
What's causing it to work like this?
Edit: Added listener after using smarx's answer, and it works! Here is what I did.
mDbxStore.addSyncStatusListener(new DbxDatastore.SyncStatusListener() {
#Override
public void onDatastoreStatusChange(DbxDatastore dbxDatastore) {
if (!dbxDatastore.getSyncStatus().isDownloading) {
try {
mDbxStore.sync();
mDbxNotesCount = mDbxNotesTable.query().count();
} catch (DbxException e) {
e.printStackTrace();
}
Log.e("mDbxNotesCount", Integer.toString(mDbxNotesCount));
}
}
});
It looks like you're trying to read the contents of the datastore before it's had a chance to sync. You'll need to wait until the initial sync is completed. I think one way to do that would be to add a listener via addSyncStatusListener and wait for store.getSyncStatus().isDownloading to be false.
But typically the pattern you'll want to follow is to always show the current information... so set up a listener and update your UI any time it changes. That way whether it's the initial sync bringing in new records or updates from a different device, your app will respond appropriately when the information changes.