This is my first Android project. I am supposed to parse an rss feed from the internet and put it into a SQLite database for offline access to the feed's posts. I have followed the xml parsing tutorial by Coding Green Robots and I have followed a SQLite database tutorial on the Code Project, but in trying to put those together, I have run into problems.
The app builds on my Droid, but then it stops unexpectedly during this method in MainActivity:
private void displayPosts(ArrayList<Post> posts) {
//Create String Arrays to separate titles and dates
Log.d("CGRParser", "Displaying Post Titles To User");
ArrayList<String> post_headlines = new ArrayList<String>();
ArrayList<String> post_pubDates = new ArrayList<String>();
ArrayList<String> post_dbids = new ArrayList<String>();
ArrayList<String> post_contents = new ArrayList<String>();
//For every post in the ArrayList posts, it puts each attribute of the post into its own ArrayList
// This should be getting stuff from the database and putting it into an ArrayList
for (Post post : posts) {
Log.d("CGRParser", "Post Title: " + post.getHeadline());
post_headlines.add(post.getHeadline());
post_pubDates.add(post.getPubDate());
post_dbids.add(post.getDbid());
post_contents.add(post.getContents());
//it's breaking here
dbh.AddPost(post);
}
this.post_headlines = post_headlines;
this.post_pubDates = post_pubDates;
this.post_dbids = post_dbids;
this.post_contents = post_contents;
//Create a ListAdapter to Display the Titles in the ListView
ListAdapter adapter = new ArrayAdapter<String>(this, R.layout.episode_row, R.id.title, post_headlines);
listview_posts.setAdapter(adapter);
//Set Progress Bar Invisible since we are done with it
progress_bar.setVisibility(ProgressBar.INVISIBLE);
}
I retained the functionality from the original tutorial. All I changed was adding dbh.AddPost(post);. dbh is a DatabaseHelper object declared in MainActivity. Each of those ArrayLists are declared in MainActivity, but they are also declared in the method. When I debug it and it gets to dbh.AddPost(post); ThreadPoolExecutor.class runs and says "Source not found. The JAR file /Users/Zach/Desktop/android-sdj-mac_x86/platforms/android-7/android.jar has no source attachment. You can attach the source by clicking Attach Source below."
My main question is what am I doing wrong here? I don't get any errors from this, and I don't understand what it means by source attachment. I feel that there is a reason the ArrayLists are declared in the method as well as MainActivity, and that I should be doing the same for dbh, but I am not sure why. Regardless, making a databaseHelper in the method wouldn't work in the long run, as the application will need to bring in new posts from the feed, and setting the old database to the new one with only the new posts would not work.
EDIT: Here's the AddPost method in DatabaseHelper:
void AddPost(Post post){
SQLiteDatabase db= this.getWritableDatabase();
ContentValues cv=new ContentValues();
cv.put(colDbid, post.getDbid());
cv.put(colType, post.getType());
cv.put(colSubType, post.getSubType());
cv.put(colHeadline, post.getHeadline());
cv.put(colContents, post.getContents());
cv.put(colUrl, post.getUrl());
cv.put(colImgUrl, post.getImgUrl());
cv.put(colVidUrl, post.getVidUrl());
cv.put(colPubDate, post.getPubDate());
db.insert(postTable, colHeadline, cv);
db.close();
}
Related
I've looked at similar questions but they don't explain how to use a CursorAdapter.
What I'm trying to do is populate a Spinner with a column of Strings read from a selected database.
This is my current code:
//open database depending on selected item
myDatabase = openOrCreateDatabase("Courses"+spSem.getSelectedItem().toString(),MODE_PRIVATE,null);
//read fields to be populated and store them in an arraylist, I need to use arraylist since not every database has the same size
Cursor resultSet = myDatabase.rawQuery("Select * from Subject",null);
resultSet.moveToFirst();
List<String> course = new ArrayList<String>();
for (int i = 1; i < course.size(); i++) {
course.add(resultSet.getString(i));
}
This next part is where I'm stuck, I'm thinking I need to use CursorAdapter() to populate the spinner, but I have no idea how? Previously I had this:
String[] cArr = new String[course.size()];
course.toArray(cArr);
CursorAdapter a = new CursorAdapter(this,cArr,android.R.layout.simple_spinner_item);
a.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spCourse.setAdapter(a);
With this code I get the error "CursorAdapter is abstract and cannot be instantiated", and "cannot resolve method'setDropDownView'".
I am using Parse.com as my backend, and I want to download data from server. I have tags which filter these data. Unfortunately it works wrong. Lets say I have two tags "city1" and "city2", now I only get data for "city1".
public ArrayList<Dataset> getDatasetFromServer(Context context) {
ParseQuery<ParseObject> query = ParseQuery.getQuery("Dataset");
List<String> cities = DatabaseAdapter.getCityNames(context);
//cities list contains "city1" and "city2"
query.whereContainedIn("cities", Arrays.asList(cities.toArray(new String[cities.size()])));
ArrayList<Dataset> dataset = new ArrayList<>();
try {
List<ParseObject> parseDataset = query.find();
dataset = setDatasetList(parseDataset);
} catch (ParseException e) {
e.printStackTrace();
}
return dataset;
}
The problem is with this : Arrays.asList(cities.toArray(new String[cities.size()]).
Don't know why, but this convertion works wrong with Parse.
However, if I change above line to this
String[] array = {"city1", "city2"};
query.whereContainedIn("cities", Arrays.asList(array));
Everything works fine and I get data for city1 and city2.
My question is, what's the difference between these two solutions and how to fix this so the first solution works?
EDIT :
This also doesn't work :
query.whereContainedIn("cities", DatabaseAdapter.getCityNames(context));
getCityNames returns List<String>
Instead of converting your list to an array and then back to a list, just do this:
query.whereContainedIn("cities", cities);
The problem was my fault. Both solutions work good.
The reason it didn't worked was that my method
DatabaseAdapter.getCityNames(context) put a whitespace on the beggining of second element which I didn't saw.
I have run into that timeless issue of wanting to have an auto-incrementing column (in SQLITE) that remains intact after a record is deleted. I have run into a number of posts about this problem, but none of them explain exactly how to code your own column for this purpose. I need the numbers to be consecutive because I want to be able to display a record number for each item in a ListView which will also serve as a running total of how many records are in the db.
So far, I have been trying to use the VACUUM function because it's my understanding that it will reset the numbers once it's complete, and I thought I would run it every time a record is deleted, but nothing seems to happen when the code is run. I'm not getting any errors, but the VACUUM isn't happening as far as I can tell. Here's the code:
String sql = "VACUUM;" ;
db.execSQL(sql,new String [] {sql});
Maybe nothing is happening because the coding is off? So I guess what I am getting at here is am I on the right track with trying to use VACUUM or should I go with manually setting up an auto-incrementing column? Either way, any advice is greatly appreciated!
Here's the fetch and display portion of the code:
populateListViewFromDB();
}
#SuppressWarnings("deprecation")
private void populateListViewFromDB() {
Cursor cursor = db.getAllRecords();
//Allow activity to manage cursor lifetime
startManagingCursor(cursor);
//Setup mapping from cursor to view fields:
String [] fromFieldNames = new String []
{DBAdapter.KEY_ROWID, DBAdapter.KEY_GENRE, DBAdapter.KEY_TITLE, DBAdapter.KEY_PLATFORM, DBAdapter.KEY_DATE, DBAdapter.KEY_PRICE, DBAdapter.KEY_WHEREBOUGHT};
int [] toViewIDs = new int []
{R.id.RecordNumberEdit, R.id.textView1, R.id.textView2, R.id.textView3, R.id.textView4, R.id.textView5, R.id.textView6};
//Create mapping from cursor to view fields
SimpleCursorAdapter myCursorAdapter = new SimpleCursorAdapter(
this,
R.layout.database_view_layout,
cursor, //Set of DB records
fromFieldNames, //DB field Names
toViewIDs //View IDs in which to put info
);
//Set the adapter for the list view
ListView listViewFromDB = (ListView) findViewById(R.id. listViewFromDB);
listViewFromDB.setAdapter(myCursorAdapter);
I changed the VACCUUM code to the following since the original code was actually passing the query twice :
String sql = "VACUUM;" ;
db.execSQL(sql);
Still, though, nothing seems to be happening.
I am trying to develop a Registration screen from Android XML. As in every Registration form, I would need to display the list of countries. I am able to do this using string-array in strings.xml file.
The greater part of the problem is, when a user selects a country, the phone number field just below it should be initially filled with its respective country code, which may or may not be editable. Here, my problem is how do I get the country code when the country is selected. Do I need to use a database or is it achievable using xml itself?
Besides that, when user submits the Register form, I would have to send the abbreviated code of the country, not the full country name. Now, again this would require either a database or xml?
My app doesn't use database till now, it would not be so good to use database for this purpose. Moreover, almost any application that uses a registration needs this thing to be done, but I cannot find any resources on how to do this in Android.
Also, I would like to tell you that my minimum sdk is version 7.
Please help.
I was finally able to do it without using database. I'm writing down the steps so that it may help anyone else who needs the same thing to be done.
First I downloaded the CSV available at: https://github.com/mledoze/countries/blob/master/countries.csv
I removed all other fields, except those I needed. It left me with 3 fields: name, abbreviation and calling code.
Next, I downloaded the CSVReader from: http://code.google.com/p/secrets-for-android/source/browse/trunk/src/au/com/bytecode/opencsv/CSVReader.java
Got the items from the CSV as mentioned in How to parse the CSV file in android application? by "Kopfgeldjaeger" as:
String next[] = {};
List<String[]> list = new ArrayList<String[]>();
try {
CSVReader reader = new CSVReader(new InputStreamReader(getAssets().open("countries.csv")));
for(;;) {
next = reader.readNext();
if(next != null) {
list.add(next);
} else {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
Next I added an ArrayList for each of the values like:
ArrayList<String> countryNames = new ArrayList<String>();
ArrayList<String> countryAbber = new ArrayList<String>();
ArrayList<String> countryCodes = new ArrayList<String>();
for(int i=0; i < list.size(); i++)
{
countryNames.add(list.get(i)[0]); // gets name
countryAbber.add(list.get(i)[1]); // gets abbreviation
countryCodes.add(list.get(i)[2]); // gets calling code
}
Then added it to the spinner in the XML layout as:
ArrayAdapter<String> countryAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, countryNames);
spinner.setAdapter(countryAdapter);
// adding event to display codes when country is selected
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int pos, long arg3) {
// display the corresponding country code
TextView tvCountryCode = (TextView) findViewById(R.id.country_code);
tvCountryCode.setText("+"+list.get(pos)[2]);
countryPosition = pos;
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
This way, I was able to display country code in the xml file, when a country was selected from the dropdown list.
Remember to add the setOnItemSelectedListener() to achive that.
I hope this helps somebody in future.
I would advise you to use a database. API level 7 supports SQLite databases (I used them in android 2.1 myself). Create one table that has all the required info:
create table countries (
_id integer primary key autoincrement,
country_code char(2),
country_name varchar,
phone_code char(4),
editable integer
);
Then store your country information into this table. When populating your list of countries, use this table instead of XML; display country names and associate country codes with each corresponding list item. Then on selection, use the country code to get the phone code and the 'editable' flag - and act upon this info.
i have a problem in a list view.. i want to put different fields in the same listview is this possible?
like this?
DBAdapter db = new DBAdapter(.this);
db.open();
List<String> ct = new ArrayList<String>();
ct = db.getAllAccounts();
List<String> sd = new ArrayList<String>();
sd = db.getAllAmount();
Account = (ListView) findViewById(R.id.ListView_addAccount);
Account.setAdapter(new ArrayAdapter<String>(this,R.layout.list_contas_layout,R.id.text1,R.id.text2, ct,sd));
theres something like this to use?
sorry about my english;)
Absolutely. Take a look at SimpleCursorAdapter. I'm not sure what database you're using, but using the Cursor class is pretty normal for this sort of thing. Otherwise you're going to have to create your own custom adapter.