Call activity using intent method - c#

I know that Android OS need paramterles constructor to recreate Activity and i could use bundle to pass some arguments if required as follows:
private void OpenOtherActivityWindow_Click(object sender, EventArgs e)
{
Intent nextActivity = new Intent(this, typeof(ThirdActivity));
Dog mydog = new Dog("mydogName");
Bundle bundle = new Bundle();
bundle.PutSerializable("mydoggy", mydog);
nextActivity.PutExtra("RowID", Convert.ToString(10));
nextActivity.PutExtras(bundle);
StartActivity(nextActivity);
}
[Activity(Label = "ThirdActivity")]
public class ThirdActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your application here
SetContentView(Resource.Layout.third);
//Receive values if any from previous activity
if (!Intent.HasExtra("mydoggy")) return;
Dog tryme = (Dog)Intent.GetSerializableExtra("mydoggy");
if (!Intent.HasExtra("RowID")) return;
string text = Intent.GetStringExtra("RowID") ?? "0";
}
}
Nevertheless is it possible to create static method which would return intent for me from given parameters like?:
static Intent CreateIntent(Dog dog, int rowID)
If so could someone show me then how it could look like as opposite to whati show in my code please.

I don't know the details of your ThirdActivity, but I could achieve the similar function by creating a simple demo.
You can check the code here.
[Activity(Label = "MovieDetailActivity")]
public class MovieDetailActivity : Activity
{
public TextView textView;
public static MovieModel mMoviemodel;// define your model here
public static int mRowID; // define a int variable mRowID
public static Intent createIntent(Context context, MovieModel movie, int rowID)
{
Intent intent = new Intent(context, typeof(MovieDetailActivity));
//Pass parameters here
mMoviemodel = movie;
mRowID = rowID;
return intent;
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your application here
SetContentView(Resource.Layout.detaillayout);
textView = FindViewById<TextView>(Resource.Id.info_textview);
textView.Text = "movie name:" + mMoviemodel.mMovieName + " text = " + mRowID;
}
}
Usage:
// pass your Object model
StartActivity( MovieDetailActivity.createIntent(this, movie,10));

Related

Refresh Fragment From Activity After Updating Data on SQLite Xamarin Android

