I have an app that uses a tab layout using fragments, in one of the fragments I would like to have a two/multi-line List View, I have been following this tutorial which shows it for a ListActivity. I have copied the code into my fragment and cannot seem to get it to work. all of my code for the layout of the fragment and the two lines is the same as code in the link above, with the exception of the Java class for the fragment I want to show the list in.
The code for the fragment is as follows:
package com.example.shopsellswap;
import java.util.ArrayList;
import java.util.HashMap;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SimpleAdapter;
public class Fragment_My_Profile extends ListFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myProfileView = inflater.inflate(R.layout.fragment_my_profile, container, false);
return myProfileView;
}
//ArrayList holds the data (as HashMaps) to load into the ListView
ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
//SimpleAdapter does the work to load the data in to the ListView
private SimpleAdapter sa;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//HashMap links each line of data to the correct TextView
HashMap<String,String> item;
for(int i=0;i<StatesAndCapitals.length;i++){
item = new HashMap<String,String>();
item.put( "line1", StatesAndCapitals[i][0]);
item.put( "line2", StatesAndCapitals[i][3]);
list.add( item );
}
sa = new SimpleAdapter(Fragment_My_Profile.this, list,
R.layout.my_two_lines,
new String[] { "line1","line2" },
new int[] {R.id.line_a, R.id.line_b});
setListAdapter(sa);
}
private String[][] StatesAndCapitals =
{{"Alabama","Montgomery"},
{"Alaska","Juneau"},
{"Arizona","Phoenix"},
{"Arkansas","Little Rock"},
{"California","Sacramento"}};
The part that is giving me errors is
sa = new SimpleAdapter(Fragment_My_Profile.this, list,
R.layout.my_two_lines,
new String[] { "line1","line2" },
new int[] {R.id.line_a, R.id.line_b});
setListAdapter(sa);
the specific error is:
The constructor SimpleAdapter(Fragment_My_Profile, ArrayList<HashMap<String,String>>, int, String[], int[]) is undefined
what's weird is when I change ListFragment to ListActivity the error is no longer there
Why it isn't working and how I can fix it?
ListFragment is not a subclass of Context, while ListActivity is. You must pass some type of Context to this constructor. For example, let's assume that your Activity (or FragmentActivity) class is named MainActivity:
sa = new SimpleAdapter(MainActivity.this, list, ...
Depending on when you create this Fragment that might not work, so you can move all of your code in onCreate() to the onActivityCreated() method and use:
sa = new SimpleAdapter(getActivity(), list, ...
Related
The title of this post says it all.
This code works without any problems:
package abc.AvailableCars;
import android.graphics.Color;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class carListActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.car_list_layout);
final ListView carListview = (ListView) findViewById(R.id.list_view);
final Button dButton = (Button) findViewById(R.id.disable_button);
String[] cars = {"Maxima GXE", "Passat", "Focus SE", "Mazda6", "Avalon", :Sentra GXE"};
final List<String> list_of_cars = new ArrayList<String>(Arrays.asList(cars));
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>
(this, android.R.layout.simple_list_item_1, list_of_cars);
carListview.setAdapter(arrayAdapter);
dButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int chosenRow = 3;
carListview.getChildAt(3).setEnabled(false);
carListview.getChildAt(3).setBackgroundColor(Color.parseColor("#3f51b5"));
}
});
}
}
This is in my listview .xml file:
<Button
android:id="#+id/disable_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Disable A Row"
/>
But, when I comment-out everything that belongs to the button, like below, and the Car List class is called, the app crashes with the error in the Logcat:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.setEnabled(boolean)' on a null object reference:
final ListView carListview = (ListView) findViewById(R.id.list_view);
//final Button dButton = (Button) findViewById(R.id.disable_button);
String[] cars = {"Maxima GXE", "Passat", "Focus SE", "Mazda6", "Avalon"};
final List<String> list_of_cars = new ArrayList<String>(Arrays.asList(cars));
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>
(this, android.R.layout.simple_list_item_1, list_of_cars);
carListview.setAdapter(arrayAdapter);
//dButton.setOnClickListener(new View.OnClickListener() {
//#Override
//public void onClick(View v) {
int chosenRow = 3;
carListview.getChildAt(chosenRow).setEnabled(false);
carListview.getChildAt(chosenRow).setBackgroundColor(Color.parseColor("#3f51b5"));
}
//});
}
//}
I'm not an Android newbie anymore, but this is eluding me.
I want the chosen row to be disabled and the color set as soon as the listview is shown.
How can I do this programmatically without a button?
I have tried every variation I can think of, getView(), even a fake click.
Just in case it makes a difference, this code is in a separate class and file than the MainActivity.java file, and is called in that file.
There has to be a simple answer. What do I need to change?
Please be verbose.
Thank you.
You are calling carListview.getChildAt(chosenRow) when you set up your list view, in onCreate. Your list view is not ready yet. Try moving this code to your onResume - should look something like this:
#Override
public void onResume(){
super.onResume();
arrayAdapter.notifyDataSetChanged();
int chosenRow = 3;
carListview.getChildAt(chosenRow).setEnabled(false);
carListview.getChildAt(chosenRow).setBackgroundColor(Color.parseColor("#3f51b5"));
}
This is a pretty simple case - your chosenRow number is generated by you. You might need a custom Adapter if you need it to be algorithmic or user-driven. Have a look at this tutorial.
From my understanding, since listViews are views, they have to be Overridden for some things to be changed in them.
I chose not to disable the required rows, but check for them in code.
The complete code that works is below.
Some credit goes to Raghunandan for his/her answer at-
Android - Change background color of specific item of ListView
Again, sorry, but the indentation of the code wouldn't work correctly for some reason.
import android.graphics.Color;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class CarListActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.car_list_layout);
final ListView carListview = (ListView) findViewById(R.id.list_view);
String[] cars = {"European Cars:", "Mercedes", "Passat", "Bently", "Porsche", "BMW", "Yugo","Land Rover",
"Japanese Cars:", "Maxima GXE", "Mazda6", "Avalon", "Toyota", "Honda", ""};
final List<String> list_of_cars = new ArrayList<String>(Arrays.asList(cars));
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>
(this, android.R.layout.simple_list_item_1, list_of_cars);
//------------------------------------------
carListview.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list_of_cars) {
// Since listViews are views, they have to be Overrdden for some things to be changed in them.
#Override
public View getView(int rowPosition, View convertView, ViewGroup parent) {
View row = super.getView(rowPosition, convertView, parent);
//------------------------------------------
// This works. I have only tried this for two rows, the two I wanted. I expected this line to crash the app, but it didn't.
if(getItem(rowPosition).equals("European Cars:") || getItem(rowPosition).equals("Japanese Cars:")) {
// Make the two rows have a white background color.
row.setBackgroundColor(Color.WHITE); // this command WORKS fine by itself.
// row.setEnabled(false); this command caused "bleeding" over into other rows, so I will check for the rows in a condition.
} // both of the getItems end here.
else {
// All of the other rows should have this color.
row.setBackgroundColor(Color.parseColor("#EEE8AA"));
// the default color
} // else ends here.
//------------------------------------------
return row;
//------------------------------------------
} // getView ends here.
}); // carListview.setAdapter ends here.
} // onCreate ends here.
} // CarListActivity ends here.
Thanks, and I hope this helps others.
I am developing an application for android 2.2, in which I would like to have a ListView with the possibility of onLongClickListener method. So far I have been using this example, but now I got stuck at getLoaderManager().initLoader(0, null, this); because my eclipse claims that it can't find the method. I've got this:
import android.app.ListActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
public class SBNextends extends ListActivity implements LoaderCallbacks<Cursor>{
SimpleCursorAdapter adapter;
private TextView tView;
#Override
protected void onCreate(Bundle b) {
super.onCreate(b);
setContentView(R.layout.sbn);
tView= (TextView) findViewById(R.id.sbn);
tView.setText("");
for (int i = 0; i < MyDataLoader.getData.size(); i++) {
tView.append(MyDataLoader.dataListONE.get(i));
}
String[] from = new String[MyDataLoader.dataListONE.size()];
for(int i = 0; MyDataLoader.dataListONE.size()> i; i++) {
from[i] = MyDataLoader.dataListONE.get(i);
}
int[] toView = {android.R.id.text1};
adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, null, from, toView);
setListAdapter(adapter);
}
Any one got any ideas of why I can't use the getLoaderManager() method? I have imported the support libraries
Well, you need to be consistent with the base classes that you use: either from compatibility package, either from android.app one. In your case you're extending from android.app.ListActivity, so replace:
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
with:
import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Loader;
But in this case, you're not actually running against 2.2. So you better stick with compatibility package by extending from FragmentActivity and make your own FragmentListActivity.
It is how I use LoaderCallbacks on v4 apps.
Instead of using ListActivity, use FragmentActivity. In this case, you have to instance your ListView by findViewById as it wouln't automatically instance your ListView.
public class MainActivity extends FragmentActivity implements LoaderCallbacks<Cursor>{
SimpleCursorAdapter mAdapter;
ListView listView ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView)findViewById(R.id.list);
String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME};
int[] toViews = {android.R.id.text1}; // The TextView in simple_list_item_1
// Create an empty adapter we will use to display the loaded data.
// We pass null for the cursor, then update it in onLoadFinished()
mAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1, null,
fromColumns, toViews, 0);
listView.setAdapter(mAdapter);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getSupportLoaderManager().initLoader(0, null, this);
}
I am doing an application in android. The application saves a quote or an expression in a textfield. The user has the opportunity to change this text. But I wanted that when the quote is appeared in the TextView, it is not appeared at all. I wanted only the first 5 characters of the quote to be appeared. I try to do this using the substring, but when I open the TextView nothing appears. The TextView is empty. What can I do?
Can anyone help me , please.
Thanks in advance.
This is the line where I use substring:
ListAdapter adapter = new SimpleAdapter( Quote.this,quoteList, R.layout.quote_entry, new String[] { "quoteId", "textQuote".substring(0, 4)}, new int[] {R.id.quoteId, R.id.textQuote});
And here is the entire class
package com.example.prova1;
/**This class is the page of quotes*/
import java.util.ArrayList;
import java.util.HashMap;
import android.app.ListActivity;
import com.example.prova1.Database;
import com.example.prova1.EditQuote;
import com.example.prova1.AddQuote;
import com.example.prova1.R;
import android.os.Bundle;
import android.content.Intent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.SimpleAdapter;
import android.widget.ListView;
public class Quote extends ListActivity {
Intent intent;
TextView quoteId;
Database quotedatabase = new Database(this);
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.quote_main);//define that the interface used is quote_main
//Store data from database in an array list
ArrayList<HashMap<String, String>> quoteList = quotedatabase.getAllItems();
//Check if there are quotes to display
if(quoteList.size()!=0) {
ListView listView = getListView();
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
quoteId = (TextView) view.findViewById(R.id.quoteId);
String itemIdValue = quoteId.getText().toString();
Intent theIndent = new Intent(getApplication(),ShowQuote.class);
theIndent.putExtra("quoteId", itemIdValue);
finish();
startActivity(theIndent);
}
});
// Here we use ListAdapter as a bridge between ListView and the data of ListView
ListAdapter adapter = new SimpleAdapter(
Quote.this,quoteList,
R.layout.quote_entry,
new String[] {
"quoteId",
"textQuote".substring(0, 4)
},
new int[] {
R.id.quoteId,
R.id.textQuote}
);
setListAdapter(adapter);
}
}
}
I don't have the SDK installed at the moment to test your code, but I do have a couple suggestions.
First: Try the code without the substring, and see if that works.
Second: If that works, then move the substring operation to the line before and pass in the result to the SimpleAdapter.
I say this because I have the feeling that the substring is not actually your problem. And this is just a good way to test that.
I'd also check your layout "R.layout.quote_entry" and make sure there isn't anything weird going on with that. Such as you having "R.id.textQuote" actually being 'gone' and another TextView being visibly shown, etc. I had this problem once. I had two EditText fields, and only one of them was being shown, so the Activity looked right, but wasn't behaving properly.
I created a Custom ListView using BaseAdapter now I want to populate this Listview with Contact Name and Number from Phone book..I am trying this..
import java.util.ArrayList;
import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;
public class Rabtaye extends Activity {
ListView msgList;
ArrayList<MessageDetails> details;
AdapterView.AdapterContextMenuInfo info;
Cursor cursor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_main);
msgList = (ListView) findViewById(R.id.MessageList);
details = new ArrayList<MessageDetails>();
MessageDetails Detail = new MessageDetails();
cursor = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null,
null, null);
startManagingCursor(cursor);
String info[] = { ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone._ID };
for(String a:info){
Detail.setName(a);
}
Detail.setNumber("0313");
details.add(Detail);
// int to[] = { R.id.name, R.id.number };
// ListAdapter cursada = new SimpleCursorAdapter(this,
// android.R.layout.simple_expandable_list_item_2, cursor, info,
// to);
msgList.setAdapter(new CustomAdapter(details, this));
msgList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
TextView s = (TextView) arg1.findViewById(R.id.name);
String abc = s.getText().toString();
Toast.makeText(Rabtaye.this, abc, Toast.LENGTH_LONG).show();
}
});
}
}
I used different ways, but I am not able to populate ListView with Contact Name or Number. In this code I have to statically add name and number...I am quite confuse here..little help would be greatly appreciated. Thanks in Advance. I am newbie so please go easy on me..:)
Hmmm. You're on the right track, but I think you're wandering a bit.
A ListView is a view object, not a BaseAdapter. As far as I can tell from your code, you don't need a custom adapter for your ListView.
What you should do is bind a regular CursorAdapter to your ListView, load the Contacts data you want from the Contacts Provider using a CursorLoader, then move the resulting Cursor to the CursorAdapter.
You can find the instructions for doing this in this Android training class:
Loading Data in the Background.
What do you want in your custom ListView that you can't get from ListView itself?
If you're putting more than just a single list of items into a ListView (it looks like you're doing name, number, etc.) you have to create your own custom adapter. Extend the BaseAdapter class either in your activity, or in a new class. Then you'll have to override the getView() method. This is what is called every time a new item gets inflated.
You pass your ArrayList into the BaseAdapter when you create it. The getView() method of the adapter is where you code your logic to take the data and present it as a list item. You'll have to define a new XML file as a layout for each list item that contains your TextViews and whatnot for your different children in each list item, and that's what you populate with your data.
There are a bunch of examples all over if you search for "baseadapter". Here's one that gives a pretty good intro.
I'm calling the setAdapter() method in a class that extends Fragment. Note that I have imported android.support.v4.app.Fragment .
However I get an error stating that the API level is required to be level 11.
What do I have to do so that I can fix this without changing minSdkVersion="8" to minSdkVersion="11"
package foo.bar.qux;
import java.util.Calendar;
import java.util.Date;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import android.support.v4.app.Fragment;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
public class TabFragmentList extends Fragment {
String category, xml;
NodeList nodes;
int numResults;
private ListView lv;
Date date;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) return null;
return (LinearLayout) inflater.inflate(R.layout.eventlist, container,
false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Activity activity = getActivity();
if (activity != null) {
final Calendar c = Calendar.getInstance();
ListContent[] item = new ListContent[3];
category = (String) activity.getIntent().getExtras()
.get("category");
xml = (String) activity.getIntent().getExtras().get("xml");
TextView tv = (TextView) getView().findViewById(R.id.category);
tv.setText(category);
nodes = doc.getElementsByTagName("event");
for (int i = 0; i < 3; i++) {
c.add(Calendar.DATE, 1);
date = c.getTime();
item[i] = new ListContent();
item[i].setList(nodes, category, date);
}
EventListAdapter adapter = new EventListAdapter(activity,
R.layout.eventlist_row, item);
lv = (ListView) getView().findViewById(R.id.listView1);
lv.setAdapter(adapter); // ERROR SHOWN HERE
}
}
}
Note : I tried reducing the targetSdkVersion to 10. Yet I get the error. Please help!
Edit : I don't understand why it's termed as AbsListVew when all that I have used is a ListView. Also, note that I've used a custom adapter.
EventListAdapter extends ArrayAdaptere<ListContent> and shows NO ERROR.
For your reference here is the xml layout code snippet for R.id.ListView1
<ListView
android:layout_margin="10dp"
android:dividerHeight="10.0sp"
android:id="#+id/listView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
Right click on the project folder > Android tools > Clear Link Markers
"Run Android Lint" makes some markers and the markers cause this error.
Solution is just casting type to correct subtype as later Android versions introduced method call with same name.
#SuppressWarnings({ "unchecked", "rawtypes" })
EventListAdapter adapter = new EventListAdapter(activity, R.layout.eventlist_row, item);
lv = (ListView) getView().findViewById(R.id.listView1);
((AdapterView)lv).setAdapter(adapter); //ERROR SOLVED HERE
As you can see in the docs setAdapter() method on AbsListView is available just from API Level 11. So there isn't much you can do, you can just cast eventually your AbsListView to a ListView or GridView and then call setAdapter().
I solved the "abstract method not implemented error" by casting my setAdapter method like this:
#SuppressWarnings("unchecked")
public void setAdapterSDK8(Adapter adapter) {
((AdapterView) this).setAdapter(adapter);
((StaggeredGridView) this).setAdapter((ListAdapter) adapter);
}
This is related to the etsy staggered gridview