Xamarin.Android how to auto update RecyclerView - c#

Following this article I created a simple application that displays a list. The list I get from a web service (.asmx web service).
I want to auto update RecyclerView every 5 seconds and I have no idea how to do it.
In WinForms I would have used the Timer component, but I don't know how this works in Xamarin.
MainActivity.cs
[Activity(Label = "CibMonitor", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : AppCompatActivity
{
RecyclerView recyclerView;
RecyclerView.LayoutManager layoutManager;
ConnectionItemsAdapter adapter;
ConnectionItem[] connectionItems;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
var ci = new ConnectionItem();
//Get list from web service
connectionItems = ci.GetList().ToArray();
//Setup RecyclerView
adapter = new ConnectionItemsAdapter(this, connectionItems);
recyclerView = FindViewById<RecyclerView>(Resource.Id.recyclerView);
recyclerView.SetAdapter(adapter);
ChangedData();
}
}
Update
I created new method in activity class as York Shen suggested
void ChangedData()
{
Task.Delay(5000).ContinueWith(t =>
{
var newData = ConnectionItem.GetList();
adapter.RefreshItems(newData);
ChangedData();
}, TaskScheduler.FromCurrentSynchronizationContext());
}
This is my update method in adapter class:
public void RefreshItems(List<ConnectionItem> newItems)
{
items.Clear();
items = newItems;
NotifyDataSetChanged();
}
my app stops working, no exception only this message:

You can create a Task which can help you update recyclerView every 5 seconds:
void ChangedData()
{
Task.Delay(5000).ContinueWith(t =>
{
adapter.NotifyDataSetChanged();
ChangedData();//This is for repeate every 5s.
}, TaskScheduler.FromCurrentSynchronizationContext());
}
EDIT:
Sorry for late reply, calling the ChangedData() in Task.Delay() can resolve the repeate problem. You can invoke the ChangedData() in OnCreate() method. Hope this can help you. : )

Related

PushAsync in constructor gives the second page the ToolbarItemes of the first page

if I do a PushAsync in the constructor on my MainPage, the ToolbarItems from the MainPage are also displayed on the second page. I already tried to switch the toolbar items in the OnAppearing and OnDisappearing triggers on and off. Unfortunately, this is useless. I test on android and I use Visual Studio.
protected override void OnDisappearing()
{
this.ToolbarItems.Clear();
}
protected override void OnAppearing()
{
var edit = new ToolbarItem
{
Icon = "edit.png",
Command = new Command(this.startEditMode),
};
this.ToolbarItems.Add(edit);
var addpage = new ToolbarItem
{
Icon = "connect.png",
Command = new Command(this.startWebsiteConnector),
};
this.ToolbarItems.Add(addpage);
}

populate ListView from Another class Xamarin c#