I got an issue with my Android program when updating user data on Fragment_profile. Fragment_Profile loads User profile data and contains an update button in which the button navigates to an activity called EditProfileActivity. Users can technically update the data but, after they save the updated data, the data still can't be updated. The old data still appear. I try to refresh the fragment by using OnResume() and add OnRestart on my EditProfileActivity.cs and OnPause both in fragment and activity but, still nothing. I am using Xamarin Android and develop it with C#. For more info, you can see what happened in the GIF
My issue
So far, I've tried to code, and here's my code.
Fragment_profile.cs
public class Fragment_Profile : Android.Support.V4.App.Fragment
{
public HomePageActivity m_currentActivity;
public TextView m_tv_loginname, m_tv_username, m_tv_fullname , m_tv_dob;
public Boolean isRefreshing = false;
public override void OnCreate(Bundle aSavedInstanceState)
{
base.OnCreate(aSavedInstanceState);
}
//public static Fragment_Profile NewInstance(Model.User aCurrentUser)
public static Fragment_Profile NewInstance()
{
var _frag4 = new Fragment_Profile { Arguments = new Bundle() };
return _frag4;
}
public override View OnCreateView(LayoutInflater aInflater, ViewGroup aContainer, Bundle aSavedInstanceState)
{
var _ignored = base.OnCreateView(aInflater, aContainer, aSavedInstanceState);
var view= aInflater.Inflate(Resource.Layout.FragmentProfile, null);
m_tv_loginname = view.FindViewById<TextView>(Resource.Id.tv_loginname);
m_tv_username = view.FindViewById<TextView>(Resource.Id.tv_userEmail);
m_tv_fullname = view.FindViewById<TextView>(Resource.Id.tv_fullname);
m_tv_dob = view.FindViewById<TextView>(Resource.Id.tv_dob);
Button _updateProfile = view.FindViewById<Button>(Resource.Id.btnUpdateProfile);
_updateProfile.Click += _updateProfile_Click;
m_currentActivity = (HomePageActivity)this.Activity;
if (m_currentActivity.CurrentUser != null)
{
//string = "Welcome, " + m_currentActivity.CurrentUser.UserName;
m_tv_loginname.Text = m_currentActivity.CurrentUser.LoginName;
m_tv_fullname.Text = m_currentActivity.CurrentUser.UserName;
m_tv_username.Text = m_currentActivity.CurrentUser.UserEmail;
m_tv_dob.Text = m_currentActivity.CurrentUser.DateOfBirth;
}
else
{
Toast.MakeText(Activity, "The data is not found!", ToastLength.Short).Show();
Intent i = new Intent(Context, typeof(MainActivity));
StartActivity(i);
this.Activity.Finish();
}
return view;
}
private void _updateProfile_Click(object sender, EventArgs e)
{
Intent i = new Intent(Context, typeof(EditProfileActivity));
i.PutExtra("loginname", m_currentActivity.CurrentUser.LoginName);
i.PutExtra("fullname", m_currentActivity.CurrentUser.UserName);
i.PutExtra("useremail", m_currentActivity.CurrentUser.UserEmail);
i.PutExtra("dob", m_currentActivity.CurrentUser.DateOfBirth);
StartActivity(i);
}
public override void OnResume()
{
base.OnResume();
if (isRefreshing)
{
Fragment fragment = new Fragment_Profile();
Android.Support.V4.App.FragmentManager fragmentMg = Activity.SupportFragmentManager;
FragmentTransaction fragmentTrans = fragmentMg.BeginTransaction();
fragmentTrans.Replace(Resource.Id.content_frame, fragment);
fragmentTrans.Detach(fragment);
fragmentTrans.Attach(fragment);
fragmentTrans.Commit();
//adapter.notifyDataSetChanged();
}
}
public override void OnPause()
{
base.OnPause();
isRefreshing = true;
}
}
When user click the _updateProfile button It will reference to next activity which is EditProfileActivity. Here's my EditProfileActivity.cs
public class EditProfileActivity : Activity, IOnDateSetListener
{
public EditText m_editFullName, m_editUsername, m_dob;
public TextView m_tvEmail;
public Button m_btnUpdate;
public Boolean isRefreshing = false;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.EditProfile);
m_editFullName = FindViewById<EditText>(Resource.Id.et_editfullName);
m_editUsername = FindViewById<EditText>(Resource.Id.et_editUserName);
m_tvEmail = FindViewById<TextView>(Resource.Id.tv_Email);
m_dob = FindViewById<EditText>(Resource.Id.et_editDob);
m_btnUpdate = FindViewById<Button>(Resource.Id.btn_updateprofile);
m_btnUpdate.Click += _btnUpdate_Click;
m_dob.Click += _dob_Click;
Bundle extras = Intent.Extras;
m_editFullName.Text = extras.GetString("loginname");
m_editUsername.Text = extras.GetString("fullname");
m_tvEmail.Text = extras.GetString("useremail");
m_dob.Text = extras.GetString("dob");
}
private void _btnUpdate_Click(object sender, EventArgs e)
{
try
{
Model.User _currentUser = Model.User.CheckEmailUser(m_tvEmail.Text);
_currentUser.UserName = m_editUsername.Text;
_currentUser.LoginName = m_editFullName.Text;
_currentUser.UserEmail = m_tvEmail.Text;
_currentUser.DateOfBirth = m_dob.Text;
var _updated = DBManager.Instance.Update(_currentUser);
if (_updated > 0)
{
Toast.MakeText(this, "Your account has been succesfully updated!", ToastLength.Long).Show();
Finish();
OnResume();
}
else
{
Toast.MakeText(this, "Failed to update!", ToastLength.Long).Show();
}
}
catch(Exception ex)
{
Toast.MakeText(this, ex.ToString(), ToastLength.Short).Show();
}
}
private void _dob_Click(object sender, EventArgs e)
{
var _dateTimeNow = DateTime.Now;
DatePickerDialog _datepicker = new DatePickerDialog(this, this
, _dateTimeNow.Year, _dateTimeNow.Month, _dateTimeNow.Day);
_datepicker.Show();
}
public void OnDateSet(DatePicker view, int year, int month, int dayOfMonth)
{
m_dob.Text = new DateTime(year, month + 1, dayOfMonth).ToShortDateString();
}
protected override void OnRestart()
{
base.OnRestart();
if (isRefreshing)
{
isRefreshing = false;
Finish();
}
}
protected override void OnPause()
{
base.OnPause();
if (!isRefreshing)
isRefreshing = true;
}
}
I also have read some articles that have the same problems as me but, It still confusing me and still same. I know it's a simple thing but, It took a few days for me because I am a newby and I still don't get the solution.
Do you guys have any ideas? Would you like to help me? If you don't mind please check my source code so, I know what I am missing. Thank in advance for your help!
In you Fragment, you can override the OnResume method. If you back to the fragment from Acitivty. you should query the new data from DB, then set the new value to the controls in Fragment.
public override void OnResume()
{
base.OnResume();
PHName.Text = photoDAO.GetFirstPhotos(Id).PhotoName;
}
Here is running GIF.
You can see this lifecycle about Fragment. Every time you display the Fragment,OnResume method will be executed. You get the newest data from DB, then set it to the Fragment page.
Here is my demo.
https://drive.google.com/file/d/11dROKS7TtqAaVYkG8w6ZKpqnQJRBD87E/view

