How to update ListView without freezing the program - java

So I have a list of strings (ISBNs), and I need to fill a listview with the objects (Book objects) associated with these strings. The problem is that the function I have to get the Book object using the string takes time, and so to get, say 30 books, the wait approaches 4 or 5 seconds.
One approach I've thought of is to get the Book objects one at a time, and to add them to the list as I get them. But this process will freeze the UI until it's done adding them all. If I try to put this process in a new thread, it won't let me add to the any UI objects (since it's from another thread). If I try to put it in an AsyncTask, I can't access the ListView since it's in the MainActivity class.
There must be a way to dynamically update a UI element, I'm sure I've seen it done. Any suggestions?
EDIT:
This is the code I'm using to actually add items to the list:
//List view and adapter setup
listView = (ListView) findViewById(R.id.listViewCheckout);
bookAdapter = new SearchBookAdapter(getApplicationContext(), R.layout.search_row_layout);
listView.setAdapter(bookAdapter);
for(int i = 0; i < searches.size(); i++) {
//Get the book
Book book = BackendFunctions.getBookFromISBN(fbSnapshot, searches.get(i));
//Assign data to the adapter variables
Bitmap cover = book.getCover();
String title = book.getTitle();
String author = book.getAuthor();
//Add data to the adapter and set the list
SearchBookDataProvider dataProvider = new SearchBookDataProvider(cover, title, author);
bookAdapter.add(dataProvider);
bookAdapter.notifyDataSetChanged();
}

Can you make some changes to your code like this it simple it think it will work
//List view and adapter setup
listView = (ListView) findViewById(R.id.listViewCheckout);
bookAdapter = new SearchBookAdapter(getApplicationContext(), R.layout.search_row_layout);
SearchBookDataProvider dataProvider;
listView.setAdapter(bookAdapter);
new AsyncTask() {
#Override
protected Object doInBackground(Object[] objects) {
for(int i = 0; i < searches.size(); i++) {
//Get the book
Book book = BackendFunctions.getBookFromISBN(fbSnapshot, searches.get(i));
//Assign data to the adapter variables
Bitmap cover = book.getCover();
String title = book.getTitle();
String author = book.getAuthor();
//Add data to the adapter and set the list
dataProvider = new SearchBookDataProvider(cover, title, author);
bookAdapter.add(dataProvider);
}
}
#Override
protected void onPostExecute(Object o) {
if (bookAdapter!= null) {
bookAdapter.notifyDataSetChanged();
}
super.onPostExecute(o);
}
}.execute();

you can use TimerTask to update the listview or runUiThread() or doInBackground(). But remember should use notifysetChanges() when you update the list.

Step 1: Declare a Executer service
private ExecutorService mExecuterService = null;
Step 2:Declare a class for your list iteration and view update
class ListViewUpdater implements Runnable{
public ListViewUpdater(/* if you need you can pass list params here */){
}
#Override
public void run() {
for(int i = 0; i < searches.size(); i++) {
//Get the book
Book book = BackendFunctions.getBookFromISBN(fbSnapshot, searches.get(i));
//Assign data to the adapter variables
Bitmap cover = book.getCover();
String title = book.getTitle();
String author = book.getAuthor();
}
//below code is important for Updating UI ,you should run UI Updates in UI thread
runOnUiThread(new Runnable() {
#Override
public void run() {
bookAdapter.notifyDataSetChanged();
}
});
}
}
Step 3: Initilize and call below methods
//Add data to the adapter and set the list
SearchBookDataProvider dataProvider = new SearchBookDataProvider(cover, title, author);
bookAdapter.add(dataProvider);
mExecuterService = Executors.newSingleThreadExecutor()
mExecuterService.execute(new ListViewUpdater());
It may solve your problems.

I think if you are open to use a open source project ,then my suggestion will be use RX-JAVA.Which is based in reactive and push based model.
link for rx-java.
rx-java example.