I'm trying to populate a ListView from Another class which run on another thread but I failed to do that.
Here is the main Activity :
public ListView myList;
List < string>contacts = new List< string>();
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Control);
myList = FindViewById<ListView>(Resource.Id.contactsList);
myList.ItemLongClick += MyList_ItemLongClick;
}
public void insertContact(string ContactInfo)
{
myList=FindViewById<ListView>(Resource.Id.contactsList);
contacts.Add(ContactInfo);
ArrayAdapter<string> myArray = new ArrayAdapter<string>(Application.Context, Android.Resource.Layout.SimpleListItem1, contacts);
list.Adapter = null;
list.Adapter = myArray;
myList.DeferNotifyDataSetChanged();
}
public void startAsync(){
Contacts con = new Contacts();
Thread thread = new Thread(()=> con.Start());
thread.Start();
}
I'm firing a method from another class to grap contacts.
There it just get some info and should send it to main Activity
The other class doing like
MainAct main = new MainAct();
main.insertContact("new Contact");
but It did nothing.
I tried to make a method to get the listView from the main activity (like mentioned in some thread) and pass it as second paramter to add contact like :
public ListView getListView()
{
ListView myList = FindViewById<ListView>(Resource.Id.contactsList);
return myList;
}
and after than calling this line which has the ListView :
main.insertContact("new Contact", main.getListView());
but I got an exception :
Java.Lang.NullPointerException: < Timeout exceeded getting exception details>
I tried from the other class to run the line like :
main.RunOnUIThread(()=> main.insertContact("new Contact", main.getListView()));
but got the same exception !
What did I missed ?
NOTE: If I put both classes in one class ( I mean all the code in one class ) It works without a problem with RunOnUIThread(()=> ); . but When I move the method to another class, I got the exception.
EDIT 1:
When I catch the exception I got nullpointer
Exception of type 'Java.Lang.NullPointerException' was thrown.
1) If Contacts is your another class, I suggest you rename it as MyContacts, because there is a Contacts class,it will confused us.
2) You don't need to new MainAct, just pass the context to your another class.
I have tried to reproduce your question, and I add a comment for these codes:
Here is your MyContacts class:
public class MyContacts
{
MainActivity mContext;
public MyContacts(MainActivity context) {
this.mContext = context;
}
public void Start() {
mContext.insertContact("new Contact");
mContext.insertContact("new Contact1");
mContext.insertContact("new Contact2");
}
}
You MainActivity:
public class MainActivity : Activity
{
public ListView myList;
List<string> contacts = new List<string>();
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
myList = FindViewById<ListView>(Resource.Id.contactsList);
//we usually init the data in OnCreate method.
startAsync();
}
public void insertContact(string ContactInfo)
{
//this is redundant, because you have Instantiated the myList in the OnCreate method.
//myList = FindViewById<ListView>(Resource.Id.contactsList);
contacts.Add(ContactInfo);
//You can use this instead of Application.Context.
ArrayAdapter<string> myArray = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, contacts);
myList.Adapter = myArray;
//from your question, I can't find any information about the list property.
//list.Adapter = null;
//list.Adapter = myArray;
//myList.DeferNotifyDataSetChanged();
}
//From your question, I can't find where have you call this method, I will call it in the OnCreate method
public void startAsync()
{
MyContacts con = new MyContacts(this);
Thread thread = new Thread(() => con.Start());
thread.Start();
}
}

How to navigate from one screen to another automatically in Xamarin cross platform app?

