I have been trying to follow this video to learn working with SQLite in Xamarin Forms and I am stuck
https://www.youtube.com/watch?v=FVH-9zjRP9M
project.Droid
class LocalDatabaseHelper : Classes.ILocalDatabaseHelper
{
public string GetLocalFilePath(string fileName)
{
string docFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
string libFolder = Path.Combine(docFolder, "..", "Library", "Databases");
if (!Directory.Exists(libFolder))
{
Directory.CreateDirectory(libFolder);
}
return Path.Combine(libFolder, fileName);
}
}
project (pcl)
public static Classes.TaskReminder.TaskReminderDatabaseOperation Database
{
get
{
if (database == null)
{
string LocalFilePath = "";
if(Device.OS==TargetPlatform.Android)
{
LocalFilePath = DependencyService.Get<Classes.ILocalDatabaseHelper>().GetLocalFilePath("TaskReminder.db3");
}
database = new Classes.TaskReminder.TaskReminderDatabaseOperation(LocalFilePath);
}
return database;
}
}
public interface ILocalDatabaseHelper
{
string GetLocalFilePath(string fileName);
}
And it is giving me Unhandled exception when executing
LocalFilePath = DependencyService.Get<Classes.ILocalDatabaseHelper>().GetLocalFilePath("TaskReminder.db3");
please help. thanks in advance.
NOTE (more information):
project (PCL)
public class TaskReminderDatabaseOperation
{
readonly SQLiteAsyncConnection database;
public TaskReminderDatabaseOperation(string dbPath)
{
database = new SQLiteAsyncConnection(dbPath);
database.CreateTableAsync<TaskReminder>().Wait();
}
public Task<List<TaskReminder>> GetTaskRemindersAsync()
{
return database.Table<TaskReminder>().ToListAsync();
}
public Task<TaskReminder> GetTaskReminder(DateTime datetime)
{
return database.Table<TaskReminder>().Where(i => i.ReminderDateTime == datetime).FirstOrDefaultAsync();
}
public Task<int> SaveTaskReminder(TaskReminder taskReminder)
{
if (taskReminder.Id == 0)
{
return database.InsertAsync(taskReminder);
}
else
{
return database.UpdateAsync(taskReminder);
}
}
public Task<int> DeleteTaskReminder(TaskReminder taskReminder)
{
return database.DeleteAsync(taskReminder);
}
}
Look closely at the video, around 29 minutes and 10 seconds. You will see that he adds a attribute to the project class. This registers the dependency with the Dependency Service in Xamarin.Forms.
You probably forgot to do that, that is why you will get a NullReferenceException when you try to resolve the implementation of the interface.
Please look into the workings of the Dependency Service to understand how these kinds of things work and resolve these errors for yourself, instead of just following the video.
Related
I am writing a library for Android and wanted it to use the constants in the BuildConfig exclusively - so the lib's client, so to speak, won't see them easily.
So, what I would like to achieve is instead of the public constant like this:
package my.lib;
public final class BuildConfig {
public static final boolean FOO = false;
}
it would rather generate a constant with no access modifier that would make the stuff visible in the package of my lib rather:
package my.lib;
public final class BuildConfig {
static final boolean FOO = false;
}
Is it possible to achieve somehow?
Thanks!
This is the generate() method from BuildConfigGenerator class:
/**
* Generates the BuildConfig class.
*/
public void generate() throws IOException {
File pkgFolder = getFolderPath();
if (!pkgFolder.isDirectory()) {
if (!pkgFolder.mkdirs()) {
throw new RuntimeException("Failed to create " + pkgFolder.getAbsolutePath());
}
}
File buildConfigJava = new File(pkgFolder, BUILD_CONFIG_NAME);
FileWriter out = new FileWriter(buildConfigJava);
JavaWriter writer = new JavaWriter(out);
Set<Modifier> publicFinal = EnumSet.of(Modifier.PUBLIC, Modifier.FINAL);
Set<Modifier> publicFinalStatic = EnumSet.of(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC);
writer.emitJavadoc("Automatically generated file. DO NOT MODIFY")
.emitPackage(mBuildConfigPackageName)
.beginType("BuildConfig", "class", publicFinal);
for (ClassField field : mFields) {
writer.emitField(
field.getType(),
field.getName(),
publicFinalStatic,
field.getValue());
}
for (Object item : mItems) {
if (item instanceof ClassField) {
ClassField field = (ClassField)item;
writer.emitField(
field.getType(),
field.getName(),
publicFinalStatic,
field.getValue());
} else if (item instanceof String) {
writer.emitSingleLineComment((String) item);
}
}
writer.endType();
out.close();
}
}
So this is impossible because BuildConfigGenerator creates only public final modifiers
Set<Modifier> publicFinal = EnumSet.of(Modifier.PUBLIC, Modifier.FINAL);
writer.emitJavadoc("Automatically generated file. DO NOT MODIFY")
.emitPackage(mBuildConfigPackageName)
.beginType("BuildConfig", "class", publicFinal);
and does not give you the option to choose)
My question is straightforward. I don't know how to migrate my data to new schema. I added ShouldDeleteIfMigrationIsNeeded when getting Realm instance which is a wrong thing to do on production. When I tried to update our app, the whole data got erased. Good thing this is our first week so it's still okay if data is gone but not for the next time.
How to do proper migration? What to put code. Where to put code. When to trigger
Here is my code on instance
public class DAL_DBAccessVariables
{
private const string databaseName = "dbname.realm";
private static readonly string dbPath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), databaseName);
private static readonly RealmConfiguration config = new RealmConfiguration(dbPath);
public static Realm GetInstance()
{
RealmConfiguration config = DAL_DBAccessVariables.config;
config.ShouldDeleteIfMigrationNeeded = true;
return Realm.GetInstance(config);
}
}
Here is the sample usage
public class DAL_Branches : IDALCommands
{
Realm realm;
public DAL_Branches()
{
realm = DAL_DBAccessVariables.GetInstance();
}
public object selectSpecific(int id)
{
try
{
return realm.All<t_Branches>().ToList().Find(o => o.Id == id);
}
catch { throw; }
}
}
I am going to open document using default app in Xamarin Forms. I tried already this approach but it doesn't work for me and I am not sure what is the reason.
Device.OpenUri(new Uri(FILE_PATH));
Please give me great solution if anyone knows how to handle it.
Thanks.
You can use DependencyService to implement this from each platform. Firstly, create a interface from PCL for example like:
public interface IFileViewer
{
void ShowPDFTXTFromLocal(string filename);
}
Then for Android platform, create a class to implement this interface:
[assembly: Xamarin.Forms.Dependency(typeof(FileViewer))]
namespace NameSpace.Droid
{
public class FileViewer : IFileViewer
{
public void ShowPDFTXTFromLocal(string filename)
{
string dirPath = Xamarin.Forms.Forms.Context.GetExternalFilesDir(Android.OS.Environment.DirectoryDocuments).Path;
var file = new Java.IO.File(dirPath, System.IO.Path.Combine(dirPath, filename));
if (file.Exists())
{
Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
{
var uri = Android.Net.Uri.FromFile(file);
Intent intent = new Intent(Intent.ActionView);
var mimetype = MimeTypeMap.Singleton.GetMimeTypeFromExtension(MimeTypeMap.GetFileExtensionFromUrl((string)uri).ToLower());
intent.SetDataAndType(uri, mimetype);
intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);
try
{
Xamarin.Forms.Forms.Context.StartActivity(intent);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
});
}
else
{
System.Diagnostics.Debug.WriteLine("file not found");
}
}
}
}
This is a example only works for the files which be placed in GetExternalFilesDir(Android.OS.Environment.DirectoryDocuments), if your files are in other place, you will need to modify the code.
2020 update: Xamarin now has a very simple solution for this using Xamarin.Essentials. You can use a single line of code to open a file in the default application using Launcher.OpenAsync:
await Launcher.OpenAsync(new OpenFileRequest { File = new ReadOnlyFile(uri) });
Here is some sample code I am using in my app to open PDF files in the default application:
private void BtnOpen_Clicked(object sender, EventArgs e)
{
string filePathAndName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "test.pdf");
OpenPdf(filePathAndName);
}
public async void OpenPdf(string uri)
{
await Launcher.OpenAsync(new OpenFileRequest { File = new ReadOnlyFile(uri) });
}
This will work on any platform with no custom renderers needed (as long as you have Xamarin.Essentials added to each project).
Here is a link to the Microsoft documentation which provides some additional information.
I implemented below code and worked perfectly.
I hope that this code will help others.
var PreviewController = UIDocumentInteractionController.FromUrl(NSUrl.FromFilename(filePath));
PreviewController.Delegate = new UIDocumentInteractionControllerDelegateClass(UIApplication.SharedApplication.KeyWindow.RootViewController);
Device.BeginInvokeOnMainThread(() =>
{
PreviewController.PresentPreview(true);
});
public class UIDocumentInteractionControllerDelegateClass : UIDocumentInteractionControllerDelegate
{
UIViewController ownerVC;
public UIDocumentInteractionControllerDelegateClass(UIViewController vc)
{
ownerVC = vc;
}
public override UIViewController ViewControllerForPreview(UIDocumentInteractionController controller)
{
return ownerVC;
}
public override UIView ViewForPreview(UIDocumentInteractionController controller)
{
return ownerVC.View;
}
}
I am developing a small game for Air Android in flash CS6, this game I'm programming object-oriented with classes written in AS3.
I want you to help me write a class that connects to SQLite from scratch, please!
I googled but only there information to FLEX or code for insert into frames (and i get lost because i don't know that libraries to import), it's not what I want.
I want to create the connection class to use in my class Main.
I hope I have your support, thank you.
Excuse my English but I speak Spanish.
You need 'Synchronous' or 'Asynchronous' sqlite connection ? You can see differences here: - Best practices for developing AIR Application with SQLite
1. There is an example for 'async' connection :SQLConnection - you just have to modify and remove transactions part (if you do not need it).
2. 'sync' is easy and i prefer this way
import flash.data.SQLConnection;
import flash.filesystem.File;
import flash.data.SQLMode; //if you use SQLMode: CREATE | UPDATE | READ
import flash.data.SQLStatement;
import flash.data.SQLResult;
import flash.errors.SQLError;
public class SQLiteConn
{
private var dbFile:File = new File("pathtofile");
private var conn:SQLConnection;
private var stmt:SQLStatement;
private var arr:Array;
public function SQLiteConn()
{
}
//open sqlite DB
public function openSQLite():Boolean {
conn = new SQLConnection;
if (dbFile.exists) {
try {
conn.open(dbFile);
return true;
}
catch (error:SQLError) {
trace(error.details, error.message);
}
}
return false;
}
//execute statement and get result/s
public function executeStatement(stmtText:String, param1:String, param2:String):Array {
if (conn.connected) {
stmt = new SQLStatement();
stmt.sqlConnection = con;
stmt.text = stmtText;
stmt.parameters[0] = param1;
stmt.parameters[1] = param2;
try {
stmt.execute();
var result:SQLResult = stmt.getResult();
if (result.data != null) {
var total:int = result.data.length;
for (var i:int = 0; i < total; i++) {
row = result.data[i];
arr.push( { id:row.tablerowID } );
}
}
else {
arr.push({id: -1}); //no result/s
}
}
catch (error:SQLError) {
arr.push({id: -2}); //sqlite error
}
}
else {
arr.push({id: -2}); //no connection
}
return arr;
}
//close sqliteConnection
public function closeSQLiteConn():void {
if (conn.connected) {
conn.close();
}
}
}
you can also 'dispatch event' from that class - it is your choise :)
I am new to android phonegap. i am storing and retrieving data using native application. i dont know how to display the retrieved data from native to phonegap(HTML)page.
can anyone pls guide me how to access sqlite with phonegap.?
Thanks in advance.
You need to first create a Android plugin for Phonegap through which you will be able to access the native code and hence the native DB like this
public class SqlitePlugin extends Plugin {
private static final String TAG = "SqlitePlugin";
private static final String CREATE_DB_ACTION = "createDatabase";
private static final String SHOW_DB_VALUES_ACTION = "showValues";
#Override
public PluginResult execute(String action, JSONArray data, String callbackId) {
Log.i(TAG, "Plugin Called");
PluginResult result = null;
if (CREATE_DB_ACTION.equals(action)) {
Log.d(TAG, "CREATE_DB_ACTION");
DB _db = new DB(ctx);
_db.insertValues();
}
else if (SHOW_DB_VALUES_ACTION.equals(action)) {
Log.d(TAG, "SHOW_DB_VALUES_ACTION");
JSONObject DBInfo = null;
try {
DBInfo = getDBValuesListing();
} catch (JSONException e) {
e.printStackTrace();
}
result = new PluginResult(Status.OK, DBInfo);
}
else {
result = new PluginResult(Status.INVALID_ACTION);
Log.d(TAG, "Invalid action : " + action + " passed");
}
return result;
}
}
After that Create a sqlite.js file like this
function SqlitePlugin() {
};
SqlitePlugin.prototype.createDatabase = function(successCallback, failCallback) {
return PhoneGap.exec(successCallback, failCallback, "SqlitePlugin",
"createDatabase", [ null ]);
};
SqlitePlugin.prototype.showValues = function(params, successCallback, failCallback) {
return PhoneGap.exec(successCallback, failCallback, 'SqlitePlugin', 'showValues',
[ params ]);
};
PhoneGap.addConstructor(function() {
PhoneGap.addPlugin("SqlitePlugin", new SqlitePlugin());
});
Import this sqlite.js in your page(index.html) and then finally use the plugin like this
function showValues() {
window.plugins.SqlitePlugin.showValues('showValues',
showValuesSuccessCallBack, showValuesFailCallBack);
}
function showValuesSuccessCallBack(e) {
if (e.Rows.length > 0) {
alert("Success");
for (i = 0; i < e.Rows.length; i++) {
alert("Id = " + e.Rows[i].id);
alert("Number = " + e.Rows[i].number);
}
} else {
alert("No values in Database");
}
}
function showValuesFailCallBack(f) {
alert("Failure");
}
Let me know if this worked out for you
Write an phonegap plugin to pass the data from native side to html (js)
http://wiki.phonegap.com/w/page/36753494/How%20to%20Create%20a%20PhoneGap%20Plugin%20for%20Android
Well, you probably should use the HTML5 functions to store and retrieve data from a sqlite DB. However, if you are set on doing it with native code you should look at our implementation which was used for older Android devices that don't support sqlite.
https://github.com/cordova/cordova-android/blob/master/framework/assets/js/storage.js
https://github.com/cordova/cordova-android/blob/master/framework/src/com/phonegap/Storage.java