I created a custom SimpleCursorAdapter, because i want a text and 2 buttons per row.
If i click on a button, he should call the Activity Lektion.
In this Lektion he should know from which Button the call came, so i thought about sending the id of the Lektion as a Bundle in the onClickEvent.
But this doesnt work, it just saves me always the last id..
How can i do this?
public class LektionenCursorAdapter extends SimpleCursorAdapter{
private Cursor c;
private Context context;
private Bundle bundle;
public LektionenCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
this.c = c;
this.context = context;
}
public View getView(int pos, View inView, ViewGroup parent){
if(inView == null){
inView = View.inflate(context, R.layout.lektionenoverview_entry, null);
}
View row = inView;
this.c.moveToPosition(pos);
String id = this.c.getString(this.c.getColumnIndex("_id"));
Log.i("Cursor", id);
String description = this.c.getString(this.c.getColumnIndex("Description"));
String info = this.c.getString(this.c.getColumnIndex("Info"));
String test = this.c.getString(this.c.getColumnIndex("Test"));
TextView descriptionTextView = (TextView)row.findViewById(R.id.description);
Button infoButton = (Button)row.findViewById(R.id.infoButton);
Button testButton = (Button)row.findViewById(R.id.testButton);
bundle = new Bundle();
bundle.putString("LektionNummer", id);
descriptionTextView.setText(id+". "+description);
if(info != null && info.length() > 0){
infoButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(context, Lektion.class);
intent.putExtras(bundle);
context.startActivity(intent);
}
});
}
if(test != null && test.length() > 0){
}
return row;
}
}
No need to use a CursorAdapter because you want to show 2 lines and button, you can use any other simpler adapter.
getView method is called multiple times for each view, not when you click on the view or button. You are re-instantiating the Bundle everytime and it is just saving the id for the last getView call (because every call destroys the previous one), and you are also creating a new OnClickListener on every call.
You probably want to use OnItemClickListener and create only one instance outside getView() method.
Related
I have a Cursor Adapter and I want to display a button and a TextView only if the value of a field (accessed from cursor) is between 1 and 4, if not, this views are removed.
So, I created a LayoutFile, with this views, and in CursorAdapter, I check if the field accessed from cursor is between 1 and 4, I remove the Views, otherwise, I add to the Layout:
class Accounts_List_CursorAdapter extends CursorAdapter{
//
Context context;
//
public Accounts_List_CursorAdapter(Context context, Cursor c) {
super(context, c, 0);
this.context = context;
}
#Override
//
//Inflate layout of the rows
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.row_list_accounts_data, parent, false);
}
#Override
//
//Set data and set changes to the row
public void bindView(View view, final Context context, Cursor cursor) {
//
//Find the elements
RelativeLayout relativeLayout = (RelativeLayout) view.findViewById(R.id.layoutRowListAccountsData);
TextView tvAccountsName = (TextView) view.findViewById(R.id.tvAccountsName);
TextView tvAccountsInitValue = (TextView) view.findViewById(R.id.tvAccountsInitValue);
TextView tvAccountsType = (TextView) view.findViewById(R.id.tvAccountsType);
//
//Get data from cursor
final int accountId = cursor.getInt(cursor.getColumnIndexOrThrow(0));
final String accountsName = cursor.getString(cursor.getColumnIndexOrThrow(1));
final String accountsCurrValue = cursor.getString(cursor.getColumnIndexOrThrow(2));
final String accountsInitValue = cursor.getString(cursor.getColumnIndexOrThrow(3));
final String accountsType = cursor.getString(cursor.getColumnIndexOrThrow(4));
//
tvAccountsName.setText(accountsName);
tvAccountsCurrValue.setText("Current Value = " + accountsCurrValue);
//
if ((accountId >= 1) && (accountId <= 4)){
try {
relativeLayout.removeView(view.findViewById(R.id.cmdEditThisAccount));
relativeLayout.removeView(view.findViewById(R.id.tvAccountsInitValue));*
} catch (Exception e) {
e.printStackTrace();
}
}
else{
//
relativeLayout.addView(view.findViewById(R.id.cmdEditThisAccount));
relativeLayout.addView(view.findViewById(R.id.tvAccountsInitValue));
//
tvAccountsInitValue.setText("Init Value = " + accountsInitValue);
//
Button cmdEditThisAccount = (Button) view.findViewById(R.id.cmdEditThisAccount);
cmdEditThisAccount.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(context, UpdateAccount.class);
context.startActivity(intent);
}
});
}
}
}
The problem is: When I run this code, it comes out this message: Java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
What am I doing wrong, or there is another way to hide and show dynamically the TextView and Button from Layout, according with the data returned by cursor?
Thanks in Advance!
Use View.setVisibility(FLAG) i.e. view.findViewById(R.id.cmdEditThisAccount).setVisibility(View.GONE)
api doc
So I have 2 activities.
The first (ActivityOne) displays a listview with data from SQLite cursor, and a button.
On click of that button, I want to add an item to the listview, so I display the second activity (ActivityTwo), that contains a number of editTexts and a save Button, that does the saving in the Database.
But what I want is:
after saving the new item to the DB, the ActivityTwo should close and the ActivityOne should be displayed with the refreshed content from the DB
.
This seems a reasonable workflow. How do I achieve it?
Code for ActivityOne:
public class ActivityOne extends Activity {
private ArrayList<String> idclient = new ArrayList<String>();
private ArrayList<String> numeclient = new ArrayList<String>();
private ArrayList<String> tipclient = new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ListView mylist = (ListView) findViewById(R.id.lv_clienti);
LoadList();
Button btnex = (Button) findViewById(R.id.btnNewCli);
btnex.setOnClickListener(
new View.OnClickListener()
{
public void onClick(View aView)
{
Toast.makeText(getApplicationContext(), "Add new client... " , Toast.LENGTH_SHORT).show();
Intent toAnotherActivity = new Intent(aView.getContext(), NewClientActivity.class);
startActivity(toAnotherActivity);
}
}
);
}
public void LoadList(){
SQLiteDatabase db = new myDbHelper(getApplicationContext()).getWritableDatabase();
Cursor mCursor = db.rawQuery("select idclient,nameclient,typeclient from clienti order by numeclient" , null);
idclient.clear();
numeclient.clear();
tipclient.clear();
if (mCursor.moveToFirst()) {
do {
idclient.add(Integer.toString(mCursor.getInt(0)));
nameclient.add(mCursor.getString(1));
typeclient.add(mCursor.getString(2));
} while (mCursor.moveToNext());
}
DisplayClientiAdapter disadpt = new DisplayClientiAdapter(ClientiActivity.this,idclient,nameclient, typeclient);
ListView lv = (ListView) findViewById(R.id.lv_clienti);
lv.setAdapter(disadpt);
mCursor.close();
db.close();
}
}
And in the ActivityTwo, I have in a button click:
db.execSQL("insert into clients (idclient, nameclient,typeclient,...");
DisplayClientiAdapter da = new DisplayClientiAdapter(getApplicationContext());
da.notifyDataSetChanged();
finish();
Also the displayAdapter is something like:
public class DisplayClientiAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<String> idclient;
private ArrayList<String> numeclient;
private ArrayList<String> tipclient;
public DisplayClientiAdapter(Context c){
this.mContext = c;
}
public DisplayClientiAdapter(Context c, ArrayList<String> idclient, ArrayList<String> numeclient, ArrayList<String> tipclient) {
this.mContext = c;
this.idclient = idclient;
this.numeclient = numeclient;
this.tipclient = tipclient;
}
public int getCount() {
return idclient.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
public View getView(int pos, View child, ViewGroup parent) {
Holder mHolder;
LayoutInflater layoutInflater;
if (child == null) {
layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
child = layoutInflater.inflate(R.layout.clienti_item, null);
mHolder = new Holder();
mHolder.txt_idclient = (TextView) child.findViewById(R.id.tv_cl_id);
mHolder.txt_numeclient = (TextView) child.findViewById(R.id.tv_cl_nume);
mHolder.txt_tipclient = (TextView) child.findViewById(R.id.tv_cl_tip);
child.setTag(mHolder);
} else {
mHolder = (Holder) child.getTag();
}
mHolder.txt_idclient.setText(idclient.get(pos));
mHolder.txt_numeclient.setText(numeclient.get(pos));
mHolder.txt_tipclient.setText(tipclient.get(pos));
return child;
}
public class Holder {
TextView txt_idclient;
TextView txt_numeclient;
TextView txt_tipclient;
}
Of course it does not work like this. The list is not refreshed... I assume it has to do with the displayAdapter !?!?!
I cannot call the LoadList method since it is static or something like that...
Please help.
Thank you
Its not a problem with your adapter. You have to call Loadlist() in onresume method instead of oncreate method in ActivityOne. It will work then.
First of all, have a look at this two articles:
http://www.doubleencore.com/2013/05/layout-inflation-as-intended/
http://www.doubleencore.com/2013/06/context/
You shouldn't inflate your views with null in your inflate method if you have parent view available.
Also, using application context for inflating may cause strange behaviour, as it may not use correct theme you may've set in app manifest for your Activity.
On the other hand - why don't you use CursorAdapter instead of BaseAdapter?
The problem with your adapter is, that you don't set the data in it! :)
///EDIT:
I checked the wrong activity - why do you create second adapter in there?
The easiest solution would be to move the LoadList() to onStart.
If you want to do it right, you should use ContentObserver and (probably) CursorAdapter.
Practicing on the ListView, I thought of adding buttons as well to it, rather than showing only content. But in my implementation, the button does not do anything at all.
Plus I was confused whether I could get the position of the button clicked. For now I am just sending the toSend declared inside the OnItemClick in an intent.
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// TODO Auto-generated method stub
final int toSend = position;
TextView refId = (TextView)view.findViewById(R.id.list_id);
TextView refName = (TextView)view.findViewById(R.id.list_name);
TextView refAdd = (TextView)view.findViewById(R.id.list_address);
Button edit = (Button)view.findViewById(R.id.edit);
edit.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
// TODO Auto-generated method stub
Intent i = new Intent(ListActivity.this, EditLayout.class);
i.putExtra("position", toSend);
startActivity(i);
}
});
String sd_id = refId.getText().toString();
String sd_name = refName.getText().toString();
String sd_add = refAdd.getText().toString();
buildAlert(sd_id, sd_name, sd_add);
}
});
You're pretty close. The "inside" setOnClickListener needs to happen when you create the list row view (the view containing id, name, address, edit).
You can do that during getView(). But where to send the clicks? Instead of creating a new onClickListener, use "this" (your activity). Put an onClick() handler in the activity.
Then, when you get a click, the onClick method will execute. Next problem: how do you know which row clicked? The easiest way that comes to mind is to give the button a different id for e ach row - use the row index (you might need to start at 1 rather than 0 - be warned).
Finally, given the row id, it's easy to start your "nested" activity.
Hope this helps.
(added later)
I do it like this; you'll need to define a layout for your row view:
class MyActivity extends Activity implements View.OnClickListener
{
public void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView (R.layout.my_page);
ListView list = (ListView)findViewById (android.R.id.list);
MyArrayAdapter adapter = new MyArrayAdapter (this, <your array of data>);
list.setAdapter (adapter);
}
#Override
public void onClick(View v)
{
int buttonId = v.getId();
if (buttonId is within range)
... do what you need to do with the click ...
}
private class MyArrayAdapter extends ArrayAdapter<MyData>
{
private Activity act;
//-----------------------------------------------------------------------------
public MyArrayAdapter (Activity act, MyData array)
{
super (act, R.layout.list_row, array);
this.act = act;
}
//-----------------------------------------------------------------------------
#Override
public View getView (int position, View convertView, ViewGroup parent)
{
ViewGroup rowView = (ViewGroup)convertView;
if (rowView == null)
{
LayoutInflater inflater = act.getLayoutInflater();
rowView = (ViewGroup) inflater.inflate (R.layout.list_row,
parent, false);
}
Button button = (Button)rowView.findViewById (R.id.is_member);
button.setId (position+1); // add one to avoid 0 as an id.
button.setOnClickListener (act);
// set field values here -- not shown
return rowView;
}
}
}
My issue today is related to a custom SimpleCursorAdapter I've implemented. Here are my activities onCreate() and the custom SimpleCursorAdapter :
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
customSharedPreference = getSharedPreferences("myCustomSharedPrefs", Activity.MODE_PRIVATE);
editor = customSharedPreference.edit();
setContentView(R.layout.activity_1);
op = new OperationsClass(getApplicationContext());
op.open();
Cursor cursor = op.getList();
startManagingCursor(cursor);
String[] columns = new String[] { "AAA", "BBB", "CCC"};
int[] to = new int[] { R.id.entry_aaa,R.id.entry_bbb, R.id.entry_ccc};
MyCursorAdapter mAdapter = new MyCursorAdapter(this, R.layout.custom_entry, cursor, columns, to);
this.setListAdapter(mAdapter);
op.close();
}
OperationsClass manages a database and the getList() function returns a cursor of the entries.
public class MyCursorAdapter extends SimpleCursorAdapter{
private Context context;
private MyCursorAdapter here = this;
private int layout;
public MyCursorAdapter (Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
this.context = context;
this.layout = layout;
}
#Override
public View newView(final Context context, Cursor cursor, ViewGroup parent) {
Cursor c = getCursor();
final LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(layout, parent, false);
int col1 = c.getColumnIndex("aaa");
String name1 = c.getString(col1 );
int col2 = c.getColumnIndex("bbb");
String name2 = c.getString(col2 );
int col3 = c.getColumnIndex("ccc");
int name3 = c.getInt(col3 );
final TextView text1 = (TextView) v.findViewById(R.id.entry_aaa);
final TextView text2 = (TextView) v.findViewById(R.id.entry_bbb);
final TextView text3 = (TextView) v.findViewById(R.id.entry_ccc);
text1.setText(name);
text2.setText(name2);
if (name3 == 0)
text3.setText("Not checked");
else {
text3.setText("Checked");
text3.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
text3.setText("Not checked");
// Here I would like to update my DB using
// OperationsClass and the SharedPrefs,
// and refresh the ListView with the new
// text value.
}
});
}
}
return v;
}
#Override
public void bindView(View v, final Context context, Cursor c) {
// Same operations as higher
}
}
Basically what I want to achieve is to refresh the ListView when the users clicks on the third column, which means its value changes (has been clicked or has not been). In the same time I wish to update the DB and the SharedPreferences(I could create a new object of both classes and recover from the application context, but that seems pretty heavy).
I also wish to know if there is a way to trigger one of the implemented methods in one activity when an AlertDialog has been opened (in the same app, I actually want to add an element to my database through an AlertDialog and make the Activity that popped it up retrieve a new cursor and refresh its List).
"Basically what I want to achieve is"
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
// if (the id of selected view matches what you want) {
boolean checked;
if (text3.getText().toString() == "checked") {
boolean checked = true;
} else {
boolean checked = false;
}
op.updateRead(id, checked);
refreshCursorAdapter();
setSharedPrefs();
// }
"to refresh the ListView when the users clicks on the 3rd column, which means its value changes (has been clicked or has not been)."
private void refreshCursorAdapter() {
Cursor cursor = op.getList();
mAdapter.changeCursor(cursor);
}
"In the same time I wish to update the DB"
private boolean updateRead(long rowId, boolean checked) {
ContentValues args = new ContentValues();
if (checked) {
args.put("read", "1");
} else {
args.put("read", "0");
}
return db.update(DB_TABLE, args, "_id =" + rowId, null) > 0;
}
"and the SharedPrefereces"
private void setSharedPrefs() {
SharedPreferences settings = getSharedPreferences("MYPREFS", 0);
SharedPreferences.Editor editor = settings.edit();
if (checked) {
editor.putBoolean("read", false);
} else {
editor.putBoolean("read", true);
}
editor.commit();
}
"I also wish to know if there is a way to trigger one of the implemented methods in one activity when an AlertDialog has been opened"
Quite honestly i don't understand what the mystique behind this one is. The process would involve copying and pasting the same code else to some other event.
Basically what I want to achieve is to refresh the ListView when the
users clicks on the 3rd column, which means its value changes (has
been clicked or has not been). In the same time I wish to update the
DB and the SharedPrefereces (I could create a new object of both
classes and recover from the application context, but that seems
pretty heavy).
First of all, you shouldn't be implementing that logic in the newView method because that method will not be called for every row due to the recycling. The newView should be used only to build a new row view and nothing more. Use the bindView method for any row logic.
Regarding the code in the onClick method I don't see where do you have problems. Update the database based on your logic and then query again the database for a Cursor with the new data and then use swapCursor() to update the adapter with the new values. This should work but it's not the recommended way mainly because you're doing every database operation on the main UI thread. Don't use the startManagingCursor method because this method runs the queries on the main UI thread, instead have a look at implementing a Loader in your activity to load data off the main UI thread. With a Loader you'll update the database values and then simply restart the Loader to update the list.
I also wish to know if there is a way to trigger one of the
implemented methods in one activity when an AlertDialog has been
opened (in the same app, I actually want to add an element to my
database through an AlertDialog and make the Activity that poped it up
retrieve a new cursor and refresh its List).
You're not saying anything about how you show that AlertDialog. If you want to update the list after you add the new element then use the listeners for the AlertDialog's buttons and the same code as above.
ok so i have an array adapted listview (the array adapting is done in another class).. i just got the click listener working for the list but now i want set it up so that when i click an item it pulls the strings from the clicked item and piggybacks them on the intent to a new activity.. i figure im supposed to use intent.putextra however im not sure how to pull the correct strings corresponding to the item that i click on.. my code is below.. im simply lost to be honest
//Initialize the ListView
lstTest = (ListView)findViewById(R.id.lstText);
//Initialize the ArrayList
alrts = new ArrayList<Alerts>();
//Initialize the array adapter notice with the listitems.xml layout
arrayAdapter = new AlertsAdapter(this, R.layout.listitems,alrts);
//Set the above adapter as the adapter for the list
lstTest.setAdapter(arrayAdapter);
//Set the click listener for the list
lstTest.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView adapterView, View view, int item, long arg3) {
Intent intent = new Intent(
HomePageActivity.this,
PromotionActivity.class
);
finish();
startActivity(intent);
}
});
my alerts class..
public class Alerts {
public String cityid;
public String promoterid;
public String promoshortcontent;
public String promocontent;
public String promotitle;
public String locationid;
public String cover;
#Override
public String toString() {
return "City: " +cityid+ " Promoter: " +promoterid+ "Short Promotion: " +promoshortcontent+ "Promotion: " +promocontent+ "Title: " +promotitle+ "Location: " +locationid+ "Cover: " +cover+ "$";
}
}
anddddd my alertsadapter class..
public class AlertsAdapter extends ArrayAdapter<Alerts> {
int resource;
String response;
Context context;
//Initialize adapter
public AlertsAdapter(Context context, int resource, List<Alerts> items) {
super(context, resource, items);
this.resource=resource;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
LinearLayout alertView;
//Get the current alert object
Alerts al = getItem(position);
//Inflate the view
if(convertView==null)
{
alertView = new LinearLayout(getContext());
String inflater = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater vi;
vi = (LayoutInflater)getContext().getSystemService(inflater);
vi.inflate(resource, alertView, true);
}
else
{
alertView = (LinearLayout) convertView;
}
//Get the text boxes from the listitem.xml file
TextView textPromo =(TextView)alertView.findViewById(R.id.txtPromo);
TextView textPromoter =(TextView)alertView.findViewById(R.id.txtPromoter);
TextView textLocation =(TextView)alertView.findViewById(R.id.txtLocation);
//Assign the appropriate data from our alert object above
textPromo.setText(al.promocontent);
textPromoter.setText(al.promoterid);
textLocation.setText(al.locationid);
return alertView;
}
}
You need to use the onItemClick event's parameters
a full more readable param enum with param name is
(AdapterView<?> parent, View view, int pos, long id)
that means you have the pos param that indicated the position in the adapter.
What you have to do is:
jump to pos in the adapter
read out the values from the adapter
use putExtra to signup for the intent
had an epiphany over the weekend about how to fix this problem and i finally found a good work around for my app.. i know it isnt optimal because i hard coded the number 100 into it but for my uses as of now i know i wont ever have that many list items..
i added these 2 bits of code to my alertsadapter class
int startzero = 0;
public static String[][] promomatrix = new String[6][100];
and
promomatrix[0][startzero] = al.cityid;
promomatrix[1][startzero] = al.promoterid;
promomatrix[2][startzero] = al.promocontent;
promomatrix[3][startzero] = al.promotitle;
promomatrix[4][startzero] = al.locationid;
promomatrix[5][startzero] = al.cover;
startzero++;
then went to my homepageactivity class and added this to the click listener
Intent intent = new Intent(
HomePageActivity.this,PromotionActivity.class);
intent.putExtra("listitemcity", AlertsAdapter.promomatrix[0][pos]);
intent.putExtra("listitempromoter", AlertsAdapter.promomatrix[1][pos]);
intent.putExtra("listitemcontent", AlertsAdapter.promomatrix[2][pos]);
intent.putExtra("listitemtitle", AlertsAdapter.promomatrix[3][pos]);
intent.putExtra("listitemlocation", AlertsAdapter.promomatrix[4][pos]);
intent.putExtra("listitemcover", AlertsAdapter.promomatrix[5][pos]);
finish();
startActivity(intent);
and finally went to my promotionactivity (where i was trying to send the strings) and added this
Bundle extras = getIntent().getExtras();
if (extras == null){
return;
}
String listitemcity = extras.getString("listitemcity");
String listitempromoter = extras.getString("listitempromoter");
String listitemcontent = extras.getString("listitemcontent");
String listitemtitle = extras.getString("listitemtitle");
String listitemlocation = extras.getString("listitemlocation");
String listitemcover = extras.getString("listitemcover");
worked like a charm.. i hope this helps someone :)