I am not able to find out how to navigate from one screen to another automatically without having to click on any button or perform any action. I want to start another screen just after my splash screen shows up. As i am new on this tool or technology. Please help. Thank you in advance.
My code is:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
protected async override void OnAppearing()
{
base.OnAppearing();
await Task.Delay(5000); // Simulate a bit of startup work.
await this.Navigation.PushAsync(new HomePage());
}
}
Working and tested code:
protected override void OnAppearing()
{
base.OnAppearing();
GoToMaster();
}
private async void GoToMaster()
{
await Task.Delay(5000);
await this.Navigation.PushAsync(new SignUpPage());
}
I made my splash activity under xamarin.droid file and i want it to display the xaml file that i made in portable portion before launching the home page activity.
You can't skip the MainActivity as it is the container of your pages in Portable lib, So if you want to redirect to your xaml page after the splash screen, you can make SplashScreenActivity navigate to your MainActivity and make your xaml file the MainPage of App.cs:
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new YourPage();
}
....
}
And in your SplashScreenActivity you need to navigate to the MainActivity:
[Activity(Theme = "#style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
public class SplashActivity : AppCompatActivity
{
static readonly string TAG = "X:" + typeof(SplashActivity).Name;
public override void OnCreate(Bundle savedInstanceState, PersistableBundle persistentState)
{
base.OnCreate(savedInstanceState, persistentState);
}
protected override void OnResume()
{
base.OnResume();
Task startupWork = new Task(() => { SimulateStartup(); });
startupWork.Start();
}
async void SimulateStartup()
{
await Task.Delay(8000);
StartActivity(new Intent(Application.Context, typeof(MainActivity)));
}
}
here is the complete demo:SplashScreenDemo.

Update Recycler view by button in toolbar

I writing app for Android using Xamarin.
I have this code in Activity for OnCreate method.
protected override int LayoutResource
{
get { return Resource.Layout.Main; }
}
private RecyclerView recyclerView;
private ProgressBar activityIndicator;
private RecyclerView.LayoutManager layoutManager;
protected override async void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
recyclerView = FindViewById<RecyclerView>(Resource.Id.recyclerView);
activityIndicator = FindViewById<ProgressBar>(Resource.Id.activityIndicator);
activityIndicator.Visibility = Android.Views.ViewStates.Visible;
layoutManager = new LinearLayoutManager(this, LinearLayoutManager.Vertical, false);
recyclerView.SetLayoutManager(layoutManager);
var repository = new TestAppRepository();
var films = await repository.GetAllFilms();
var formsAdapter = new FormAdapter(films.results);
recyclerView.SetAdapter(formsAdapter);
activityIndicator.Visibility = Android.Views.ViewStates.Gone;
SupportActionBar.SetDisplayHomeAsUpEnabled(false);
SupportActionBar.SetHomeButtonEnabled(false);
I have Button in toolbar and need to refresh Recycler when I tap this button.
Here is calling of it for display
public override bool OnCreateOptionsMenu(IMenu menu)
{
MenuInflater.Inflate(Resource.Menu.home, menu);
return base.OnCreateOptionsMenu(menu);
}
How I need to write code to refresh Recycler?
Thank's for help
Use the button's setOnClickListener method and implement the onClick method of the new OnClickListener In the onClick method called the RecyclerView adapter's notifydatasetchanged()

MonoDroid Splash Screen

How can I implement a simple "splash screen" on program startup? I am copying a SQLite DB and it can be a bit of a long process that is not UI "friendly" .
I would prefer not to use "java code".
TIA
I recently solved this problem in the following way.
In the main activity I passed a parameter via the intent to set the number of milliseconds for which the splash screen would remain visible.
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
Intent i=new Intent();
i.SetClass(this, typeof (Splash));
i.PutExtra("Milliseconds", 3000);
StartActivity(i);
}
Then, in the second activity which I named "Splash" I retrieved the value and set a second thread to end the activity when the time had elapsed.
[Activity(Label = "Daraize Tech")]
public class Splash : Activity
{
private int _milliseconds;
private DateTime _dt;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
_milliseconds = Intent.GetIntExtra("Milliseconds", 1000);
SetContentView(Resource.Layout.Splash);
_dt=DateTime.Now.AddMilliseconds(_milliseconds);
}
public override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
new Thread(new ThreadStart(() =>
{
while (DateTime.Now < _dt)
Thread.Sleep(10);
RunOnUiThread( Finish );
}
)).Start();
}
}
Also see http://docs.xamarin.com/android/tutorials/Creating_a_Splash_Screen
Really great tutorial.
It only takes about 10 lines of code :)
In a Styles.xml:
<resources>
<style name="Theme.Splash" parent="android:Theme">
<item name="android:windowBackground">#drawable/splash</item>
<item name="android:windowNoTitle">true</item>
</style>
</resources>
In your activity:
[Activity (MainLauncher = true, Theme = "#style/Theme.Splash", NoHistory = true)]
public class SplashActivity : Activity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Create your async task here...
StartActivity (typeof (Activity1));
}
}
This worked for me:
Starting an new thread from the splash activity. You can wait a few seconds or load some data or something else.
[Activity(MainLauncher = true, NoHistory = true)]
public class Splashscreen : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView (Resource.Layout.splashscreen);
new Thread (new ThreadStart (() =>
{
//Load something here ...
Thread.Sleep(1500);
Intent main = new Intent (this, typeof(MainActivity));
this.StartActivity (main);
this.Finish ();
})).Start ();
}
}
This solution gets you the following:
Immediate display of the splash screen
Removal of splash screen the exact time the "main" activity is launched (main activity replaces the splash activity)
In OnCreate, SetContentView is called to get the splash screen up, and then the worker thread is kicked off, which runs the slow processing data initialization stuff.
This way, the spalsh screen is displayed without delay. The last statement in the worker thread kicks off the "main" app/activity, which will have its DB & data all ready for access. Calling StartActivity() from OnCreate (ie, after initializeDataWorker.Start()), will cause MainActivity to run before/while the DB is being created and/or data is being fetched, which is usually not desireable).
This solution lacks a way to remove the splash screen from the backstack. When I get around to implementing this functionality I'll update it.
namespace Mono.Droid
{
[Activity(
Label = "Splash Activity",
MainLauncher = true,
Theme = "#android:style/Theme.Black.NoTitleBar",
Icon = "#drawable/icon",
NoHistory = false)]
public class SplashActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.SplashLayout);
Thread initializeDataWorker = new Thread(new ThreadStart(InitializeData));
initializeDataWorker.Start();
}
private void InitializeData()
{
// create a DB
// get some data from web-service
// ...
StartActivity(typeof(MainActivity));
}
}
}

Categories