OnCreateView Called twice

I'm trying to create an activity with two tabs, one holding FragmentA and one holding FragmentB. Here is how I add the fragments to the Activity:
[Activity(Label = "My App")]
public class MyActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.ConnectionMenu);
ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
AddTab("A", new FragmentA());
AddTab("B", new FragmentB());
}
private void AddTab(string tabText, Fragment fragment)
{
var tab = ActionBar.NewTab();
tab.SetText(tabText);
tab.TabSelected += (sender, e) =>
{
e.FragmentTransaction.Replace(
Resource.Id.fragmentContainer,
fragment);
};
ActionBar.AddTab(tab);
}
}
When I rotate the orientation I want to keep fields filled out in the fragments the same. I save my data in OnSaveInstanceState and restore the data in OnActivityCreated. However, I'm noticing that the OnCreateView and OnActivityCreated methods are being called twice per rotate. The first time containing my filled in Bundle and the second time with bundle being null.
I assume that my error is in the MyActivity class but if you need more information let me know!
Given you create the fragment in your Activity.OnCreate(), you will always have 2 calls due to creating new ones in the method, and maintaining the old ones in the base.OnCreate(). What you should probably do is instead of always creating these fragments, you can search via a tag or ID for an existing fragment and use those in the Tabs instead.
i.e.
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.ConnectionMenu);
ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
if(savedInstanceState == null)
{
AddTab("A", new FragmentA());
AddTab("B", new FragmentB());
}
else
{
Fragment a = (FragmentA)SupportFragmentManager.FindFragmentByTag("my_tag_a");
Fragment b = (FragmentB)SupportFragmentManager.FindFragmentByTag("my_tag_b");
AddTab("A", a);
AddTab("B", b);
}
}
I ended up solving the issue. as #JonDouglas said you need to make sure the tab wasn't already loaded before creating a new fragment. To do this the fragment can be loaded from the FragmentManager class using a tag. During the TabSelected event if the fragment was not previously create, a new fragment is created and added to the event FragmentTransaction using the tag. During the TabUnselected event, if the fragment was created then it is detached.
I also added in a Bundle value to hold onto the last active tab.
Here is the code I used to solve the issue.
[Activity(Label = "My App")]
public class MyActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.ConnectionMenu);
ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
AddTab("A", "a_fragment", () => new FragmentA());
AddTab("B", "b_fragment", () => new FragmentB());
if (savedInstanceState != null)
{
var selectedTab = savedInstanceState.GetInt(
"ActionBar.SelectedNavigationIndex", 0);
ActionBar.SetSelectedNavigationItem(selectedTab);
}
}
protected override void OnSaveInstanceState(Bundle savedInstanceState)
{
base.OnSaveInstanceState(savedInstanceState);
savedInstanceState.PutInt(
"ActionBar.SelectedNavigationIndex",
ActionBar.SelectedNavigationIndex);
}
private void AddTab<TFragment>(
string tabText,
string tag,
Func<TFragment> ctor) where TFragment : Fragment
{
var tab = ActionBar.NewTab();
tab.SetText(tabText);
tab.SetTag(tag);
var fragment = FragmentManager.FindFragmentByTag<TFragment>(tag);
tab.TabSelected += (sender, e) =>
{
if (fragment == null)
{
fragment = ctor.Invoke();
e.FragmentTransaction.Add(
Resource.Id.fragmentContainer,
fragment,
tag);
}
else
{
e.FragmentTransaction.Attach(fragment);
}
};
tab.TabUnselected += (sender, e) =>
{
if (fragment != null)
{
e.FragmentTransaction.Detach(fragment);
}
};
ActionBar.AddTab(tab);
}
}

