I am building an app that uses ListView and a custom adapter extending BaseAdapter to handle the data to the ListView. The code is as follows:
newlist.java compiles/runs fine
public class newslist extends Activity {
public static final String tag = "newslist";
ListView listNews;
MyListAdapter listAdapter;
/** Set or Grab the URL */
public static final String parseURL = "http://www.example.com.gr/article.php";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newslist);
/** Array Lists */
ArrayList<String> titles = new ArrayList<String>();
ArrayList<String> links = new ArrayList<String>();
ArrayList<String> dates = new ArrayList<String>();
Log.d(newslist.tag, "****** parseURL = " + parseURL);
listNews = (ListView) findViewById(R.id.listNews);
try {
/** Open URL with Jsoup */
Document doc = Jsoup.connect(parseURL).get();
/** Grab classes we want */
Elements pcontent = doc.getElementsByClass("content_title");
Elements pdates = doc.getElementsByClass("content_datecreated_left");
/** Loop for grabbing TITLES within parent element */
for (Element ptitles : pcontent) {
/** Grab Anchors */
Elements ptitle = ptitles.getElementsByTag("a");
for (Element title : ptitle) {
titles.add(title.text());
}
}
/** Loop for grabbing LINKS within parent element */
for (Element plinks : pcontent) {
/** Grab anchors */
Elements plink = plinks.getElementsByTag("a");
for (Element link : plink) {
links.add(link.attr("abs:href")); /** parse absolute address */
}
}
/** Loop for grabbing DATES within parent element */
for (Element pdate : pdates) {
dates.add(pdate.text()) ;
}
//TODO: Regex on Date
//String content: Main Activity Content
int i=0;
int num = titles.size();
String[] printDates = new String[num];
for (i=0; i < num; i++)
{
//substring(25) leaves a space after the date, eg "26/6/2011 "
//content[i] = titles.get(i) + "\n Date: " + dates.get(i).substring(25);
printDates[i] = dates.get(i).substring(25);
}
/** Create an ArrayAdapter, that will actually make the Strings above
* appear in the ListView */
listAdapter = new MyListAdapter(this, titles, dates);
listNews.setAdapter(listAdapter);
} catch (Exception e) {
Log.e(newslist.tag, "****** Failed to Parse URL:" + e.getMessage());
e.printStackTrace();
}
} /*- OnCreate End -*/
} /*- Class End -*/
MyListAdapter.java runs a NPE at line 75:
public class MyListAdapter extends BaseAdapter {
public final static String tag = "MyListAdapter";
public Context context;
public ArrayList<String> title;
public ArrayList<String> date;
public LayoutInflater inflater;
public MyListAdapter(Activity context, ArrayList<String> title, ArrayList<String> date) {
super();
this.context = context;
this.title = title;
this.date = date;
this.inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
// Auto-generated method stub
return this.title.size();
}
public Object getItem(int position) {
//Auto-generated method stub
return this.title.get(position);
}
public long getItemId(int position) {
// Auto-generated method stub
return position;
}
private static class ViewHolder {
TextView titleView;
TextView dateView;
}
public View getView(int position, View convertView, ViewGroup parent)
{
// Auto-generated method stub
ViewHolder holder;
Log.d(tag, "****** convertView: " + convertView);
if (convertView == null)
{
convertView = inflater.inflate(R.layout.listrow, null);
holder = new ViewHolder();
holder.titleView = (TextView) convertView.findViewById(R.id.listTitle);
holder.dateView = (TextView) convertView.findViewById(R.id.listDate);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
Log.d(tag, "****** Title: " + title.get(position));
Log.d(tag, "****** findViewById: " + convertView.findViewById(R.id.listTitle));
Log.d(tag, "****** holder.titleView: " + holder.titleView);
holder.titleView.setText(title.get(position));
holder.dateView.setText(date.get(position));
//notifyDataSetChanged();
return convertView;
}
}
Line 75 is:
holder.titleView.setText(title.get(position));
However I have tracked the problem to line 62:
holder.titleView = (TextView) convertView.findViewById(R.id.listTitle);
where it seems from my debugging messages that holder.titleView is null
I have tried cleaning/erasing bin folder and rebuilding the project to no avail. I think the problem lies in the View R.id.listTitle not being found. But i have no idea why.
I will also include my two xml files for previewing
newslist.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/title"
android:gravity="center|top"
android:textSize="20dip"
android:textStyle="bold"
android:text="#string/titleNewslist"
/>
<ListView
android:id="#+id/listNews"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
</ListView>
</LinearLayout>
listrow.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:name="#+id/listTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top|left"
android:textSize="18dip"
android:textStyle="bold"
android:text="TextView">
</TextView>
<TextView
android:name="#+id/listDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom|right"
android:textSize="12dip"
android:textStyle="bold"
android:textColor="#android:color/white"
android:text="TextView">
</TextView>
</LinearLayout>
You never assign anything to titleView.
You need to do the following in your onCreate() after super.onCreate()
titleView = (TextView) this.getViewById(R.id.listTitle);
Make sure to declare titleView as a field at the top of your class so the rest of your class can access it, if you need to.
Hope this helps!
EDIT:
An important note I just noticed:
android:name="#+id/myName"
is NOT the same as
android:id="#+id/myName"
You need to make sure you declare the ids, or you will not be able to access the layout elements.
I don't really understand the use of ViewHolder.
You should do :
convertView = new YourViewClass();
in this class have 2 fields for both textviews and a onCreate that inflate listRow.xml and find both views by id.
but converview and view holder should not be different and you should not try to pass one view from one component to the other.
Regards,
Stéphane
NullPointerException usually comes, when you have some problems with your XML files. Try to not end your
<TextView
android:name="#+id/listTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top|left"
android:textSize="18dip"
android:textStyle="bold"
android:text="TextView">
</TextView>
with > and instead of > and
I'm not sure that it's the source of your problem, but it can happen.
Hope it helps.
you are passing the Activity context into the MyListAdapter constructor and assign to the Context object.
change the Activity to Context in constructor and then try it
Related
How do you add multiple adapters to a listview? After reading this question and following the tutorial, I still don't have what I want.
Scenario
Adding two types of text into an SQLite database table and retrieving them on another activity in the form of a card with a title on top, a separator, and the content underneath.
Visuals
Adding content to main list:
Card on main list:
My Code
I take it no one really needs to see the layout for the edittext part so I'll jump right to the main card row item layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:background="#drawable/card_selecter_background">
<TextView
android:id="#+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sample"
android:textSize="30sp"/>
<View
android:id="#+id/separator"
android:layout_marginTop="5dp"
android:layout_marginBottom="2dp"
android:layout_width="fill_parent"
android:layout_height="1dp"
android:background="#android:color/darker_gray"/>
<TextView
android:id="#+id/tvContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sample"
android:textSize="22sp"/>
</LinearLayout>
This is where I add the edittext strings to the database:
db.execSQL("CREATE TABLE IF NOT EXISTS Lists (Title VARCHAR, Content VARCHAR);");
addListBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean cancel = false;
String listName = listNameET.getText().toString();
String content = contentET.getText().toString();
if (TextUtils.isEmpty(listName)) {
listNameET.setError("Please enter a list name.");
cancel = true;
} else if (listName.contains("'") || listName.contains("\"")) {
listNameET.setError("Please enter alphanumeric (abc123) characters only.");
cancel = true;
}
if (TextUtils.isEmpty(content)) {
contentET.setError("Field cannot be left blank.");
cancel = true;
} else if (content.contains("'") || content.contains("\"")) {
contentET.setError("Please enter alphanumeric (abc123) characters only.");
cancel = true;
}
if (cancel) {
//Nothing happens
} else {
db.execSQL("INSERT INTO Lists VALUES('" + listName + "', '" + content + "');");
db.close();
finish();
}
}
});
Here is where it is retrieved in the listview activity:
Cursor c = db.rawQuery("SELECT Title from Lists", null);
Cursor c2 = db.rawQuery("SELECT Content from Lists", null);
final ArrayList<String> titleList = new ArrayList<String>();
final ArrayList<String> contentList = new ArrayList<String>();
if (c.moveToFirst() && c2.moveToFirst()) {
do {
titleList.add(c.getString(c.getColumnIndex("Title")));
contentList.add(c2.getString(c2.getColumnIndex("Content")));
} while (c.moveToNext() && c2.moveToNext());
}
ArrayAdapter<String> titleAdapter = new ArrayAdapter<String>(MainActivity.this, R.layout.listname_row, R.id.tvTitle, titleList);
ArrayAdapter<String> contentAdapter = new ArrayAdapter<String>(MainActivity.this, R.layout.listname_row, R.id.tvContent, contentList);
ListView lv = (ListView) findViewById(R.id.listOfNames);
//Since Java works top to bottom, the contentAdapter is set even though
//this line is here.
lv.setAdapter(titleAdapter);
lv.setAdapter(contentAdapter);
db.close();
c.close();
I need to be able to attach the title and the content to the same listview.
Help is much appreciated!
You can create a custom Adapter like this:
class ExampleAdapter extends BaseAdapter{
List<String> mTitles;
List<String> mContents;
#Override
public int getCount() {
return mTitles.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v;
//inflate view if needed
...
TextView tv_title;
TextView tv_content;
String title = mTitles.get(position);
String content = mContents.get(position);
tv_title.setText(title);
tv_content.setText(content);
return v;
}
}
Now past 2 list of String to this Adapter and call setAdapter of ListView.
I am implmenting a Fragment activity that implements ActionBar.TabListener, so I have 3 tabs that each have ListFragments which have a list populated with data obtained through the server. I have been facing this issue for a while now, and I couldn't find an answer no matter how many questions I looked into regarding this particular issue or how many tutorials I looked at in regarding implementing ListFragments with custom array adapters.
The issue I'm having is that I couldn't get the data on the Listview to display on the app. I have managed to obtain the data through the server that I needed to populate the Custom Array Adapter before setting the adapter to the ListView. I even debugged the code and it says that the data is populated in the Adapter as well as in the Listview after making the call to set the array adapter to that Listview. Yet, I couldn't get the data in the Listview to show up in the app. I have been looking into this issue for a while now and I looked into this issue through tutorials and questions posted in forums for any suggestions(Even this one) and I have yet to find anything that has helped me resolve my issue. If anyone could point out on what I did wrong and offer suggestions to fix this issue, I'd gladly appreciate any input.
Code for the ListFragment Activity
public class MyJobsActivity extends ListFragment{
private ArrayList<Job> myJobs;
private static ListView listView;
private static ArrayList<Job> jobList;
ActionBar titleBar;
MyJobsActivity disAllList;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myJobs = (ArrayList<Job>) getArguments().getSerializable(Constants.MYJOBS);
jobList = new ArrayList<Job>();
Job datJob;
for(int i = 0; i < myJobs.size(); i++){
datJob = new Job();
datJob.setJobId(myJobs.get(i).getJobId());
datJob.setJobTitle(myJobs.get(i).getJobTitle());
datJob.setCompany(myJobs.get(i).getCompany());
datJob.setLocation(myJobs.get(i).getLocation());
jobList.add(datJob);
}
MyJobsAdapter datAdapter = new MyJobsAdapter(getActivity(), R.layout.job_row, jobList);
listView.setAdapter(datAdapter);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
try{
Intent datIntent = new Intent(getActivity(),JobActivity.class);
Job job = jobList.get(position);
datIntent.putExtra(Constants.JOBID, job.getJobId());
datIntent.putExtra(Constants.JOBTITLE, job.getJobTitle());
startActivity(datIntent);
}
catch(RuntimeException e){
e.printStackTrace();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View rootView = inflater.inflate(R.layout.activity_my_jobs, container, false);
listView = (ListView) rootView.findViewById(android.R.id.list);
return rootView;
}
}
XML file for ListFragment Activity
<?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:gravity="center_horizontal"
android:orientation="vertical"
android:background="#FFFFFF">
<ListView
android:id="#android:id/list"
android:drawSelectorOnTop="false"
android:tag="my_jobs"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent" />
</LinearLayout>
Code for the custom array adapter
public class MyJobsAdapter extends ArrayAdapter<Job> {
private Activity activity;
private ArrayList<Job> data;
private HashMap<Integer, Boolean> selection;
private static LayoutInflater inflater=null;
private TextView jobPosition, company, location;
private CheckBox jobChecked;
private View actionView;
private int height, prevSize;
private ActionMode datMode;
public MyJobsAdapter(Activity a, int layoutResourceId, ArrayList<Job> jobs) {
super (a, layoutResourceId, jobs);
this.selection = new HashMap<Integer, Boolean>();
this.activity = a;
this.data = jobs;
}
private class ViewHolder {
TextView jobTitle;
TextView companyName;
TextView location;
}
/*public void setData(ArrayList<Job> d){
data = d;
if(data != null){
for (Job job : d){
add(job);
}
}
this.notifyDataSetChanged();
} */
public void setNewSelection(int position, boolean value){
prevSize = selection.size();
selection.put(position, value);
this.notifyDataSetChanged();
}
public boolean isPositionChecked(int position, boolean value){
boolean result = selection.get(position);
return result == true ? result : false;
}
public void removedSelection(int position){
prevSize = selection.size();
selection.remove(position);
this.notifyDataSetChanged();
}
public void clearSelection(){
prevSize = 0;
selection = new HashMap<Integer, Boolean>();
this.notifyDataSetChanged();
}
#Override
public int getCount() {
return data.size();
}
#Override
public long getItemId(int position) {
return position;
}
public void setMode(ActionMode mode){
datMode = mode;
}
public int getSelectedNumberOfItems(){
return selection.size();
}
public HashMap<Integer, Boolean> getSelectedList(){
return selection;
}
public ArrayList<Job> getData(){
return data;
}
public int getHeight(){
return height;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder jobHolder = null;
Job rowItem = getItem(position);
if(convertView==null){
convertView = inflater.inflate(R.layout.job_row, parent, false);
convertView.setBackgroundResource(R.drawable.list_selector);
jobHolder = new ViewHolder();
jobHolder.jobTitle = (TextView) convertView.findViewById(R.id.Position);
jobHolder.companyName = (TextView) convertView.findViewById(R.id.Company);
jobHolder.location = (TextView) convertView.findViewById(R.id.Location);
convertView.setTag(jobHolder);
} else{
jobHolder = (ViewHolder) convertView.getTag();
}
/* jobPosition = (TextView)vi.findViewById(R.id.Position);
company = (TextView)vi.findViewById(R.id.Company);
location = (TextView)vi.findViewById(R.id.Location);
jobChecked = (CheckBox)vi.findViewById(R.id.JobSelected);
jobChecked.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
StringBuilder lSelectedString = new StringBuilder(selection.size()).append(Constants.SELECTED);
if(isChecked){
setNewSelection(position,true);
datMode.setTitle(lSelectedString.toString());
}
else{
removedSelection(position);
datMode.setTitle(lSelectedString.toString());
if(selection.size() < 1)
datMode.finish();
}
}
});
if(selection.size() == 0){
jobChecked.setVisibility(View.GONE);
}
else{
jobChecked.setVisibility(View.VISIBLE);
jobChecked.setChecked(selection.get(position) == null ? false : true);
}
vi.setBackgroundResource(selection.get(position) == null ? color.white_color : color.holo_blue_bright);
*/
jobHolder.jobTitle.setText(rowItem.getJobTitle());
jobHolder.companyName.setText(rowItem.getCompany());
jobHolder.location.setText(rowItem.getLocation());
return convertView;
}
}
Code for each row in the ListView
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/light_gray"
android:paddingTop="8dip"
android:paddingBottom="8dip"
android:descendantFocusability="blocksDescendants">
<RelativeLayout
android:id="#+id/JobRow"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<CheckBox
android:id="#+id/JobSelected"
android:layout_centerVertical ="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/Position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/dark_gray_position"
android:layout_toRightOf="#+id/JobSelected"
android:typeface="sans"
android:fontFamily="Roboto Regular"
android:textSize="22sp"
android:paddingLeft="4dip"/>
<TextView
android:id="#+id/Company"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#color/blue_company"
android:textSize="18sp"
android:fontFamily="Roboto Regular"
android:paddingLeft="4dip"
android:layout_below="#+id/Position"
android:layout_toRightOf="#+id/JobSelected"/>
<TextView
android:id="#+id/Location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/Company"
android:layout_toRightOf="#+id/JobSelected"
android:paddingBottom="8dip"
android:paddingLeft="4dip"
android:textColor="#color/steel_gray_location"
android:fontFamily="Roboto Regular"
android:textSize="14sp"/>
</RelativeLayout>
</RelativeLayout>
Well there are a few issues you might have with the fragment lifecycle due to the statics in your MyJobsActivity, but as for showing the data itself:
In your MyJobsActivity.onActivityCreated (or wherever you end up associating your custom adapter with the underlying ListFragment), you need to use setListAdapter instead of setAdapter.
From the ListFragment docs (see Binding to Data):
You must use ListFragment.setListAdapter() to associate the list with an adapter. Do not directly call ListView.setAdapter() or else important initialization will be skipped.
To be a bit more clear, one of the many benefits of using/extending a ListFragment is that it will internally handle the binding between your custom adapter and the underlying ListView, but the adapter must be added to the ListFragment itself (i.e., setListAdapter), not on the ListView.
A few other observations:
In fact, unless you need a custom layout, I would recommend completely removing your implementation of onCreateView. This will allow the ListFragment to use its default layout, initialization, and handling for its internal ListView and you'll get (default) handling of an empty list, a loading progress bar, etc. as well.
Given the code you've posted, I would recommend against using a private ListView member in your MyJobsActivity - its parent ListFragment already maintains a copy of the underlying ListView for you, and if you're properly setting the adapter via setListAdapter, you don't need the explicit object (and if you do, use ListFragment's getListView()).
Regardless, if my own trials and challenges are any indication, the static ListView and ArrayList members will most certainly cause you grief when the fragment is destroyed and recreated (on orientation change, on restore of your app from the Recents list if the process has been torn down in the interim, etc.).
My current code layout no fragment at the moment,
I need to make a little change on Status(-/Picking/Picked) and Button(Pick-enable/disable) to fragment because I need to keep the data for status and button(enable/disable) always up-to-date/sync to database.
The apps and same piece of data would use by few authorize users. If one of user click on "Pick" button,the rest of user who use the apps,particular Pick button should be disable and status should display "Picking" immediately without refresh the whole layout.
I'm quite new on android apps development, although have some idea/logic to do it but a bit confuse...
Following is my current code...
Hope someone advice me where is the proper place to plant in the "fragment",so I could run a thread behind to get rest service info then display up-to-date value on status and Pick button accordingly immediately without refresh the whole layout .
<LinearLayout
<TextView
android:id="#+id/code"
.../>
<TextView
android:id="#+id/name"
.../>
<TextView
android:id="#+id/qty"
.../>
<TextView
android:id="#+id/status"
.../>
<Button
android:id="#+id/pickButton"
...
android:text="#string/pick" />
/>
.
On the Activity
public class blablaActivity extends ListActivity{
#Override
protected void onStart(){
super.onStart();
new HttpRequestTask().execute();
}
private class HttpRequestTask extends AsyncTask<Void, Void, ArrayList<PickerItemDetail>> {
//private SkuArrayAdapter m_adapter;
#Override
protected ArrayList<PickerItemDetail> doInBackground(Void... params) {
try {
final String url = "http://10.0.2.2:8080/picking";
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
List<PickerItemDetail> resultList = Arrays.asList(restTemplate.getForObject(url, PickerItemDetail[].class));
ArrayList<PickerItemDetail> pickerList = new ArrayList<PickerItemDetail>();
if(resultList.size()>0){
for(int i=0;i<resultList.size();i++){
PickerItemDetail pickerItemDetail = resultList.get(i);
pickerList.add(pickerItemDetail);
}
}
return pickerList;
} catch (Exception e) {
Log.e("ListFruitActivity:doInBackground", e.getMessage(), e);
}
return null;
}
#Override
protected void onPostExecute(ArrayList<PickerItemDetail> pickerList) {
try{
m_adapter = new SkuArrayAdapter(PickerItemActivity.this,pickerList);
setListAdapter(m_adapter);
}catch(Exception e){
Log.e("ListFruitActivity:onPostExecute", e.getMessage(), e);
}
}
}
}
ArrayAdapter...
public class SkuArrayAdapter extends ArrayAdapter<PickerItemDetail>{
private ArrayList<PickerItemDetail> objects;
private String currentsku;
public SkuArrayAdapter(Context context,ArrayList<PickerItemDetail> objects){
super(context,R.layout.activity_list_fruit,objects);
this.objects = objects;
}
public View getView(int position,View convertView,ViewGroup parent){
// assign the view we are converting to a local variable
View v = convertView;
// first check to see if the view is null. if so, we have to inflate it.
// to inflate it basically means to render, or show, the view.
if (v == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.activity_list_fruit, null);
}
/*
* Recall that the variable position is sent in as an argument to this method.
* The variable simply refers to the position of the current object in the list. (The ArrayAdapter
* iterates through the list we sent it)
*
* Therefore, i refers to the current Item object.
*/
PickerItemDetail i = objects.get(position);
if (i != null) {
TextView code = (TextView) v.findViewById(R.id.code);
TextView name = (TextView) v.findViewById(R.id.name);
TextView qty = (TextView) v.findViewById(R.id.qty);
TextView status = (TextView) v.findViewById(R.id.status);
Button btn = (Button) v.findViewById(R.id.pickButton);
//some code....//
}
return v
}
At the moment I am getting items out of my database and add them to a string called result which I return and set to my TextView:
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.level);
loadDataBase();
int level = Integer.parseInt(getIntent().getExtras().getString("level"));
questions = new ArrayList<Question>();
questions = myDbHelper.getQuestionsLevel(level);
tvQuestion = (TextView) findViewById(R.id.tvQuestion);
i = 0;
String data = getAllItems();
tvQuestion.setText(data);
}
private String getAllItems() {
result = "";
for (i = 0; i<9; i++){
result = result + questions.get(i).getQuestion() + "\n";
}
return result;
// TODO Auto-generated method stub
}
The thing is, all these items also have a title(string) and graphical thumb (string) in the database. I would like to show them as illustrated in the picture below, each with an onclicklistener on it, instead of a boring list of items below eachother. Each item has a picture and title.
Since my beginning programming skills, I am wondering how to do this best, and if you know any good tutorials on it which explain it well?
Thanks!
if i understood your question you need to create a customize an adapter.
Create a new simple class like this which holds an string and a picture
Class ObjectHolder {
int Image;
String Title;
}
and create a getter and setter for this two
then create custom ArrayAdapter
Class CustomArrayAdapter extends ArrayAdapter<ObjectHolder> {
public CustomArrayAdapter(Context C, ObjectHolder[] Arr) {
super(C, R.layout.caa_xml, Arr);
}
#Override
public View getView(int position, View v, ViewGroup parent)
{
View mView = v ;
if(mView == null){
LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mView = vi.inflate(R.layout.cpa_xml, null);
}
TextView text = (TextView) mView.findViewById(R.id.tv_caarow);
ImageView image = (ImageView) mView.findViewById(R.id.iv_caarow);
if(mView != null )
{ text.setText(getItem(position).getText());
image.setImageResource(getItem(position).getImage());
return mView;
}
}
and create caa_xml.xml in res\layout\
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/iv_caarow"
android:src="#drawable/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/tv_caarow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="15dip"
android:layout_BottomOf="#+id/iv_caarow" />
</RelativeLayout>
and use it like this.
GridView GV= (GridView) findViewById(R.Id.gv); // reference to xml or create in java
ObjectHolder[] OHA;
// assign your array, any ways!
mAdapter CustomArrayAdapter= CustomArrayAdapter(this, OHA);
GridView.setAdapter(mAdapter);
Hi i've got a custom listview with a text view and a button in each row.
Im having trouble trying to use the buttons . Each button will fire a different intent. This is the xml file for the list view rows.
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout
android:id="#+id/widget28"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<Button
android:id="#+id/widget29"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Remind me"
android:layout_alignParentRight="true"
/>
<TextView android:id="#+id/text12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ff99ccff"
android:text="Text view" />
</RelativeLayout>
Then i have another xml file which simply contains the list view in a linear layout.
This is my custom array class.
public class customArray extends ArrayAdapter<String> {
int resource;
public customArray(Context cont, int _resource, List<String> items) {
super (cont, _resource,items);
resource = _resource;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
RelativeLayout rl;
String prod = getItem(position);
if (convertView == null) {
rl = new RelativeLayout(getContext());
LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vi.inflate(resource, rl, true);
} else {
rl = (RelativeLayout)convertView;
}
TextView t1 = (TextView)rl.findViewById(R.id.text12);
t1.setText(prod);
Button b1 = (Button)rl.findViewById(R.id.widget29);
return rl;
}
}
Then the final class which gets the data from a database and uses the custom adapter to display the information. Does anyone know how i would call each button?
`public class SatMain extends Activity {
/** Called when the activity is first created.
* #param cont */
#Override
public void onCreate(Bundle savedInstanceState)
{
List<String> results = new ArrayList<String>();
super.onCreate(savedInstanceState);
setContentView(R.layout.satmain);
dbAdapter db = new dbAdapter(this);
// button.setOnClickListener(m);
//---get all titles---
db.open();
db.InsertData();
Cursor c = db.getSat1();
if (c.moveToFirst())
{
do {
String pub = c.getString(c.getColumnIndex(db.KEY_Artist));
String pub1 = c.getString(c.getColumnIndex(db.KEY_Time));
results.add(pub + pub1 );
} while (c.moveToNext());
}
db.close();
ListView listProducts;
customArray ca = new customArray(this, R.layout.button, results);
listProducts = (ListView)findViewById(R.id.list1);
listProducts.setAdapter(ca);
ca.notifyDataSetChanged();
}
}`
In the "getView" method of your adapter, you should set an onClick listener for the button. You can do an anonymous class so that you can refer to the contents of the row in the button. I.e, add the following where you get b1 in your example.
b1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//create activity based on prod
}
});