You can get the list of the books in a Thread and send a Broadcast with the data received.
Register a broadcast receiver in your MainActivity class and update the Adapter in the receiver. That should not freeze the UI.
EDIT -
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Book book = (Book)intent.getSerializableExtra("Book");
SearchBookDataProvider dataProvider = new SearchBookDataProvider(cover, title, author);
bookAdapter.add(dataProvider);
bookAdapter.notifyDataSetChanged();
}
};
Thread thread = new Thread(){
#Override
public void run()
{
for(int i = 0; i < searches.size(); i++) {
//Get the book
Book book = BackendFunctions.getBookFromISBN(fbSnapshot, searches.get(i));
Intent intent = new Intent();
intent.setAction("Book Received");
intent.putExtra("Book",book);
sendBroadcast(intent);
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
listView.setAdapter(bookAdapter);
registerReceiver(broadcastReceiver,new IntentFilter("Book Received"));
thread.start();
}

Related

Static ArrayList from a service is empty when accessed from my MainActivity

I am making a basic app that just reads RSS files from google and displays the headlines in a listview. The problem I am having is that the static ArrayList I am using in an IntentService is empty when I access it after I start the intent for the service. There could be something very basic I am missing here but tit used to work before I added more RSS links to the service. I tried commenting them out to see if there was some sort of overloading somewhere but nothing changed, which I guess means that I changed something else without realizing or remembering it.
Here is my relavent code, the ArrayList I am trying to access is the newsList variable in RSSsearcher. In the past I have logged the string values of the arraylist and confirmed that it was being populated in the RSSsearcher class, but empty in the MainActivity class.
Relevant code:
RSSsearcher:
public class RSSsearcher extends IntentService {
public static ArrayList<NewsCard> newsList = new ArrayList<>();
private static String TAG = "RSS";
public RSSsearcher() {
super("RSSsearcher");
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
parseNewsLists();
Log.i(TAG,"newsList in onHandleIntent" + newsList);
}
public static ArrayList<NewsCard> getNewsCards() {
return newsList;
}
//helper method to create all the RSSfeed objects
private void parseNewsLists() {
Log.i(TAG, "the service has been started");
//Creating the RSS feed objects
RSSfeed topStories = new RSSfeed("https://news.google.com/news?cf=all&hl=en&pz=1&ned=us&output=rss");
RSSfeed worldNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/WORLD?ned=us&hl=en");
RSSfeed usNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/NATION?ned=us&hl=en");
RSSfeed buisnessNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/BUSINESS?ned=us&hl=en");
RSSfeed technologyNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/TECHNOLOGY?ned=us&hl=en");
RSSfeed entertainmentNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/ENTERTAINMENT?ned=us&hl=en");
RSSfeed sportsNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/SPORTS?ned=us&hl=en");
RSSfeed scienceNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/SCIENCE?ned=us&hl=en");
RSSfeed healthNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/HEALTH?ned=us&hl=en");
try {
//getting RSS feeds
topStories.FileReader();
worldNews.FileReader();
usNews.FileReader();
buisnessNews.FileReader();
technologyNews.FileReader();
entertainmentNews.FileReader();
sportsNews.FileReader();
scienceNews.FileReader();
healthNews.FileReader();
} catch (Exception e) {
Log.i(TAG, Log.getStackTraceString(e));
}
//adding stories to main
newsList.addAll(topStories.getNews());
newsList.addAll(worldNews.getNews());
newsList.addAll(usNews.getNews());
newsList.addAll(buisnessNews.getNews());
newsList.addAll(technologyNews.getNews());
newsList.addAll(entertainmentNews.getNews());
newsList.addAll(sportsNews.getNews());
newsList.addAll(scienceNews.getNews());
newsList.addAll(healthNews.getNews());
}
}
MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//TODO remove and have actual tags show up
TagCard onecard = new TagCard("TestCard");
TagCard twocard = new TagCard("TestCard2");
dummyTags.add(onecard);
dummyTags.add(twocard);
mainListView = (ListView) findViewById(R.id.main_content_list);
drawerLayout = (DrawerLayout) findViewById(R.id.main_layout);
tagDrawerList = (ListView) findViewById(R.id.tag_drawer);
//setting an intent for the RSSsearcher to fetch the news
//TODO make this happen every 15 minutes or so
Intent intent = new Intent(this, RSSsearcher.class);
startService(intent);
NewsCard card = new NewsCard("Testing", "linkeroni");
//adding all the NewsCard objects to this classes newsList
newsList.addAll(RSSsearcher.getNewsCards());
MainAdapter adapter = new MainAdapter(this, newsList);
mainListView.setAdapter(adapter);
Log.i(TAG, "This is the array from main activity" + newsList.toString());
actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.open_drawer, R.string.close_drawer){
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
getActionBar().setTitle("Closed");
}
public void onDrawerOpened(View view){
super.onDrawerOpened(view);
getActionBar().setTitle("Open");
}
};
//TODO removed dummytags and add actual tag implementation
tagDrawerList.setAdapter(new TagAdapter(this,dummyTags));
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
}
Thank you in advance!
I think that when you call
newsList.addAll(RSSsearcher.getNewsCards());
The intent is still in execution

