I have a class that gets longitude and latitude from user's device and and saves it to an SQLite database. Here's the code:
[Activity(Label = "GetLocation")]
public class GetLocation : Activity, ILocationListener
{
Button btncreate;
EditText txtlong;
EditText txtlat;
static readonly string TAG = "X:" + typeof(GetLocation).Name;
Location _currentLocation;
LocationManager _locationManager;
string _locationProvider;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.GetLocation);
txtlong = FindViewById<EditText>(Resource.Id.txtlong);
txtlat = FindViewById<EditText>(Resource.Id.txtlat);
btncreate = FindViewById<Button>(Resource.Id.btnvalidate);
btncreate.Click += Btncreate_Click;
InitializeLocationManager();
}
void InitializeLocationManager()
{
_locationManager = (LocationManager) GetSystemService(LocationService);
Criteria criteriaForLocationService = new Criteria
{
Accuracy = Accuracy.Fine
};
IList<string> acceptableLocationProviders = _locationManager.GetProviders(criteriaForLocationService, true);
if (acceptableLocationProviders.Any())
{
_locationProvider = acceptableLocationProviders.First();
}
else
{
_locationProvider = string.Empty;
}
Log.Debug(TAG, "Using " + _locationProvider + ".");
}
public void OnProviderDisabled(string provider) { }
public void OnProviderEnabled(string provider) { }
public void OnStatusChanged(string provider, Availability status, Bundle extras) { }
protected override void OnResume()
{
base.OnResume();
_locationManager.RequestLocationUpdates(_locationProvider, 0, 0, this);
}
protected override void OnPause()
{
base.OnPause();
_locationManager.RemoveUpdates(this);
}
public void OnLocationChanged(Location location)
{
_currentLocation = location;
if (_currentLocation == null)
{
txtlong.Text = "Unable to determine your location. Try again in a short while.";
txtlat.Text = "Unable to determine your location. Try again in a short while.";
}
else
{
txtlong.Text = _currentLocation.Longitude.ToString();
txtlat.Text = _currentLocation.Latitude.ToString();
}
}
private void Btncreate_Click(object sender, EventArgs e)
{
try
{
string dpPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "Location.db3");
var db = new SQLiteConnection(dpPath);
db.CreateTable<DataTable>();
DataTable tbl = new DataTable();
tbl.Longitude = txtlong.Text;
tbl.Latitude = txtlat.Text;
db.Insert(tbl);
NextPage();
Toast.MakeText(this, "Data Store Successfully...,", ToastLength.Short).Show();
}
catch (Exception ex)
{
Toast.MakeText(this, ex.ToString(), ToastLength.Short).Show();
}
}
void NextPage()
{
//code to get next page
}
}
the DataTable class is as follows:
class DataTable
{
[PrimaryKey, AutoIncrement, Column("_Id")]
public int Id {get; set;}
public string Longitude { get; set; }
public string Latitude { get; set; }
}
once it has saved the data, I would like another class (activity) to be able to display it on a separate .axml page. my problem is I am a programmer in training (college) and have no clue what to do. Your help is greatly appreciated.
You need to start a new activity using
StartActivity(typeof(Activity2));
and in the OnCreate of your Activity2 set you new .axml layout:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.MyView);
}
Then to retrieve the data use Query:
string dpPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "Location.db3");
var db = new SQLiteConnection(dpPath);
var dataTables = db.Query<DataTable>("select * from DataTable");
I'd recommend you to read SQLite: GettingStarted and if you want to improve that move all about SQLite to another class to reuse the code of openning an SQLiteConnection. Also if you can use asynchronous calls in order to prevent blocking the UI while persisting data in your database.
Also check Xamarin Android docs that is really helpful
HIH
Related
Started with Xamarin Android yesterday and can't seem to figure out why the Back Button script(s) won't be called.
Searched and seen that a lot of people recommend something like this:
public override void OnBackPressed()
{
Toast.MakeText(this, "Back Button Pressed", ToastLength.Short).Show();
}
However this doesn't stop my phone or the android emulator from closing the app instantly.
Most of the things I have found about this thread I haven't managed to make work for some reason or they won't be called.
Thanks
Update:
Checked another project. It works 100% there with the same code as above. Not sure what makes it not work in my project
Update
Here is some of the code. I know it's terrible but I'm just messing around trying to learn as I'm a total newbie with Xamarin & Android - Feel free to give links on something I should read however!
namespace Workout_App {
[Activity(Label = "Workout App", MainLauncher = true)]
public class MainActivity : Activity
{
private List<Exercise> mItems, mItemsDay1;
private ListView mListView;
MyListViewAdapter adapter, adapter2;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
mListView = FindViewById<ListView>(Resource.Id.myListView); // myListView er navnet på objekte i AXML fila f.eks
mItems = new List<Exercise>();
mItemsDay1 = new List<Exercise>();
mItems.Add(new Exercise() { Name = "Day 1"});
mItems.Add(new Exercise() { Name = "Day 2"});
mItems.Add(new Exercise() { Name = "Day 3"});
mItemsDay1.Add(new Exercise() { Name = "Benkpress", Reps = "8x4", kg = 140});
mItemsDay1.Add(new Exercise() { Name = "Lårpress", Reps = "8x4", kg = 58});
mItemsDay1.Add(new Exercise() { Name = "BankPro", Reps = "8x4", kg = 22});
adapter = new MyListViewAdapter(this, mItems);
adapter2 = new MyListViewAdapter(this, mItemsDay1);
mListView.Adapter = adapter;
mListView.ItemClick += mListView_ItemClick; // subscribes it, - to unsub
mListView.ItemLongClick += mListView_ItemLongClick;
// mListView.ItemClick += mListView_ItemClick2;
}
public override void OnBackPressed()
{
Toast.MakeText(this, "Back Button Pressed Detected", ToastLength.Short).Show();
}
void mListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
mListView.Adapter = adapter2;
}
And this is the view
namespace Workout_App {
class MyListViewAdapter : BaseAdapter<Exercise>
{
public List<Exercise> mItems;
private Context mContext;
public MyListViewAdapter(Context context, List<Exercise> items)
{
mItems = items;
mContext = context;
}
public override int Count
{
get { return mItems.Count; }
}
public override long GetItemId(int position)
{
return position;
}
public override Exercise this[int position]
{
get { return mItems[position]; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View row = convertView;
if(row == null)
{
row = LayoutInflater.From(mContext).Inflate(Resource.Layout.listview_row, null, false );
}
TextView txtName = row.FindViewById<TextView>(Resource.Id.txtName);
txtName.Text = mItems[position].Name;
TextView txtReps = row.FindViewById <TextView>(Resource.Id.txtReps);
txtReps.Text = mItems[position].Reps;
TextView txtKg = row.FindViewById<TextView>(Resource.Id.txtKg);
if(mItems[position].kg > 0) {
txtKg.Text = mItems[position].kg + " kg";
} else
{
txtKg.Text = "";
}
return row;
}
}
}
I'm trying to figure out in my customer's Mobile what causes black screens of death. The apk in different places and random moments causes a black screen of death and application stucks. I have place exceptions almost everywhere but i dont get any exception message.I will send you an examample from my code:
What can cause this black screens???
Here is my class:
class MyListViewAdapterInventory : BaseAdapter<InventoryPreviewClass>
{
public List<InventoryPreviewClass> mitems;
private Context mContext;
private int mRowLayout;
private int[] mAlternatingColors;
public MyListViewAdapterInventory(Context context, int rowLayout, List<InventoryPreviewClass> items)
{
mitems = items;
mContext = context;
mRowLayout = rowLayout;
mAlternatingColors = new int[] { 0xF2F2F2, 0xbfddff };
}
public override int Count
{
get
{
return mitems.Count;
}
}
public override long GetItemId(int position)
{
return position;
}
public override InventoryPreviewClass this[int position]
{
get
{
return mitems[position];
}
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View row = convertView;
if (row == null)
{
row = LayoutInflater.From(mContext).Inflate(Resource.Layout.InventoryPreview, null, false);
}
row = LayoutInflater.From(mContext).Inflate(Resource.Layout.InventoryPreview, null, false);
row.SetBackgroundColor(GetColorFromInteger(mAlternatingColors[position % mAlternatingColors.Length]));
TextView txtInventoryID = row.FindViewById<TextView>(Resource.Id.txtInventoryID);
txtInventoryID.Text = mitems[position].InventoryItemID;
TextView txtInventoryName = row.FindViewById<TextView>(Resource.Id.txtInventoryName);
txtInventoryName.Text = mitems[position].InventoryItemName;
TextView txtInventoryPrice = row.FindViewById<TextView>(Resource.Id.txtInventoryPrice);
txtInventoryPrice.Text = mitems[position].InventoryItemPrice.Replace(",", ".");
Button ExtraBtn = row.FindViewById<Button>(Resource.Id.ExtrasBtn);
ExtraBtn.Click += (sender, e) =>
{
try
{
Connection.InventoryItemID = mitems[position].InventoryItemID;
Connection.InventoryItemName = mitems[position].InventoryItemName;
Connection.RetailPrice = mitems[position].InventoryItemPrice;
Toast toast = Toast.MakeText(mContext, txtInventoryName.Text, ToastLength.Short);
toast.Show();
mContext.StartActivity(typeof(ExtrasPreviewMain));
}
catch (Exception ex)
{
Toast toast = Toast.MakeText(mContext, Convert.ToString(ex), ToastLength.Long);
toast.Show();
}
};
return row;
}
private Color GetColorFromInteger(int color)
{
return Color.Rgb(Color.GetRedComponent(color), Color.GetGreenComponent(color), Color.GetBlueComponent(color));
}
}
And here is my activity Main when running:
private List<InventoryPreviewClass> mItems;
private ListView mlistview;
private EditText mSearch;
private EditText etSearchAlwaysOn;
private LinearLayout mContainer;
private bool mAnimatedDown;
private bool mIsAnimating;
private MyListViewAdapterInventory mAdapter;
string dpPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "student.db3");
SQLiteConnection db;
private TextView mTxtHeaderFirstName;
private TextView mTxtHeaderLastName;
private bool mFirstNameAscending;
private bool mLastNameAscending;
protected override void OnCreate(Bundle savedInstanceState)
{
try
{
ActionBar.SetHomeButtonEnabled(true);
ActionBar.SetDisplayHomeAsUpEnabled(true);
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.InventoryPreviewMain);
OverridePendingTransition(Resource.Layout.trans_left_in, Resource.Layout.trans_left_out);
mSearch = FindViewById<EditText>(Resource.Id.etSearch);
etSearchAlwaysOn = FindViewById<EditText>(Resource.Id.etSearchAlwaysOn);
mContainer = FindViewById<LinearLayout>(Resource.Id.llContainer);
mTxtHeaderFirstName = FindViewById<TextView>(Resource.Id.txtHeaderFirstName);
mTxtHeaderLastName = FindViewById<TextView>(Resource.Id.txtHeaderLastName);
mTxtHeaderFirstName.Click += mTxtHeaderFirstName_Click;
mTxtHeaderLastName.Click += mTxtHeaderLastName_Click;
mSearch.Alpha = 0;
mContainer.BringToFront();
mSearch.TextChanged += mSearch_TextChanged;
etSearchAlwaysOn.TextChanged += EtSearchAlwaysOn_TextChanged;
mlistview = FindViewById<ListView>(Resource.Id.InventoryList);
}
catch (Exception ex)
{
Toast.MakeText(this, Convert.ToString(ex), ToastLength.Short).Show();
}
try
{
db = new SQLiteConnection(dpPath);
var table = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID =" + Connection.CategoryID+ "");
mItems = new List<InventoryPreviewClass>();
foreach (var item in table)
{
mItems.Add(new InventoryPreviewClass() { InventoryItemID = item.InventoryItemID, InventoryItemName = item.InventoryItemName, InventoryItemPrice = item.InventoryItemPrice });
}
MyListViewAdapterInventory adapter = new MyListViewAdapterInventory(this, Resource.Layout.InventoryPreview, mItems);
mlistview.Adapter = adapter;
mlistview.ItemClick += Mlistview_ItemClick;
}
catch
{
}
try
{
if (SearchAlwaysOn == true)
{
var param = (LinearLayout.LayoutParams)etSearchAlwaysOn.LayoutParameters;
var WidthParam = ViewGroup.LayoutParams.MatchParent;
var HeigthParam = ViewGroup.LayoutParams.WrapContent;
param.Width = WidthParam;
param.Height = HeigthParam;
mIsAnimating = true;
}
}
catch (Exception ex)
{
Toast.MakeText(this, Convert.ToString(ex), ToastLength.Short).Show();
}
}
using Android.App;
using Android.Widget;
using Android.OS;
using Android.Locations;
using Android.Content;
[Activity(Label = "Getlocation", MainLauncher = true)]
public class MainActivity : Activity, ILocationListener
{
Button bttnGo;
TextView txtLoc;
LocationManager locMgr;
Location currentLocation;
string provider;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
bttnGo = FindViewById<Button>(Resource.Id.get_address_button);
txtLoc = FindViewById<TextView>(Resource.Id.location_text);
InitializeLocationManager();
bttnGo.Click += BttnGo_Click;
}
async void BttnGo_Click(object sender, EventArgs e)
{
if (currentLocation == null)
{
txtLoc.Text = "No location found, try moving around";
}
else
{
txtLoc.Text = currentLocation.ToString();
}
}
private void InitializeLocationManager()
{
locMgr = (LocationManager)GetSystemService(LocationService);
Criteria criteriaForLocationService = new Criteria
{
Accuracy = Accuracy.Fine
};
IList<string> acceptableLocationProviders = locMgr.GetProviders(criteriaForLocationService, true);
if(acceptableLocationProviders.Any())
{
provider = acceptableLocationProviders.First();
}
else
{
provider = string.Empty;
}
}
protected override void OnResume()
{
base.OnResume();
locMgr.RequestLocationUpdates(provider, 2000, 0, this);
}
protected override void OnPause()
{
base.OnPause();
locMgr.RemoveUpdates(this);
}
public void OnLocationChanged(Location location)
{
currentLocation = location;
if (currentLocation == null)
{
txtLoc.Text = "No location detected";
}
else
{
txtLoc.Text = location.Latitude.ToString();
}
}
public void OnProviderDisabled(string provider)
{
}
public void OnProviderEnabled(string provider)
{
}
public void OnStatusChanged(string provider, [GeneratedEnum] Availability status, Bundle extras)
{
}
}
}
My coding knowledge is minimal and I was just following a tutorial to retrieve current location.
My problem is that I can only retrieve the location when the actual location changes. I know this is probably because of currentLocation not getting a value until OnLocationChanged happens. how to go around this?
Xamarin android get location before location changes
You could use GetLastKnownLocation(provider) method to implement this feature. Here is a simple demo :
LocationManager locationManager = (LocationManager)GetSystemService(Context.LocationService);
IList<String> lp = locationManager.AllProviders;
foreach (String item in lp)
{
Log.Debug("TAG", "Available Location Service :" + item);
}
//A class indicating the application criteria for selecting a location provider.
Criteria criteria = new Criteria();
//Indicates whether the provider is allowed to incur monetary cost.
criteria.CostAllowed = false;
//Set desired accuracy of location Accuracy
criteria.Accuracy = Accuracy.Coarse;
//Returns the name of the provider that best meets the given criteria
String providerName = locationManager.GetBestProvider(criteria, true);
Log.Debug("8023", "------Location Service:" + providerName);
//Directly choose a Location Provider
//String providerName = LocationManager.GpsProvider;
Location location = locationManager.GetLastKnownLocation(providerName);
double lat = location.Latitude;
double lng = location.Longitude;
txtLoc.Text = "Latitude = " + lat + ", Longitude = " + lng;
I have tried to look out for an answer to the behavior of my views but I seem not find any question or solution related to it. My recycler views seemed to be set up well. I just realized that my app is not responding in the right way to the OnClickListeners.
I have set up toasts in my adapter for the recycler view click events. When i have 10 views. When i click on a view, it gives a text of another view. It seems it randomly gives me the text of another view amongst the 9 remaining views. What could be the cause of this?
Activity
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
FrameLayout content = (FrameLayout)FindViewById(Resource.Id.content_frame);
LayoutInflater.Inflate(Resource.Layout.Main, content);
setUpRecyclerView();
}
public void setUpRecyclerView(){
rv = FindViewById<RecyclerView>(Resource.Id.recyclerView);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.Orientation = LinearLayoutManager.Vertical;
layoutManager.ReverseLayout = true;
layoutManager.StackFromEnd = true;
rv.HasFixedSize = true;
rv.SetLayoutManager(layoutManager);
}
Adapter
public class FeedViewHolder : RecyclerView.ViewHolder, View.IOnClickListener, View.IOnLongClickListener
{
public FeedViewHolder(View itemView):base(itemView)
{
//binding of variables here
itemView.SetOnClickListener(this);
itemView.SetOnLongClickListener(this);
}
public void OnClick(View v)
{
itemClickListener.OnClick(v, AdapterPosition, false);
}
public bool OnLongClick(View v)
{
itemClickListener.OnClick(v, AdapterPosition, true);
return true;
}
public class FeedAdapter : RecyclerView.Adapter, ItemClickListener
{
public FeedAdapter(RssObject rssObject, Context mContext)
{
this.mContext = mContext;
this.inflater = LayoutInflater.From(mContext);
activity = (MainActivity)mContext;
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
hold = holder as FeedViewHolder;
//binding
hold.itemClickListener = this;
}
public void OnClick(View view, int position, bool isLongClick)
{
Toast.MakeText(activity, "Main text : " + hold.txtContent.Text, ToastLength.Long).Show();
}
public override int ItemCount
{
get { return rssObject.items.Count; }
}
}
}
}
in my activity I have this:
public class MainActivity : Activity
{
RelativeLayout mRelativeLayout;
Button mButton;
private Button mBtnSignUp;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
mRelativeLayout = FindViewById<RelativeLayout>(Resource.Id.mainView);
mButton = FindViewById<Button>(Resource.Id.btnLogin);
mButton.Click += mButton_Click;
mRelativeLayout.Click += mRelativeLayout_Click;
mBtnSignUp = FindViewById<Button> (Resource.Id.button1);
mBtnSignUp.Click += (object sender, EventArgs e) =>
{
//Pull up dialog
FragmentTransaction transaction = FragmentManager.BeginTransaction();
dialog_SignUp signUpDialog = new dialog_SignUp();
signUpDialog.Show(transaction, "dialog fragment");
signUpDialog.mOnSignUpComplete += signUpDialog_mOnSignUpComplete;
};
void signUpDialog_mOnSignUpComplete (object sender, OnSignUpEventArgs e)
{
Thread thread = new Thread (ActLikeARequest);
thread.Start ();
}
private void ActLikeARequest()
{
Thread.Sleep (3000);
}
And in the dialog I have:
public class OnSignUpEventArgs : EventArgs
{
private string mFirstName;
private string mEmail;
private string mPassword;
public string FirstName
{
get{ return mFirstName; }
set{ mFirstName=value;}
}
public string Email
{
get{ return mEmail; }
set{ mEmail=value;}
}
public string Password
{
get{ return mPassword; }
set{ mPassword=value;}
}
public OnSignUpEventArgs (string firstName, string email, string password) : base()
{
FirstName = firstName;
Email = email;
Password = password;
}
}
class dialog_SignUp:DialogFragment
{
private Button mBtnSignUp;
private EditText mFirstName;
private EditText mEmail;
private EditText mPassword;
public event EventHandler<OnSignUpEventArgs> mOnSignUpComplete;
public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView (inflater, container, savedInstanceState);
var view = inflater.Inflate (Resource.Layout.dialog_sign_up, container, false);
mBtnSignUp = view.FindViewById<Button> (Resource.Id.btnDialogEmail);
mFirstName = view.FindViewById<EditText> (Resource.Id.txtFirstName);
mEmail = view.FindViewById<EditText> (Resource.Id.txtEmail);
mPassword = view.FindViewById<EditText> (Resource.Id.txtPassword);
mBtnSignUp.Click += mBtnSignUp_Click;
return view;
}
void mBtnSignUp_Click (object sender, EventArgs e)
{
//User has clicked the sign up button
mOnSignUpComplete.Invoke (this, new OnSignUpEventArgs(mFirstName.Text, mEmail.Text, mPassword.Text));
this.Dismiss ();
}
public override void OnActivityCreated (Bundle savedInstanceState)
{
Dialog.Window.RequestFeature (WindowFeatures.NoTitle); //Sets the title bar to invisible
base.OnActivityCreated (savedInstanceState);
Dialog.Window.Attributes.WindowAnimations = Resource.Style.dialog_animation; //Set the animation
}
}
The question is, how can I pass data(strings) from the activity into the dialog, so that when it is called, the TextViews get the data I'm passing?
Is it something to add in the actitity, but what?
i think you need to be able to accept a parameter in your dialog_signup.
class dialog_SignUp:DialogFragment
{
private Button mBtnSignUp;
private EditText mFirstName;
private EditText mEmail;
private EditText mPassword;
String parameter="";
public event EventHandler<OnSignUpEventArgs> mOnSignUpComplete;
public dialog_SignUp(String parameterIn){
parameter=parameterIn;
}
public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView (inflater, container, savedInstanceState);
var view = inflater.Inflate (Resource.Layout.dialog_sign_up, container, false);
mBtnSignUp = view.FindViewById<Button> (Resource.Id.btnDialogEmail);
mFirstName = view.FindViewById<EditText> (Resource.Id.txtFirstName);
mFirstName.setText(parameter);
mEmail = view.FindViewById<EditText> (Resource.Id.txtEmail);
mPassword = view.FindViewById<EditText> (Resource.Id.txtPassword);
mBtnSignUp.Click += mBtnSignUp_Click;
return view;
}
then replace dialog_SignUp signUpDialog = new dialog_SignUp(); with dialog_SignUp signUpDialog = new dialog_SignUp(stringToSend);
Keep in mind that you can always use The Application class to define a variable there.
namespace YourNamespace
{
[Application]
public class App : Application
{
public ParseObject currentBusiness { get; set;}
public App (IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public override void OnCreate ()
{
base.OnCreate ();
currentBusiness = new ParseObject ("Business");
}
}
}
Then you can access it from evewhere in that way:
App _app = (App)Application.Context;
var curentBusiness = _app.currentBusiness;
You can use Property feature of Class.
Dialog Fragment Code
class Error : DialogFragment
{
public string getErrorMsg { get; set; } // this gets the message
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.Inflate(Resource.Layout.Error, container, false);
TextView text = view.FindViewById<TextView>(Resource.Id.txtError);
text.Text = getErrorMsg; //here the message is set to the TextView
return view;
}
}
Calling Method
FragmentTransaction transaction = FragmentManager.BeginTransaction();
Error obj = new Error();
obj.Cancelable = false;
obj.getErrorMsg = passMyString; // in this line you send message to The Class
obj.Show(transaction, "error");