i have login, register, and home page on my project. I use StartActivity(typeof(Register));to open register page. When user already insert data and click register button, i use StartActivity(typeof(MainActivity)); to go back to login page again.
When i click back button on my phone it back to register page>login page>then exit. I want my activity that already created is closed after i open a new page.
And my second question, i have exit button, how to close my app using the exit button?
I'm using Visual Studio 2015 and Xamarin for developing android app.
Calling Finish will close and kill the Activity and it will work as expected. Better way to remove an Avtivity so that it won't appear when Back button is pressed will be to set the NoHistory of that Activity as true.
If you have a LoginActivity and a DashboardActivity and you don't want the LoginActivity to show while pressing back-button after logging in, you can set NoHistory of LoginActivity as true, like below.
[Activity (NoHistory = true)]
public class LoginActivity : Activity
{
}
You can use Finish method to close your current activity:
StartActivity(typeof(MainActivity));
Finish();
To close the app, simply use
System.exit(0);
To remove an activity from navigation you can use finish keyword like that :
[Activity(Label = "MainActivity", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity: Activity
{
protected override async void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
var intent = new Intent(this, typeof(SecondActivity));
intent.SetFlags(ActivityFlags.NewTask);
//Navigation to SecondActivity
StartActivity(intent);
//delete main activity from navigation
Finish();
}
}
For the Second question you can use :
System.exit(0);
You have a very good explanation about this feature in this post for android that you can use for xamarin android :
Close Android Application
StartActivity(typeof(nameOfActivity));
// add this line
Finish();
You can't close previous activity in current activity. It only can be closed by itself.
But you can return data to previous activity. And in event handler OnActivityResult of previous activity, you can do close action.
This sample will be helpful for you. https://code.msdn.microsoft.com/How-to-close-activity-d51941c8
code below shows how to close previous activity.
In previous activity:
Intent intent = new Intent(this, typeof(RegisterActivity));
//for get result, we should use method StartActivityForResult
//the second param is the request code, it is the ID of this request, it should be >= 0
StartActivityForResult(intent, 1);
In current activity:
Intent intent = new Intent(this, typeof(RegisterActivity));
intent.PutExtra("result", "Success");
SetResult(Result.Ok, intent);
Finish();
//when back to login activity, the OnActivityResult event will be trigger.
And go back to previous activity:
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
//when regester activity retrun data, it will be execute
if (requestCode == 1 && resultCode == Result.Ok)
{
string result = data.GetStringExtra("result");
if (result == "Success")
{
Finish();
}
}
}
For your second question:
Just use this:
System.exit(0);
Related
Second activity is called from my First Activity
public static int REQUEST_CODE = 1;
myButton.Click += delegate
{
StartActivityForResult(typeof(SecondActivity), REQUEST_CODE);
};
In the First Activity I override OnActivityResult
protected override void OnActivityResult(int requestCode, Android.App.Result resultCode, Intent data)
{
if (requestCode == 1)
{
if (resultCode == Android.App.Result.Ok)
{
String newdata = data.GetStringExtra("data");
}
}
}
In my second activity I return to the first activity using the following code
Intent returnIntent = new Intent();
returnIntent.PutExtra("data", somedata);
SetResult(Android.App.Result.Ok, returnIntent);
Finish();
This all works well the first go round, I return to the first activity with the correct data. However, the next time the second activity is started, the data is stored correctly, but the activity doesn't finish. It is almost as if the Finish command is ignored and the activity is started again and OnCreate() is invoked. Following that, the next time the above code is invoked it returns to the first activity and two key value pairs are stored in the data. So the data is stored correctly, however the navigation is incorrect. Anyone have any ideas?
Use Intent to start an Activity
StartActivityForResult(new Intent(this, typeof(SecondActivity)), REQUEST_CODE);
I've made a notification for my media app (xamarin/android) that allows the user to play and pause the audio straight from the notification so the user doesn't have to get back into the app if they want to pause or play quickly.
However, each time the user hits my notification's button it also brings them back to the app. How can get it so that the user can be in a different application, go to the notification, hit the play/pause button but then return to whatever they were doing? Not bring them back to my app.
I thought it might have to do something with setting the launchmode to my activity but I have been messing around with it and haven't gotten anything to change yet.
This is my activity
[Activity]
public class SecondActivity : Activity
{
DabPlayer player = GlobalResources.playerPodcast;
EpisodeViewModel Episode;
DroidDabNativePlayer droid = new DroidDabNativePlayer();
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
if (player.IsReady)
{
if (player.IsPlaying)
{
player.Pause();
}
else
{
player.Play();
}
}
else
{
if (player.Load(Episode.Episode))
{
player.Play();
}
else
{
//DisplayAlert("Episode Unavailable", "The episode you are attempting to play is currently unavailable. Please try again later.", "OK");
}
}
Finish();
}
This is my android manifest
<application android:label="DAB">
<activity android:name="SecondActivity" launchMode="singleTop" />
I don't think you would really need to see the notification build but here it is in case it's helpful.
var builder = new NotificationCompat.Builder(Application.Context, CHANNEL_ID)
.SetStyle(new Android.Support.V4.Media.App.NotificationCompat.MediaStyle()
.SetShowActionsInCompactView(0))
.SetContentIntent(firstPendingIntent) // Start up this activity when the user clicks the intent.
.SetVisibility(NotificationCompat.VisibilityPublic)
.AddAction(Resource.Drawable.ic_media_play_dark, "Play", pendingIntent)
.SetMediaSession(mSession.SessionToken)
.SetContentText(GlobalResources.playerPodcast.EpisodeTitle)
.SetContentTitle(GlobalResources.playerPodcast.ChannelTitle);
.SetDeleteIntent(MediaButtonReceiver.BuildMediaButtonPendingIntent(Application.Context, PlaybackState.ActionStop))
.SetSmallIcon(Resource.Drawable.app_icon) // This is the icon to display
Any ideas how to call this play/pause function without having to bring the user back to the app?
I have one Fragment "AddNewIncomeFragment " with a TextView("#+id/lblAccountHead"). On click on textview it starts a new activity "AccountHeadListActivit" which shows a list of existing Account Head. On selection of account head from "AccountHeadListActivity" i want to update "lblAccountHead" of first activity with selected account name, other values need to be intact.
Earlier i did it using "messaging center" for xamarin form. Now i trying to do the same in xamarin native(android).
*****UPDATED WITH FIRST SOLUTION APPLIED****
Click event in AddNewIncomeFragment which start account head activity:
public void onAccounyHeadClick(object sender, EventArgs e)
{
var intend = new Intent(this.Activity, typeof(AccountHeadListActivity));
//this.StartActivity(intend);
this.StartActivityForResult(intend, 1000);
}
ListView Selection event of Account head activity
void OnSelection (object sender, SelectedItemChangedEventArgs e)
{
var result = new Intent();
result.PutExtra("name", "Salary Account");
result.PutExtra("id", 2);
SetResult(Result.Ok, result);
Finish();
}
On closing this activity i want to update textview of previous activity with selected account head name/id. Please share what option we have to do this in xamarin andriod, should use StartActivityForResult,Local Notifications or any best approach.
I have implemented above solution and it is working fine. But the issue is- 2nd activity "AccountHeadList" contains an add new account link which start a new activity "AddNewAccount"- Now if user create a new account and save it then this activity need to be closed and 1st activity need to updated with newly created account name. So basically "StartActivityForResult" failed when it involves three activity and need to updated 1st activity from 3rd activity- Please suggest.
Thanks,
#Paul
To receive a result, call
startActivityForResult() instead of startActivity()
then in your second activity, call the setResult(result) method to set the result before you finish the activity finish() after that in your original activity you can override the method
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// set the text view with the data from the result
}
I have a service that calls a Activity using the following code:
var activityIntent = new Intent(ApplicationContext, typeof(cptChamadaActivity));
activityIntent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTask | ActivityFlags.NoHistory);
StartActivity(activityIntent);
Inside the OnCreate method of the activity, I have that code:
base.OnCreate(bundle);
SetContentView(Resource.Layout.Chamada);
var simBtn = FindViewById<Button>(Resource.Id.simBtn);
var naoBtn = FindViewById<Button>(Resource.Id.naoBtn);
simBtn.Click += (sender, e) => { Finish(); };
naoBtn.Click += (sender, e) => { Finish(); };
If I click on the simBtn, the Activity closes, but is not removed from the activity stack, but, if I put the Finish(); inside the OnCreate(), like that:
base.OnCreate(bundle);
SetContentView(Resource.Layout.Chamada);
var simBtn = FindViewById<Button>(Resource.Id.simBtn);
var naoBtn = FindViewById<Button>(Resource.Id.naoBtn);
simBtn.Click += (sender, e) => { Finish(); };
naoBtn.Click += (sender, e) => { Finish(); };
Finish();
the Activity is closed and removed from the stack.
I'm using the NoHistory = true on my Activity declaration.
Any idea of what I'm missing?
Edit:
I've misunderstood the question. Now in your comment in the original question i think i do now.
The Activity is visible in activity stack on the device itself. I think it is added after OnResume because then all the views are inflated etc making it for Android possible to show it on the stack. If you use Finish(); in OnCreate the views are not visible yet thus not showing up on the stack.
Don't worry, if you finish your activity the activity is actually finished even if Android shows it to the user trough the stack. It's just a means for the user to return to your app.
You can confirm this by overriding OnDestroy and placing a breakpoint. If it's hit then you know the activity is closed. If not, then look at my original answer.
Original answer:
I've ran in the same kind of problem recently. I almost completed my app and during the testing phase other people noticed that Activities were not being disposed. As a result after hours of using the app, the app ran out of memory and hung.
The problem you have probably lies not in your OnCreate but in OnResume as you pass your Activity to another object that is keeping the reference to it thus the Activity not being disposed by mono GC. However without the code in OnResume i can't be 100% sure that you have the same problem i had.
The reason why your example is acting like you described is because when you call Finish(); within OnCreate, OnResume will never be called in the Android lifecycle(Just tested it). So the Activity leak has never occurred. If you use Finish(); within anonymous method then OnResume has already been ran and the code within has already created an Activity leak.
If you like more help with your code please post your OnResume code.
Some tips:
Try avoiding using this and thus passing Activity to other objects. If some object requires a Context, use ApplicationContext instead of this.
If really really need to pass the Activity to other object, create a WeakReference within the object:
public class SomeClass
{
private WeakReference _weakactivity;
private Activity _activity
{
get { return _weakactivity.Target as Activity; }
set { _weakactivity = new WeakReference(value); }
}
public SomeClass(Activity activity)
{
_activity = activity;
}
}
The example will create a weak reference telling the GC it is allowed to dispose it when not used(My understanding of how it works, can be wrong.)
Also another tip is to use Action instead of EventHandlers. As you can use action = null; To discard all events. If you still want to use EventHandlers make sure you unsubscribe before OnDestroy is called.
For more info on this watch https://www.youtube.com/watch?v=88ZLgLrwdts
Managed to do it by creating a simple Activity that just finishes itself after the base.OnCreate(savedInstanceState), and then starting it from the actual Activity I want to close and then Finishing it.
Here is the Activity:
[Activity]
public class clsExitActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Finish();
}
public static void ExitApp(Context ctx)
{
var i = new Intent(ctx, typeof(clsExitActivity));
i.AddFlags(ActivityFlags.NewTask | ActivityFlags.ClearTask | ActivityFlags.ExcludeFromRecents | ActivityFlags.NoAnimation);
ctx.StartActivity(i);
}
}
And then the usage (from the activity I want to close):
base.Finish();
clsExitActivity.ExitApp(ApplicationContext);
I found the code for the clsExitActivity in another question, but I can't find it again to paste it's URL here.
I am working with NFC using Xamarin Android.
My scenario is to read nfc tag. I have implemented the following, which works using a button. But I would like it so the user doesn't have to press Scan button to scan nfc tag.
OnCreate
scanButton.Click += (object sender, EventArfs e) =>{
var view = (View)sender;
if(view == Resource.Id.scan){
var mesgEl = FindViewById<TextView>(Resource.Id.msg);
msgEl.Text = "Ready to Scan. Touch and hold the tag against the phone.";
InitNfcScanner();
}
}
InitNfcScanner
private void InitialiseNfcScanner(){
// Create an intent filter for when an NFC tag is discovered. When
// the NFC tag is discovered.
var tagDetected = new IntentFilter(NfcAdapter.ActionTagDiscovered);
var filters = new[] { tagDetected };
// When an NFC tag is detected, Android will use the PendingIntent to come back to this activity.
// The OnNewIntent method will invoked by Android.
var intent = new Intent(this, GetType()).AddFlags(ActivityFlags.SingleTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, 0);
if (_nfcAdapter == null) {
var alert = new AlertDialog.Builder (this).Create ();
alert.SetMessage ("NFC is not supported on this device.");
alert.SetTitle ("NFC Unavailable");
alert.SetButton ("OK", delegate {
// display message here
});
alert.Show ();
} else {
_nfcAdapter.EnableForegroundDispatch (this, pendingIntent, filters, null);
}
}
OnNewIntent
protected override void OnNewIntent(Intent intent)
{
// onResume gets called after this to handle the intent
Intent = intent;
}
OnResume()
protected override void OnResume ()
{
base.OnResume ();
InitialiseNfcScanner();
if (NfcAdapter.ActionTagDiscovered == Intent.Action) {
// do stuff
}
}
But if i remove the button delegate from OnCreate, and call InitNfcScanner(), I get the error Unable to start activity: java.lang.illegalStateException: Foreground dispatch can only be enabled when your activity is resumed.
I want the user to be able to just scan the asset, once the activity is loaded. What would be a good solution to achieve this?
Can you please add the button delegate in OnCreate and Just call button.PerformClick() in OnResume.
I have now resolved this issue.
The objective was to be able to read nfc tag without pressing Button.
So i removed the button from the view, and I removed the ScanButton delegate from OnCreate.
As I was calling InitialiseNfcScanner inside the OnResume(), this is all i needed, because _nfcAdapter.EnableForegroundDispatch (this, pendingIntent, filters, null);
would create a pendingIntent and looking at the Android Guidelines for this, the ForgroundDispatch can only been called from the OnResume().
See http://developer.android.com/reference/android/nfc/NfcAdapter.html
enableForegroundDispatch