How to pass object through activities by reference?

this is my first post here so be gentle :p
Here is the thing, I'm facing a really though issue and after several research i did not manage to figure out a clean solution. Let me explain:
I'm actually developing an android app for restaurant management.
In activity A, i'm able to create some articles with different parameters (picture, name, price ..).
I can also create a menu in which i indicate which articles are included. To do so i run Activity B that contains a dynamic list of the available articles (the ones i created) to be chosen. After picking up some of them the customised chosen objects are sent to Activity A through Parcel. And the chosen article list is updated in the menu.
But here is the thing, as far as i know, using Parcels create another instance of the object. As a result, if i modify or delete an article, the article list included in the menu does not change, and obviously i would like the list in the menu to be automatically updated.
Is there a way to simply pass customised objects through activities by reference?
What could be a clean solution to make the article list in the menu dynamic?
Here is some code:
In Activity A, in the menu interface i click + button to add an article, which run Activity B (the extras is the list of articles already included in the menu before, so in the beginning it's empty).
//Add article
FloatingActionButton addArticleButton = (FloatingActionButton)parentActivity.findViewById(R.id.addArticleButton);
addArticleButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showMenuDetails(menuListView,menuAdapter,currentMenu);
parentActivity.startActivityForResult(new Intent(parentActivity.getApplicationContext(),ChooseArticleActivity.class).putParcelableArrayListExtra("menuArticleList",currentMenu.getArticles()),PICK_ARTICLES);
}
});
In activity B: I select Articles in a list of available Articles (the ones i created). After picking up i press OK button to put the list of chosen articles in result Intent as Parcelable Extras
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.choose_article_layout);
initializeLists();
this.resultIntent = new Intent();
}
private void initializeLists(){
final ListView articleToChoose = (ListView)findViewById(R.id.articleToChoose);
final ListView articleChosen = (ListView)findViewById(R.id.articleChosen);
final ArrayList<Article> articleToChooseList = (ArrayList<Article>)MainActivity.model.getArticleList().getArticleList().clone();
final ArrayList<Parcelable> articleChosenListParcelable = (ArrayList<Parcelable>)this.getIntent().getParcelableArrayListExtra("menuArticleList");
final ArticleAdapter articleToChooseAdapter = new ArticleAdapter(getApplicationContext(), articleToChooseList);
articleToChoose.setAdapter(articleToChooseAdapter);
ArrayList<Article> articleChosenListTemp = new ArrayList<>();
ArrayList<Article> articleToRemove = new ArrayList<>();
for(Parcelable a:articleChosenListParcelable){
articleChosenListTemp.add((Article)a);
for(Article article:articleToChooseList){
if(article.getName().equals(((Article) a).getName())){
articleToRemove.add(article);
}
}
}
articleToChooseList.removeAll(articleToRemove);
articleToChooseAdapter.notifyDataSetChanged();
final ArrayList<Article> articleChosenList = articleChosenListTemp;
final ArticleAdapter articleChosenAdapter = new ArticleAdapter(getApplicationContext(),articleChosenList);
articleChosen.setAdapter(articleChosenAdapter);
articleChosen.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Article articleClicked = articleChosenAdapter.getItem(position);
articleChosenList.remove(articleClicked);
articleToChooseList.add(articleClicked);
articleChosenAdapter.notifyDataSetChanged();
articleToChooseAdapter.notifyDataSetChanged();
}
});
articleToChoose.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Article articleClicked = articleToChooseAdapter.getItem(position);
if(!articleChosenList.contains(articleClicked)){
articleChosenList.add(articleClicked);
articleToChooseList.remove(articleClicked);
articleToChooseAdapter.notifyDataSetChanged();
articleChosenAdapter.notifyDataSetChanged();
}
}
});
Button okButton = (Button)findViewById(R.id.okButton);
okButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
chosenArticleListAttr = articleChosenList;
resultIntent.putParcelableArrayListExtra("articleList",chosenArticleListAttr);
setResult(RESULT_OK,resultIntent);
finish();
}
});
Button cancelButton = (Button)findViewById(R.id.cancelButton);
cancelButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
In activity A, in onActivityResult i catch the result and update the list, but the added Articles here are not the same instance as the article list in the model
if(requestCode==PICK_ARTICLES && resultCode==RESULT_OK){
ArticleAdapter articleAdapter = (ArticleAdapter) gestionMenusLayout.getMenuArticleListView().getAdapter();
ArrayList<Parcelable> chosenArticleList = (ArrayList<Parcelable>)data.getParcelableArrayListExtra("articleList");
gestionMenusLayout.getCurrentMenu().getArticles().clear();
for(Parcelable a:chosenArticleList){
gestionMenusLayout.getCurrentMenu().addArticle((Article)a);
}
articleAdapter.notifyDataSetChanged();
}
For debugging purpose only, I suggest that you use a public static List<Article> articleList and call it directly from whether activity A or B
A better but take-alittle-more-effort solution is that you store the list in a database, and every updates, queries, ... come through it.You can use the server's database (where people usually get articles from), or a offline database like Realm here
I figured it out with a quite easy and simple solution finally.
I keep passing my Article objects through intents by parcels.
But as it creates a new instance, instead of adding this instance i add the original one (the one from the model) after an equality key check (the name of the article). By doing so i keep the reference on my Article.
Thank you for helping!
Edit:
Here is the code:
if(requestCode==PICK_ARTICLES && resultCode==RESULT_OK){
ArticleAdapter articleAdapter = (ArticleAdapter) gestionMenusLayout.getMenuArticleListView().getAdapter();
ArrayList<Parcelable> chosenArticleList = (ArrayList<Parcelable>)data.getParcelableArrayListExtra("articleList");
gestionMenusLayout.getCurrentMenu().getArticles().clear();
ArrayList<Article> modelArticles = MainActivity.model.getArticleList().getArticleList();
for(Parcelable a:chosenArticleList){
for(Article modelArticle:modelArticles){
if(((Article)a).getName().equals(modelArticle.getName())){
gestionMenusLayout.getCurrentMenu().addArticle(modelArticle);
}
}
}
articleAdapter.notifyDataSetChanged();
}

