Issue with 'cannot find setter error' with a date field - java

I am attempting to create an app using android studio and when trying to run the app I seem to have an issue with one of the fields for my database.
public void setTime(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
this.time = Time.from(Instant.now());
}
}
I keep getting error: Cannot find setter for field. private Date time;
If i remove the if statement about build version I get the same issue but android studio also underlines the this.time = Time.from(Instant.now()); statement and advises me to surround it with the if statement. How do I fix this?

Related

Unity AndroidJavaObject not working without showing errors

I have been trying to call a Java method in unity. Not working for me, even the simplest example from the docs
using System.Collections;
using UnityEngine;
public class ExampleClass : MonoBehaviour {
void Start () {
AndroidJavaObject jo = new AndroidJavaObject ("java.lang.String", "some string");
int hash = jo.Call<int> ("hashCode");
Debug.Log ("hash=" + hash);
}
}
Unity console prints hash=0, which is not the hash code for provided String. Even if I change and use java.lang.StringInvalidClass as class name, unity still reports same result to the console without notifying errors. I can even try to call toString, toStringa, toInvalid2 and they always return empty string without showing errors.
This is a brand new 2d project with only script displayed above, attached to camara object. I am using Ubuntu, Unity 2019.4 and project platform is Android.
Thanks for the assistance.
Answering myself after some time working with unity.
All examples in the web and unity documentation doesn't mention it, which is weird since it is something simple to mention and about confusions: code needs to run as an android application. Editor or even unity remote does not work, in order to use AndroidJavaObject and related classes, your code needs to run as an android application installed in the phone.

Why are SharedPreferences ignored on some devices?

I have a 2-step database migration in my app, using Room. The migration had to be done in two parts (v.2 -> 3 -> 4) because complex database operations using newly added tables had to be done between versions 3 and 4.
I have a SharedPreferences key-value pair to save the information when the user migrates. This is to ensure that the app won't try to migrate from 2 to 3 after it has already migrated to version 4.
The migration from 2 to 3 is meant to be run only when the user updates the app from the old version to the new version.
This has worked in every single one of our test devices, but Google Play's data is giving us a lot of crash reports for IllegalStateException, stating that the database tried to downgrade itself. This should NOT happen, should the SharedPreferences check work correctly.
For reference. Here's some of the migration code:
if(!hasMigrated){
if(NeedMigration.needMigrate(MyApplication.getAppContext())){
..
try{
//instantiate migration 2 to 3
pdb=PreDatabase.getInstance(this);
dRepo = new DayRepo(pdb, this, dayInstance);
//db operations
createDays();
//store into SharedPrefs that we already migrated from 3
NeedMigration.setHasMigrated(MyApplication.getAppContext());
}catch(IllegalStateException e){
Log.e("Database", "Already at version 4");
..
return;
}
..
//instantiate migration from 3 to 4 (mig is in db.build)
mdb = MyDatabase.getInstance(this);
mRepo = Repository.fromContext(this);
..
} else {
/*
If the user already has updated and the database exists in its newest state, skip straight to MyDatabase.java
instantiation and load Day objects from database.
*/
instantiateDatabase();
}
..
hasMigrated=true;
}
The hasMigrated boolean is just a static boolean so that the app won't try to instantiate the database again during runtime. If NeedMigration.needMigrate returns false, it instead just instantiates the database at the current version.
Here is the NeedMigrate class:
private static final String MIG_PREFS= "migration_preferences";
private static final String MIG_HAS_UPDATED ="has_updated_to_four";
//if yes (true) then yes need migrate
//if false then no! no migrate
public static boolean needMigrate(Context activity){
//compare versioncode with sharedprefs
final SharedPreferences preferences = activity.getSharedPreferences(MIG_PREFS, Activity.MODE_PRIVATE);
final boolean needmig = preferences.getBoolean(MIG_HAS_UPDATED, true);
return needmig;
}
public static void setHasMigrated(Context activity){
final SharedPreferences prefs = activity.getSharedPreferences(MIG_PREFS, Activity.MODE_PRIVATE);
//check if value exists
SharedPreferences.Editor edit = prefs.edit();
//false because if needMigrate is false then we dont need migrate
edit.putBoolean(MIG_HAS_UPDATED, false);
edit.commit();
}
Again let me clarify that this works perfectly fine on my test devices, but we're getting a lot of crash reports from Google implying that the database tried to run at the previous version:
java.lang.IllegalStateException:
at androidx.room.RoomOpenHelper.onUpgrade (RoomOpenHelper.java:101)
at androidx.room.RoomOpenHelper.onDowngrade (RoomOpenHelper.java:113)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onDowngrade
(FrameworkSQLiteOpenHelper.java:144) at
android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked
(SQLiteOpenHelper.java:257) at
android.database.sqlite.SQLiteOpenHelper.getWritableDatabase
(SQLiteOpenHelper.java:2) at
androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase
(FrameworkSQLiteOpenHelper.java:96) at
androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase
(FrameworkSQLiteOpenHelper.java:54) at
androidx.room.RoomDatabase.query (RoomDatabase.java:256) at
androidx.room.util.DBUtil.query (DBUtil.java:54) at
fi......controllers.database_controller.MealGroupDao_..PreDatabase_Impl.getMealGroupsInDay
(MealGroupDao_..PreDatabase_Impl.java:157) at
fi.....DayRepo.lambda$populateDayCache$0 (DayRepo.java:301) at
fi.....controllers.database_controller.repos.-$$Lambda$DayRepo$gQGLM0kHLZLeLseqjFzeMTTO2fw.run
(-.java:8) at java.util.concurrent.ThreadPoolExecutor.runWorker
(ThreadPoolExecutor.java:1167) at
java.util.concurrent.ThreadPoolExecutor$Worker.run
(ThreadPoolExecutor.java:641) at java.lang.Thread.run
(Thread.java:764)
We just got a review saying "Can't open app"and I suspect that this is the reason.
Why is this SharedPreference check ignored, or does it just return a wrong value ? Is this a context-related issue or perhaps related to the fact that the NeedMigration class is static?
I have tried:
Changing context from activity to application context
moving the setHasMigrated call to happen before the database 2 to 3 update (DID NOT WORK...)
Adding try/catch blocks in a lot of places