How to pass data between tabs on Xamarin Android?

I have two tabs in viewpager. So in fragment1 I input a text and when in tab2 is selected and then fragment2 will get data from that text from fragment1.
ex: when I open tab1 -> I input a text is "abcd" -> I open tab2 -> I want to get a text is "abcd" from tab1(fragment1).
public class Fragment1 : Android.Support.V4.App.Fragment
{
Fragment2 frag2 = new Fragment2();
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
// return inflater.Inflate(Resource.Layout.YourFragment, container, false);
Singleton singleton = Singleton.GetInstance();;
singleton.SetSource("abcd");
}
}public class Singleton
{
private static Singleton singleton;
string a = null;
private Singleton()
{
}
public static Singleton GetInstance()
{
if (singleton == null)
singleton = new Singleton();
return singleton;
}
public void SetSource(string text)
{
this.a = text;
}
public string showMessage()
{
return a;
}
}
public class Fragment2 : Android.Support.V4.App.Fragment
{
public List<string> data = new List<string>();
public void add(string t)
{
data.Add(t);
}
TextView txt;
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
// return inflater.Inflate(Resource.Layout.YourFragment, container, false);
//return base.OnCreateView(inflater, container, savedInstanceState);
return inflater.Inflate(Resource.Layout.view2, container, false);
txt = View.FindViewById<TextView>(Resource.Id.txtgetdata);
if (data != null)
{
txt.Text = data[0];
}
else
Toast.MakeText(Application.Context, "no", ToastLength.Long).Show();
}
}
I have tried it but don't having the result.
After a few hours of research/test & debugging and solved, try this out.
In your Activity
add public string tabFragment { get; set; }
In your source fragment
ie on click or that navigate to other fragment
string tab = ((ActivityUser)Activity).tabFragmentAddUser;
FragmentAddUser fragment = (FragmentAddUser);
Activity.SupportFragmentManager.FindFragmentByTag(tab);
fragment.setValText("Hello");
viewPager.SetCurrentItem(1, true);
In your destination fragment (ie which elements will be modified)
add a method like this
public void setValText(string str) { txtUsrFirstName.Text = str; }
==================================================================
Fragment fragment = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt(key, value);
fragment.SetArguments(bundle);
in on create of the other fragment
Bundle bundle = this.GetArguments();
int myInt = bundle.GetInt(key, defaultValue);
optionaly two fragments should never communicate directly and should communicate through activity
From Developers website:
Often you will want one Fragment to communicate with another, for
example to change the content based on a user event. All
Fragment-to-Fragment communication is done through the associated
Activity. Two Fragments should never communicate directly.
refer this and this

Save products in basket , when close activity