Assigned a ArrayList in AsyncTask, but the change discard afterwords

I'm writing a simple program to request a JOSN request of a list of earthquakes to display for users. I use Asynctask to put the request in the background thread and use an ArrayList Adaptor to display the relevant information. I declare an empty ArrayList and then extract the JOSN request and put them in a temporary list and then assign the temporary list to the empty ArrayList.
I use a debugger tool to see that in the updateEarthquakeList method. I set the break point in the updateEarthquakeList method. this.earthquak and earthquakes both have 10 elements. Pics are as follow:
But when I set the break point after task.execute(USGS_REQUEST_URL) in the onCreate method, I got this:
As the pics shown after execute the AsyncTask the ArrayList is empty. But inside the AsyncTask The array was actually updated. (To do a little experiment I create an int haha as 0 and change it to 1 in the Asynctask, but it changed back to 0 afterwards)
How is this happen and how do I supposted to make it right?
public class EarthquakeActivity extends AppCompatActivity {
public static final String LOG_TAG = EarthquakeActivity.class.getName();
ArrayList<Earthquake> earthquak = new ArrayList<Earthquake>();
int haha = 0;
private static final String USGS_REQUEST_URL = "http://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&eventtype=earthquake&orderby=time&minmag=6&limit=10";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.earthquake_activity);
EarthquakeAsyncTask task = new EarthquakeAsyncTask();
task.execute(USGS_REQUEST_URL);
// Create a fake list of earthquake locations.
// Find a reference to the {#link ListView} in the layout
ListView earthquakeListView = (ListView) findViewById(R.id.list);
// Create a new {#link ArrayAdapter} of earthquakes
EarthquakeAdapter adapter = new EarthquakeAdapter(this, earthquak);
// Set the adapter on the {#link ListView}
// so the list can be populated in the user interface
earthquakeListView.setAdapter(adapter);
//OPEN a web page of a specific when textview is clicked.
earthquakeListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(Intent.ACTION_VIEW, earthquak.get(position).getUrl());
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
});
}
private void updateEarthquakeList(ArrayList<Earthquake> earthquake) {
this.earthquak = earthquake;
haha = 1;
}
private class EarthquakeAsyncTask extends AsyncTask<String, Void, ArrayList<Earthquake>> {
#Override
protected ArrayList<Earthquake> doInBackground(String... urls) {
if (urls.length < 1 || urls[0] == null) {
return null;
}
ArrayList<Earthquake> earthquakes = QueryUtils.fetchEarthquakeData(urls[0]);
return earthquakes;
}
#Override
protected void onPostExecute(ArrayList<Earthquake> earthquakes) {
updateEarthquakeList(earthquakes);
}
}