Get User Android Version

is there any way for my application to get the user's Android Version or API Level ? .. because i am working on an app that supports API 9 (2.3 Gingerbread) .. and since API 9 does not support DialogFragments even with android.support.v4.app.DialogFragment imported, i decided to do an if else statement instead
if (the users Android Version is Lower than API 11)
{
i will show a new class instead of a Dialog Fragment containing all information about the developer
}
else if (the users Android Version is Higher than or equal to API 11)
{
my dialog fragment will show up containing all information about the developer
}
i hope anyone can help me out about this, thanks :)
Use Build.VERSION.SDK_INT to get the API level. You can then compare it against values in Build.VERSION_CODES:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// do something cool
}
Standard how to execute code for different versions.
Android provides a unique code for each platform version in the Build constants class. Use these codes within your app to build conditions that ensure the code that depends on higher API levels is executed only when those APIs are available on the system.
#SuppressWarnings("deprecation")
// We use the new method when supported
#SuppressLint("NewApi")
// We check which build version we are using.
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
mapView.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
} else {
mapView.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
}
Try this:
Build.VERSTION.RELEASE
http://developer.android.com/reference/android/os/Build.VERSION.html

How to support multiple android version in your code?

Take accessing contacts in android
android.jar for versions 1.6 has People.CONTENT_URI for invoking contacts related info whereas in later versions we need to have api support for RawContacts.CONTENT_URI.
Same thing is true for accessing calendar for instance as its URI is changed in android 2.2.
Is there a best practice to manage all different changes without adding additional application or build separately for each version of changes?
For my money, a very good answer is at http://android-developers.blogspot.co.uk/2010/07/how-to-have-your-cupcake-and-eat-it-too.html. However, the example there is a little more complicated than need be, so based on that, here is an example of how to cope with it when building notifications. The underlying reason this works is a consequence of how java engines interpret classes: it only looks at them when needed, so if you wrap version specific code up in a class and only create it when you know you are using that version, it all works ...
There are, as far as I can tell, two generations of approaches to creating notification, and a naming change along the way in the second. So that gives three ways to do it. For each way, create a class with the notification generation in it:
The first approach (used through to Gingerbread):
public class MyNotificationBuilderToGingerBread {
Notification notification = null;
MyNotificationBuilderToGingerBread(Context myContext, int icon, String ticker, String title, String info, Long timeStamp, PendingIntent pendingIntent, int flags) {
notification = new Notification(R.drawable.ic_sb, ticker, timeStamp);
notification.setLatestEventInfo(myContext, title, info, pendingIntent);
notification.flags |= flags;
}
Notification get() {
return notification;
}
}
The second approach, Honeycomb to IceCreamSandwich:
public class MyNotificationBuilderHoneyCombToIceCreamSandwich {
Notification.Builder mb = null;
MyNotificationBuilderHoneyCombToIceCreamSandwich(Context myContext, int icon, String ticker, String title, String info, Long timeStamp, PendingIntent pendingIntent, boolean onGoing) {
mb = new Notification.Builder(myContext);
mb.setSmallIcon(icon);
mb.setContentIntent(pendingIntent);
mb.setContentTitle(title);
mb.setContentText(info);
mb.setWhen(timeStamp);
if (ticker != null) mb.setTicker(ticker);
mb.setOngoing(onGoing);
}
Notification get() {
return mb.getNotification();
}
}
The second generation, with the name change, Jellybean (onwards, so far ...):
public class MyNotificationBuilderJellyBean {
Notification.Builder mb = null;
MyNotificationBuilderJellyBean(Context myContext, int icon, String ticker, String title, String info, Long timeStamp, PendingIntent pendingIntent, boolean onGoing) {
mb = new Notification.Builder(myContext);
mb.setSmallIcon(icon);
mb.setContentIntent(pendingIntent);
mb.setContentTitle(title);
mb.setContentText(info);
mb.setWhen(timeStamp);
if (ticker != null) mb.setTicker(ticker);
mb.setOngoing(onGoing);
}
Notification get() {
return mb.build();
}
}
Then, you just need to pick which class to instantiate on the fly:
// System information
private final int sdkVersion = Build.VERSION.SDK_INT;
// If you want to go really old:
// (actually, there is a question about how this issue should be handled
// systematically. Suggestions welcome.)
// final int sdkVersion = Integer.parseInt(Build.VERSION.SDK);
// This is for a permanent notification. Change the final argument (flags or boolean) if it isn't meant ot be
// For meaning of other variable, see notification documentation on the android website.
if (sdkVersion < Build.VERSION_CODES.HONEYCOMB) {
MyNotificationBuilderToGingerBread mnb = new MyNotificationBuilderToGingerBread(myContext, R.drawable.notification_icon, ticketText, title, infoText, timeStampMillis, pendingIntentForTapOnFullNotitifcation, Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR);
notification = mnb.get();
}
else if (sdkVersion < Build.VERSION_CODES.JELLY_BEAN) {
MyNotificationBuilderHoneyCombToIceCreamSandwich mnb = new MyNotificationBuilderHoneyCombToIceCreamSandwich(myContext, R.drawable.notification_icon, ticketText, title, infoText, timeStampMillis, pendingIntentForTapOnFullNotitifcation, true);
notification = mnb.get();
}
else {
MyNotificationBuilderJellyBean mnb = new MyNotificationBuilderJellyBean(myContext, R.drawable.notification_icon, ticketText, title, infoText, timeStampMillis, pendingIntentForTapOnFullNotitifcation, true);
notification = mnb.get();
}
// Send the notification.
notificationManager.notify(idForNotificationManager, notification);
Hope this helps!
There are many resources for you to utilize to help support multiple versions of android.
Read this blog post here and
then read this one here, they
will help you address API level
version support issues.
Read this blog post on multiple
screen support, especially how the
asset hierarchy in parsed in res
folder. This will help you
understand and design how to do
asset folder structure to support
different screen size/densities and
android versions.
Lastly write your own custom ant build
scripts so that you can compile with
all versions of android.
Quite Honestly, it's a pain.
I usually, just isolate parts of code that are different and access them using abstract classes. So technically creating different version for different OS.
But there are other ways. The best one i've seen involves using reflection.
If you don't really need the new functionnalities, and really have to support old Android versions, drop it. Build your app for the oldest version, and don't bother with this kind of thing.
In the other case, you can detect the version using Build, and use reflection to load the classes you need. An example of that can be found in the source code of the K9Mail app
There's a nice article on android.com about it:
http://developer.android.com/resources/articles/backward-compatibility.html
Personally I would suggest the wrapper class or wrapper library solution. But in small cases the reflection should be fine (and in case performance is not a problem for you).
If you need more info, ask in comments.
This is a great article for when you have to do reflection in Android (to support multiple API levels).
And when you have to have different resources for different API Levels, this is the reference to use (see the section on "Platform Version (API level)").
If on Eclipse, from ADT version 17 you can specify code to run with some version simply as described in Lint API Check.
The code word is #TargetAPI(XX)
Hope it helps
Best practice (though not for Android, but for J2ME) to my knowledge is to use preprocessing C/C++ styled statements, like:
//#if S40
...
//#else
...
//#endif
Some IDE's support these kind of preprocessing, e.g. Netbeans. To my knowledge Eclipse has some plugins to enable preprocessing also. I don't really know are they applicable to Android development. Try to google yourself.

Android: setPictureFormat() error

I'm a beginner in Andoird, currently trying to write an application using the Camera class of Android in Eclipse. The problem is when I call the parameters.setPictureFormat() method with ImageFormat.JPEG as the argument, I get an error.
Here's how my code looks like:
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h){
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(854,480); // (h,w)
parameters.setPictureFormat(ImageFormat.JPEG);
parameters.set("jpeg-quality", 100);
parameters.set("orientation", "lanscape");
parameters.set("rotation", 90);
mCamera.setParameters(parameters);
mCamera.startPreview();
}
And I get this error in return:
ImageFormat cannot be resolved to a variable
I've tried using PixelFormat.JPEG as well, but I get the same error that says "PixelFormat cannot be resolved to a variable". I've checked, it's not importing android.R. I also tried importing android.graphics.ImageFormat but it doesn't work.
Could anybody help point out what the problem is?
For what target are you trying to build this app? android.graphics.ImageFormat is only available for android 2.2. I suppose your selected target is android 2.0 or below.
Two important points:
For Android 1.5 and Android 1.6, you
can't call setPictureFormat. Only
getPictureFormat is supported.
For Android 2.0 you will need to call
getSupportedPictureFormat to get the
list of formats supported.

Categories