I have basket activity when I add products from list of products.
Code of adding attributes
add.Click += delegate {
var intent = new Intent (this, typeof(CartActivity));
intent.PutExtra ("title", (string)(firstitem ["post_title"]));
intent.PutExtra ("price", (string)(firstitem ["price"] + " грн"));
intent.PutExtra ("weight", (string)(firstitem ["weight"] + "г"));
StartActivity (intent);
};
Code of receiving attributes
productname.Text = Intent.GetStringExtra("title");
price.Text = Intent.GetStringExtra("price");
weight.Text = Intent.GetStringExtra("weight");
I tried OnPause
namespace MurakamiKiev
{
[Activity(Label = "Murakami", Icon = "#drawable/logo", Theme = "#android:style/Theme.Black.NoTitleBar", ScreenOrientation = ScreenOrientation.Portrait)]
public class CartActivity : Activity
{
protected override void OnPause()
{
base.OnPause();
But when I run activity I have black screen
Did you call SetContentView() in OnCreate()?
like this
namespace MurakamiKiev
{
[Activity(Label = "Murakami", Icon = "#drawable/logo", Theme = "#android:style/Theme.Black.NoTitleBar", ScreenOrientation = ScreenOrientation.Portrait)]
public class CartActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.YourLayout);
}
}
}

Create instance of ActionBar Xamarin Android

Iam using A ActionBar in my app. I have done something like so:-
ActionBar.SetDisplayHomeAsUpEnabled(true);
ActionBar.SetHomeButtonEnabled(true);
But I get a compilation error like:-
A object reference is required for the non-static field, method, or property 'Android.Support.V7.App.ActionBar.SetDisplayHomeAsUpEnabled(bool)'
How can I create a instance of ActionBar as it is a Abstract class?
EDIT:-
With waquaslam's solution I did this:-
public class Homescreen : ActionBarActivity
{
private DrawerLayout _drawer;
private MyActionBarDrawerToggle _drawerToggle;
private ListView _drawerList;
private static ActionBar ActionBar ;
private string _drawerTitle;
private string _title;
private string[] _planetTitles;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SupportRequestWindowFeature(WindowCompat.FeatureActionBar);
SetContentView(Resource.Layout.homescreen);
_title = _drawerTitle = Title;
_planetTitles = Resources.GetStringArray(Resource.Array.TitlesArray);
_drawer = FindViewById<DrawerLayout>(Resource.Id.drawer_layout);
_drawerList = FindViewById<ListView>(Resource.Id.left_drawer);
_drawer.SetDrawerShadow(Resource.Drawable.drawer_shadow_dark, (int)GravityFlags.Left);
_drawerList.Adapter = new ArrayAdapter<string>(this,
Resource.Layout.drawerlistitem, _planetTitles);
_drawerList.ItemClick += (sender, args) => SelectItem(args.Position);
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetHomeButtonEnabled(true);
//DrawerToggle is the animation that happens with the indicator next to the
//ActionBar icon.
_drawerToggle = new MyActionBarDrawerToggle(this, _drawer,
Resource.Drawable.ic_drawer_light,
Resource.String.DrawerOpen,
Resource.String.DrawerClose);
//You can alternatively use _drawer.DrawerClosed here
_drawerToggle.DrawerClosed += delegate
{
ActionBar.Title = _title;
//InvalidateOptionsMenu();
};
//You can alternatively use _drawer.DrawerOpened here
_drawerToggle.DrawerOpened += delegate
{
ActionBar.Title = _drawerTitle;
// InvalidateOptionsMenu();
};
_drawer.SetDrawerListener(_drawerToggle);
if (null == savedInstanceState)
SelectItem(0);
}
Now I get a NoClassDefinitionFoundError.
If you are using support.V7 then make sure your activity inherits from ActionBarActivity.
In order to get reference of ActionBar in compatibility library, you must need to use the following:
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetHomeButtonEnabled(true);
For more info, read this in which the example is based on Tabs in actionbar but using support library.

Categories

Resources