Retrieving ArrayList<Object> from FireBase inner class

I've been looking at the firebase documentation and tried to make firebase work with an android app I'm building.
All the code examples I could find show how to get a value, then immediately print it within the firebase ValueEventListener inner class. I would like to get the values and store them in an array for later use.
What I try to do is when a user clicks the highscore button the client gets the current scoreboard from firebase, and sends that list to the highscoreboard class.
UPDATE: I have been able to retrieve the data now but there is a behavior that confuses me greatly. If the user clicks the highscorebutton the scores list gets populated and highscore class is correctly showing 10 elements. If I exit the scoreboard and enter it again it will now show all scores twice (understandably so, as I am just adding to the same list). But any calls to scores.clear() or scores = new ArrayList(); between the two clicks results in scores being empty even after the second click (I assumed that populating scores, then emptying it and repopulating it would leave 10 items in there) This behavior was the reason I thought my scores array never got populate when first posting here as I had a scores.clear() call inside the load function since I didn't want to duplicate values. If anyone is able to explain why this happens that would be fantastic.
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
ArrayList<Score> scores;
Firebase myFirebase;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Firebase.setAndroidContext(this);
myFirebase = new Firebase(FirebaseURL);
scores = new ArrayList<Score>();
loadScoresFromFireBase();
}
public void loadScoresFromFireBase() {
String entry = "";
for (int i = 0; i < 10; i++) {
entry = "Name_" + i;
myFirebase.child("users").child(entry).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
//getValue correctly returns a Score object
scores.add(snapshot.getValue(Score.class));
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//....
if ( id == 2) {
Intent intent = new Intent(getApplicationContext(), ScoreBoard.class);
Bundle bundle = new Bundle();
//calling scores.clear() here leaves the scores array empty even though loadscores is called afterwards.
loadScoresFromFireBase();
Collections.sort(scores);
bundle.putSerializable("players", scores);
intent.putExtra("players", bundle);
startActivityForResult(intent, 0);
}
}
}
You're falling for the classic asynchronous trap:
loadScoresFromFireBase();
Collections.sort(scores);
When you call loadScoresFromFireBase() (it's spelled Firebase btw), the program starts synchronizing the scores from the server. Loading this data takes some time. Instead of making your program wait (which would be a bad user experience), Firebase makes you pass in a ValueEventListener that it then calls when the data is available. But you're calling Collections.sort(scores) straight away, before the (first) data has been loaded.
You can most easily see this by adding a few log statements:
public void loadScoresFromFireBase() {
String entry = "";
for (int i = 0; i < 10; i++) {
entry = "Name_" + i;
myFirebase.child("users").child(entry).addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot snapshot) {
System.out.println("Adding score to array");
scores.add(snapshot.getValue(Score.class));
}
public void onCancelled(FirebaseError firebaseError) { }
});
}
}
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//....
if (id == 2) {
Intent intent = new Intent(getApplicationContext(), ScoreBoard.class);
Bundle bundle = new Bundle();
System.out.println("Before calling loadScores");
loadScoresFromFireBase();
System.out.println("After calling loadScores");
Collections.sort(scores);
System.out.println("After sorting scores");
The output of these log statements will be:
Before calling loadScores
After calling loadScores
After sorting scores
Adding score to array
That is probably not what you expected. But it is completely normal when you're dealing with asynchronous/event driven code, like is common in modern internet programming.
The most direct solution is to move the code that needs the scores into the function that loads them:
public void loadScoresFromFireBase() {
String entry = "";
for (int i = 0; i < 10; i++) {
entry = "Name_" + i;
myFirebase.child("users").child(entry).addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot snapshot) {
scores.add(snapshot.getValue(Score.class));
Collections.sort(scores);
Intent intent = new Intent(getApplicationContext(), ScoreBoard.class);
Bundle bundle = new Bundle();
bundle.putSerializable("players", scores);
intent.putExtra("players", bundle);
startActivityForResult(intent, 0);
}
public void onCancelled(FirebaseError firebaseError) { }
});
}
}
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//....
if (id == 2) {
loadScoresFromFireBase();
Also see this answer I wrote a while ago: Setting Singleton property value in Firebase Listener
As well as these great answers on the same problem:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
How do I return the response from an asynchronous call?
Although these are about JavaScript, they deal with the exact same problem.
As you have not initialized scores you will be getting a NullPointerException when calling add
If you do
ArrayList<Score> scores = new ArrayList ();
it should work

Keeping list entries when I move activity

I have a ListView.
I populate this list from 2 editTexts
When I move activity and go back to it the entries are gone again.
I kind of understand why this is but dont know how to correct it.
ListView lv2 = (ListView) findViewById(R.id.listView2);
final SimpleAdapter simpleAdpt = new SimpleAdapter(this, planetsList, android.R.layout.simple_list_item_1, new String[]{"planet"}, new int[]{android.R.id.text1});
planetsList.add(createPlanet("planet", "testme"));
lv2.setAdapter(simpleAdpt);
button21.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
iinitList();
simpleAdpt.notifyDataSetChanged();
editText5.setText("");
editText6.setText("");
}
});
}
private void iinitList() {
String st,str;
Double db;
if (editText5.getText().toString()!= "" && editText6.getText().toString()!="") {
st = editText5.getText().toString();
str = editText6.getText().toString();
db = Double.parseDouble(str);
planetsList.add(createPlanet("planet", ""+st+
": \n" +db+""));
}
}
HashMap<String, String> createPlanet(String key, String name) {
HashMap<String, String> planet = new HashMap<String, String>();
planet.put(key, name);
return planet;
}
As you can see I have added a value to the list manually called test also, when I move activity this stays in the list, I would love if the editText entries were to stay in there also when I move activities.
Activities can be destroyed when you navigate to a new one or rotate. This will clear anything that is only referenced by the activity, like your EditTexts. However, Android provides a nice utility for saving things you want to remain in a method called, which you can override in your activity:
#Override
protected void onSaveInstanceState(Bundle state) {
// Put your values in the state bundle here
}
#Override
protected void onCreate(Bundle savedState) {
// Load your UI elements as usual
if (savedState != null) {
// Load your state from the bundle
}
}
That same bundle will be given back to you in onCreate, where you create your UI to begin with so you can reload the state from it.
This is a really good description of how activities work:
http://developer.android.com/reference/android/app/Activity.html

Categories

Resources