I am facing a problem while updating a ListView via an ArrayAdapter in a Android Fragment.
I have a method handling a .csv that is retrieved from a server. It parses the .csv and does the following:
for(int i =0; i< lines.length; i++){
String[] words = lines[i].split(",");
for(int j = 0;j<words.length; j++)
if ( j%6 == 1 || j%6 == 2)
getArrayAdapter().add(words[j]);
Using breakpoints, I can see that "words[j]" is a valid String. The method getArrayAdapter is the following:
private ArrayAdapter<String> getArrayAdapter(){
if (aa == null){
ListView lv = (ListView) getCurrentActivity().findViewById(R.id.list);
aa = new ArrayAdapter<String>(
getCurrentActivity(),
android.R.layout.simple_list_item_1);
aa.setNotifyOnChange(true);
lv.setAdapter(aa);
}
return aa;
}
If the "getArrayAdapter().add(words[j]);" is called, method "notifyDataSetChanged()" in ArrayAdapter is called, as it should:
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
mNotifyOnChange = true;
}
Via its parent it reaches DataBaseObservable that does this:
public void notifyChanged() {
synchronized(mObservers) {
// since onChanged() is implemented by the app, it could do anything, including
// removing itself from {#link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {#link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
The array of observers had an "AdapterDataSetObserver" that contains all kind of references to my adapter and ListView. I looked what happens in the onChanged() of AdapterDataSetObserver, but I do not really know what to look at.
My table_fragment.xml looks like:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/top">
<ListView android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="2"
android:numColumns="2"
android:columnWidth="30dp"
android:id="#+id/list">
</ListView>
</LinearLayout>
The xml of the activity containing the Fragment looks like:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<fragment android:name="com.example.TableFragment"
android:id="#+id/table_fragment"
android:layout_weight="0"
android:layout_width="match_parent"
android:layout_height="0dip" />
</LinearLayout>
When looking in the log, nothing strange is there. All seems to go fine, but the screen does not show any of the strings.
What am I missing here? Probably missing something trivial, since I am a newbie to Android.
android:layout_height="0dip"
this is wrong. You should let get the ListView all the available space. Change it in fill_parent
then:
aa = new ArrayAdapter<String>(
getCurrentActivity(),
android.R.layout.simple_list_item_1);
you need to submit to the Apdater the dataset you want to show. For this purpose you should use this constructor
It turns out that layout_height of the ListView can be 0 (it auto expands). However, in the xml of the activity that contains the fragment, the layout_height could could not be set to 0 (it does not auto expand). I had put that on 0dip as well (after suggestion of Eclipse). Changing to "match_parent" did the job (despite the Eclipse warnings).
#Jos, the answer you selected is not the correct answer. The ListView height can, and should be, 0dp. In order for the ListView to function in its default manner you need to change the Id of the ListView to exactly android:id="#id/android:list" and you can also add a TextView or ProgressBar to show when the list is empty, also the default function of ListView, something like the following:
<TextView
android:id="#id/android:empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal|center_vertical"
android:text="#+string/empty_list_message" />
Again the id must match exactly, everything else can change to suit your needs.
Here is what the complete xml would look like:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="#id/android:list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:drawSelectorOnTop="false"
android:listSelector="#drawable/list_selector"/>
<TextView
android:id="#id/android:empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal|center_vertical"
android:text="#string/empty_list_message" />
</LinearLayout>
The layout_weight and listSelector are particular to my program, you may or may not need these.
Related
I am new to stack, but I figured I need help. I hope someone can help me :).
What I want to do is the following:
the user of the App is saving some database (db3) files via PC in a folder he has to create. In my case he needs to call it "My Custom Foler".
implement a Spinner which lets the user choose from all db3 files of this directory and then be able to do db_selected.getReadableDatabase
Just to put it in context: I am gonna implement a ContenProvider and the populate a ListView with Items from specific table using SQliteOpenHelper and LoaderManager.LoaderCallbacks<Cursor>. BUT THAT IS NOT MY QUESTION.
I want to setup this spinner. Maybe someone can help?
Here is my code so far with still a lot missing but the basic structure should be clear.
Greetings :)
I added:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
In activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/list">
</ListView>
<LinearLayout
android:id="#+id/login_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="8dp">
<Spinner
android:id="#+id/select_database"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</RelativeLayout>
MainActivity.class
public class MainActivity extends AppCompatActivity {
private final String DATABASE_PATH = "My Custom Folder";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//either we show login page or the populated ListView
ListView populatedListView = (ListView) findViewById(R.id.list);
View logInView = findViewById(R.id.login_view);
populatedListView.setEmptyView(logInView);
//How to setup a Spinner which lets select a ".db3" from a custom created Folder
Spinner spinner = findViewById(R.id.select_database);
//When Spinner item is clicked/touched I am gonna load it into my ListView
}
}
}
I tried using TwoWayView. My xml contains
<org.lucasr.twowayview.TwoWayView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/rewardListView"
style="#style/TwoWayView"
android:layout_marginTop="20dp"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:drawSelectorOnTop="false"
tools:context=".RewardActivity" />
I have created the Adapter which extends RecyclerView.Adapter and properly implemented every methods. Now in the activity, on the instance of TwoWayView, I try to set the adapter, but its not allowing me to set it up.
mRewardListView = (TwoWayView) findViewById(R.id.rewardListView);
adaptor = new RewardListViewAdaptor(mRewardList, this);
mRewardListView.setAdapter(adaptor);
I am getting this error "setAdapter(android.widget.ListAdapter) in TwoWayView cannot be cast to RewardListViewAdaptor".
Any help will be highly appreciated.
Having a bit of trouble dealing with empty ListView in android. Here's what I've got:
public class MainActivity extends ListActivity {
...
refreshList();
...}
public void refreshAlbumList(){
albumList=control.listAlbums();
if (albumList.length!=0){
ArrayAdapter<String> ap = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,albumList);
setListAdapter(ap);
}else{
//deal with empty list somehow, currently results in error
}
}
What I've tried is:
this.getListView().setEmptyView(findViewById(android.R.id.empty));
And then inserting a TextView with id empty into main_activity.xml
But the result was that took over the screen and I couldn't see the list.
Current xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android1="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity" >
<ListView
android1:id="#id/android:list"
android1:layout_width="match_parent"
android1:layout_height="wrap_content"
android1:layout_weight="1" >
</ListView>
</LinearLayout>
The ListView calls ListAdapter#isEmpty method to determine if it should show/hide itself and the empty view. You will therefore always need to set an ListAdapter.
So the answer is to always create your ArrayAdapter and always set it to the ListView. In your activities onCreate call ListView#setEmptyView method. Alternatively, you can simply have a TextView with the android:id="#android:id/empty" attribute and the ListActivity will detect it and assign it using the above method.
Example: https://gist.github.com/slightfoot/5519281
I've written a simple android list view, but it is throwing a java.lang.NullPointerException during run time. Checked it in debug mode and it seems the findViewbyId is returning null.
So when I get to the setAdapter it throws the exception. But the list does exist in the R.java file and the main.xml. How can I fix this?
setContentView(my.namespace.R.layout.main);
String[] a={"asd","asdsad"};
ListView lt;
lt = (ListView) findViewById(R.id.list);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,my.namespace.R.layout.rowitem, a);
lt.setAdapter(adapter);
Main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
Is your activity extends ListActivity? You dont need a separate layout if you extend ListActivity. See this tutorial for further reference.
Wirte this:
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,my.namespace.R.layout.simple_list_item_1, a);
Refer THIS
First a little background about why I'm asking this question...
I'm working on a scheduling app for a machine shop. I have a database with tables for the machines, jobs and employees. It's possible that not all of these machines will have jobs or operators, so I needed a way to add "None" to the spinners (there are several reasons I won't go into for not adding that to the database itself). To accomplish this I settled on getting a cursor from the database and iterating over it, loading those bits I needed into an ArrayList and adding a "None" element at the end.
This works just fine, but now I've come upon a sticking point I can't seem to figure out.
The Job table has two columns (not counting the index): a job number and a part number. I created a custom layout to put them together and then use that in the spinner (so you would see Job # - Part # on each line of the spinner). Populating that from a cursor was simple. Trying to convert that to two arrays has me stumped.
I can get the data from the cursor into the two arrays with no problem, but I can't figure out how to relate them to the layout ids contained in the layout.
I'm new to android and long time ago schooled in Java, so if I've missed something obvious, please point it out!
listlayoutdouble.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
<TextView
android:id="#+id/ListItem1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingLeft="12dip"
android:gravity="left|center_vertical"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/ListItem2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingRight="12dip"
android:gravity="right|center_vertical"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
What I have so far:
private void fillJobSpinner() {
Cursor jobsCursor = mDBHelper.fetchAllJobs();
startManagingCursor(jobsCursor);
ArrayList<String> jobnumbers = new ArrayList<String>();
ArrayList<String> jobnparts = new ArrayList<String>();
if (jobsCursor != null) {
operatorsCursor.moveToFirst();
while (operatorsCursor.isAfterLast() == false) {
jobnumbers.add(jobsCursor.getString(jobsCursor
.getColumnIndex(ScheduleDBAdapter.JOB_NUMBER)));
jobnparts.add(jobsCursor.getString(jobsCursor
.getColumnIndex(ScheduleDBAdapter.JOB_PART)));
jobsCursor.moveToNext();
}
jobnumbers.add("None");
jobparts.add("None");
}
}
I think what you need is a custom adapter for your spinner.
You need to extend BaseAdapter
http://developer.android.com/reference/android/widget/BaseAdapter.html
Then override the getView method.
A quick google turned up this tutorial:
http://app-solut.com/blog/2011/03/using-custom-layouts-for-spinner-or-listview-entries-in-android/