Find List item that populated clicked Table-layout row: - android

I have an activity that contains a TableLayout. I'm populating this table programmaticly by data i have in a list:
what i need to do is to make every row clickable and when it's click I need to find the corresponding item in the list so i can get extra data out of it, this is my onCreate code:
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.reports_list_activity_layout);
application = (SGRaportManagerAppObj)getApplication();
reportsRepository = application.reportsRepository.getReportsRepository();
TableLayout table = (TableLayout) findViewById(R.id.tableReportsList);
table.setStretchAllColumns(true);
table.setShrinkAllColumns(true);
for (Report tempReport : reportsRepository)
{
TableRow row = new TableRow(this);
row.setClickable(true);
TextView tvName = new TextView(this);
tvName.setText(tempReport.getName());
tvName.setGravity(Gravity.CENTER_HORIZONTAL);
tvName.setTextColor(getResources().getColor(R.color.my_black));
row.addView(tvName);
TextView tvPath = new TextView(this);
tvPath.setText(tempReport.getPath());
tvPath.setGravity(Gravity.CENTER_HORIZONTAL);
tvPath.setTextColor(getResources().getColor(R.color.my_black));
row.addView(tvPath);
row.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
Map<String, String> map = new HashMap<String, String>();
map.put(Report.JSON_KEY_ID, );
}
});
table.addView(row);
}
}
so what I need here is when the row is clicked i need to find it in the list and get the ID of the report that was clicked in the table and put into the Map object to pass foreword.
does anyone know how is this can be done?
thanks.

Use a hashtable that maps the content you show in the table row (say Report ID) againsg the Report Object
So something like
Hashtable map = new Hashtable();
...
map.put(report.getId(), report);
onClick on table row, manage to get the report id and in turn look it up this hashtable you are maintaining at a class level or somewhere accessible ..
Edit(code block)
class MyTableRow extends TableRow{
Object report = null;
public MyTableRow(Context context) {
super(context);
}
public Object getReport() {
return report;
}
public void setReport(Object report) {
this.report = report;
}
}
in the onCreate() of your activity, jus use MyTableRow class instead of TableRow like
tableRow = new MyTableRow(this) and use tableRow.setMethod(reportObject) to set the Report. should work..

Related

Weird Behavior about notifyDatasetChanged refreshment

Background
Hi, I am new to Android and trying to get familiar with ListView. So I decide to write a simple program for user to enter quotes and display them in order. I implement a StringAdapter and call the notifyDataSetChanged every time when the user confirms.
Question
The weird thing is that the ListView would sometimes update the oldest quotes and sometimes the newer one. and I don't know the problem.
Please ignore the view data button. In this state, I have entered four quotes:
Quotes: hi - Signature:William Shakespeare
Quotes: hello - Signature:William Shakespeare
Quotes: Virtue is bold and goodness never fearful. - Signature:William Shakespeare
Quotes: Love all, trust a few, do wrong to none. - Signature:William Shakespeare
(in reverse order, meaning in time sequence, it goes 4,3,2,1)
Code
main activity
public class storage extends AppCompatActivity {
// the adapter
private StringAdapter sa;
// the edit text view
public EditText etString,etSignature;
// the list view
public ListView lv;
// the array list to capture the quotes and signature
private ArrayList<String[]> dataString = new ArrayList<String[]>();
// add the string and notify
public void addString(String[] s){
this.dataString.add(0,s);
((BaseAdapter)this.lv.getAdapter()).notifyDataSetChanged();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_storage);
// Link the view elements
this.etString = (EditText) findViewById(R.id.etInput);
this.etSignature = (EditText) findViewById(R.id.etSignature);
this.lv = (ListView) findViewById(R.id.stringList);
Button btn_confirm = (Button) findViewById(R.id.btnConfirm),
btn_viewData = (Button) findViewById(R.id.btnViewData);
// load the adapter
this.sa = new StringAdapter(this,this.dataString);
lv.setAdapter(sa);
btn_confirm.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
storage s = (storage) v.getContext();
// get the String
String sString = s.etString.getText().toString(),
sSignature = s.etSignature.getText().toString();
System.out.println("Quotes: " + sString + "\nSignature:" + sSignature);
// verify it is not empty
if (!sString.isEmpty()&&!sSignature.isEmpty()) {
// add new string and notify
s.addString(new String[]{s.etString.getText().toString(),
s.etSignature.getText().toString()});
((StringAdapter) s.lv.getAdapter()).print_stringData();
// prompt the result
Toast.makeText(s.getBaseContext(),
"Enter Quotes from"+etSignature.getText().toString(),Toast.LENGTH_SHORT).show();
} else {
// prompt the result
Toast.makeText(s.getBaseContext(),
"Please Enter Quotes and Signatures!",Toast.LENGTH_SHORT).show();
}
}
});
}
}
StringAdapter
public class StringAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<String[]> dataStrings = new ArrayList<String[]>();
public StringAdapter(Context c,ArrayList<String[]> dataStrings){this.mContext=c;this.dataStrings=dataStrings;}
public int getCount(){return this.dataStrings.size();}
public Object getItem(int position){ return this.dataStrings.get(position);}
public long getItemId(int postion){ return (long) postion;}
public void print_stringData(){
System.out.println("String Adapter Output:");
for(String [] s: this.dataStrings){
System.out.println("Quotes: "+s[0]+"\nSignature:"+s[1]);
}
}
public View getView(int position, View convertView, ViewGroup parent){
LinearLayout ll;
if(convertView == null){
// set the linear layout
ll = new LinearLayout(this.mContext);
ll.setOrientation(LinearLayout.VERTICAL);
ll.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
// get the data and set the text inside
String[] data = this.dataStrings.get(position);
TextView //tvNo = new TextView(this.mContext),
tvString = new TextView(this.mContext),
tvSignature = new TextView(this.mContext);
ll.addView(tvString);
ll.addView(tvSignature);
tvString.setText(data[0]);
tvString.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
tvSignature.setText(data[1]);
tvSignature.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
tvSignature.setGravity(Gravity.RIGHT);
}
else{
ll = (LinearLayout) convertView;
}
return ll;
}
}
Comments
Some might notice that I add the String[] always to the first element. Actually I have tried to add to the last. The weird behavior still exists.
Environment
Android SDK Version: API 23 lollipop
Emulator Version: Nexus S API 23
Yes, of course, you get that error. Why? Because ListView always re-use convertView in your getView function of Adapter.
Look at your if,else:
else{
ll = (LinearLayout) convertView;
}
return ll;
At this block, you tell the adapter reuse the convertView, but you dont re-set the data. As a result, it will show the data of the previous row.
How to resolve it? just set the data in else block as you do in if one.
P/s: you should learn how to use ViewHolder in ListView to avoid laggy in when scrolling.

How to clear and add new texts to a dynamically created TextView?

I have added a TextView dynamically in a loop. On a button click, I want to clear the existing text in the text view and set some other text to it. How can I do this?
This is my current code:
ArrayList<String> Cheif_ComplaintNew = new ArrayList<String>();
int cc_Arraylist_length = Cheif_ComplaintNew.size();
android.widget.TextView cc_new = new android.widget.TextView(getApplicationContext());
for(int i=0; i<cc_Arraylist_length; i++)
{
cc_new.setId(i);
cc_new.setText(Cheif_ComplaintNew.get(i));
cc_new.setTextColor(getResources().getColor(R.color.black));
cc_new.setTypeface(null,android.graphics.Typeface.ITALIC);
cc_new.setTextSize(14);
cc_linearNew.addView(cc_new);
System.out.println("id"+i);
}
On a button click, the list is cleared and new data is stored in it. I want to display the new data in the same text view by clearing the old one.
You can either add the text to the textbox when you are creating it or assign it a class variable when you create it and later on you can add text to it.
TextView dynamicTextView;
...
private void CreateNewTextView()
{
dynamicTextView = Your New Text View;
}
...
private void ChangeTheText()
{
dynamicTextView.SetText("new value");
}
if you have more than one TextView you can create a class level generic list of TextViews and add them to the list and call them later.
you can also create a map of all TextView so you can call them with their key as well.
I think you can set a tag to cc_new before add it to cc_linearNew, like this: cc_new.setTag(i). when button got click, you can find those TextView by cc_linearNew.findViewByTag(i) in loop, and set new data to them.
Depends on how many TextViews you need to add to the layout dynamically.
As per the code mentioned, no TextViews are added to the layout as: Cheif_ComplaintNew.size() would return "0" so your loop will not be executed.
If you have to add only one TextView, then I agree with Daniel's answer of having a class level TextView variable.
If its multiple TextViews and you know which ID to use then in your Activity you can always get that TextView by calling findViewById("ID_OF_THE_TEXTVIEW_NEEDED")
You can do this in many ways, some of them :
Store your just created ids in array. Then just get your views calling parentView.findViewById(arreyOfIds(0));
Bad for performance do not do this :) - remove all of just added views from your parentView and create them one more time.
To handle back click in Activity use :
#Override
public void onBackPressed()
{
clearTextView();
}
All of this will simple look like this :
private List<Integer> ids = new ArrayList<Integer>();
#Override
public void onBackPressed()
{
clearTextView();
}
private void clearTextView()
{
for(Integer id : ids)
{
TextView view = (TextView)findViewById(id);
view.setText("")
}
}
private void createTextViews()
{
ArrayList<String>Cheif_ComplaintNew = new ArrayList<String> ();
int cc_Arraylist_length=Cheif_ComplaintNew.size();
android.widget.TextView cc_new = new android.widget.TextView(getApplicationContext() );
for(int i=0; i<cc_Arraylist_length; i++)
{
ids.add(i)
cc_new.setId(i);
cc_new.setText(Cheif_ComplaintNew.get(i));
cc_new.setTextColor(getResources().getColor(R.color.black));
cc_new.setTypeface(null,android.graphics.Typeface.ITALIC);
cc_new.setTextSize(14);
cc_linearNew.addView(cc_new);
System.out.println("id"+i);
}
}

Passing the view in onClick to a private class causes the wrong object to be sent

What im trying to do is display a checkbox, a button and a spinner in a TableLayout. The values are obtained from a web service and tableRows are added dynamically to the TableLayout.
The first button creates a dialog with a listview. The listview contains the numbers 1-30. When the user clicks selects a value in the ListView, i need the text of the button to change to the value clicked.
The code works for the first button that is clicked(The first time the listview is opened and a value is selected the text of the button is changed). But the second time i open the list view and select a button, the text of the first button changes and not the one which was clicked. What am i doing wrong?
protected void fillTableView() {
for (MedicineInfo temp : orderedMedList) {
LayoutInflater inflater = getLayoutInflater();
TableRow tr = (TableRow) inflater.inflate(
R.layout.neworderrestockmedicinelist2, tlOrderInfo, false);
CheckBox cbMedicine = (CheckBox) tr
.findViewById(R.id.cbNewOrderRestockMedName);
cbMedicine.setText(temp.vcProduct);
Button btnQty = (Button) tr
.findViewById(R.id.btnNewOrderRestockQty);
Spinner spnIntakeUnit = (Spinner) tr
.findViewById(R.id.spnNewOrderRestockIntakeUnit);
IntakeUnitAdapter intakeUnitAda = new IntakeUnitAdapter(this);
spnIntakeUnit.setAdapter(intakeUnitAda);
ArrayAdapter<String> arrayAda = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, numberArray);
arrayAda.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
tlOrderInfo.addView(tr);
btnQty.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
dlgQty = new Dialog(mContext);
TableRow tr = (TableRow) v.getParent();
ListView lvQty = new ListView(mContext);
QuantityAdapter qtyAda = new QuantityAdapter(mContext);
lvQty.setAdapter(qtyAda);
dlgQty.addContentView(lvQty,
new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
ItemSelectTest test = new ItemSelectTest(tr);
lvQty.setOnItemClickListener(test);
showDialog(DLG_QTY);
test = null;
}
});
}
}
private class ItemSelectTest implements OnItemClickListener {
Button btn = null;
public ItemSelectTest(TableRow tr) {
Button bt = (Button) tr.findViewById(R.id.btnNewOrderRestockQty);
btn = bt;
}
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
btn.setText(String.valueOf(arg3));
}
}
In the same shown above, i'm passing the TableRow that contains the button. I've also tried passing v from onClick. The problem is the same either way..
Thanks
I think that the problem is the way that you're showing the dialog. If you look at the docs for showDialog (here):
Show a dialog managed by this activity. A call to onCreateDialog(int,
Bundle) will be made with the same id the first time this is called
for a given id. From thereafter, the dialog will be automatically
saved and restored.
Presumably you're returning dlgQty in onCreateDialog. The thing is, that dialog will be cached after the first time. A quick fix for this is to always call removeDialog when you are done with it.

Add new LinearLayout on each iteration of Activity

In one of my activities, I create a Linear Layout and some other Widgets when a bundle is received from an Intent. Currently, that Layout is overwrited each time I come back to that Activity. How can I create a new Layout each time without rewriting the code?
CODE:
public class FrontPageActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.frontpage);
Bundle bundle = this.getIntent().getExtras();
try{
String size = bundle.getString("size");
int toppcount = bundle.getStringArrayList("toppings").toArray().length;
LinearLayout container = (LinearLayout)findViewById(R.id.container);
TextView t = new TextView(this);
TextView tprice = new TextView(this);
tprice.setGravity(Gravity.RIGHT);
LinearLayout inner = new LinearLayout(this);
LinearLayout.LayoutParams innerparams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
inner.setLayoutParams(innerparams);
inner.setBackgroundDrawable(getResources().getDrawable(R.drawable.background));
inner.setPadding(10,10,10,10);
if(toppcount == 0){
t.setText(size+" Cheese Pizza");
}
else{
t.setText(size+" "+toppcount+" Topping Pizza");
}
tprice.setText(getPrice(size, toppcount)+"");
tprice.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.FILL_PARENT));
container.addView(inner);
inner.addView(t);
inner.addView(tprice);
}
catch(NullPointerException e){
}
final Intent sender = new Intent(this.getApplicationContext(), OrderPizzaActivity.class);
Button badd = (Button)findViewById(R.id.buttonaddpizza);
badd.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
startActivityForResult(sender, 0);
}
});
}
It sounds like you would need to create a data structure to hold the LinearLayouts, or provide a ViewGroup container for them to be added to each time.
Currently you are creating, modifying, and then overwriting the same LinearLayout in the try{} catch(){} block. Which I would guess to be the reason why it keeps overwriting.
As I understood you add new "options" to the "final order". Every time additional topping added you create a layout and fill it with specific data. And you want it to be aka OrderList. If what this app is about, you can have an application level variable myOrder:List. Add there toppings (topping = new Order()) and read list in FrontPageActivity.
Recommend you to have a separate layout for an order. Looping through orders fill layout with data and inflate in a container of Activity.
Idea in pseudo:
MyApplication extends Application {
private static List<Order> mOrderList = null;
public MyApplication(){
mOrderList = new ArrayList<Order>();
}
public static List<Order> getOrderList(){
return mOrderList();
}
public static void addOrder(Order order) {
mOrderList.add(order);
}
}
options activity:
MyApplication.add(order);
MyApplication.add(order);
FrontPageActivity
foreach(Order order : MyApplication.getOrderList()) {
// fill layout with order data
// inflate orderLayout into container
}

Android TableLayout not Displaying

I've got a class whose content is set to a layout which has a few buttons and a TableLayout.
The real work that makes the TableLayout is in a separate static helper class, which has a method that returns the desired table.
However, the table is not displaying. What humiliatingly simple fact am I missing?
Here is the class whose content is set to the layout:
public class TesterActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TableLayout table = (TableLayout) findViewById(R.id.table);
table = TableHelper.getTable_BINARY_NUMBERS(getApplicationContext(), 5, 25);
}
}
And here is the helper class that creates the Table's meat:
public class TableHelper {
public static TableLayout getTable_BINARY_NUMBERS(Context context, int numRows, int numCols) {
TableLayout table = new TableLayout(context);
table.setStretchAllColumns(true);
table.setShrinkAllColumns(true);
TableRow[] rows = new TableRow[numRows];
for (int row=0; row<numRows; row++) {
rows[row] = new TableRow(context);
for (int col=0; col<numCols-1; col++) {
TextView num = new TextView(context);
num.setText("0");
rows[row].addView(num);
}
TextView rowText = new TextView(context);
rowText.setText("Row " + (row + 1));
rowText.setTextAppearance(context, android.R.style.TextAppearance_Small);
rows[row].addView(rowText);
rows[row].setPadding(0, 50, 0, 0);
table.addView(rows[row]);
}
return table;
}
}
Instead of returning a new table layout, pass the one you get right away to your getTable_BINARY_NUMBERS() and modify it in your method instead of returning a completely new one.
The TableLayout your helper class is returning is not the same as the TableLayout that you are seeing.
when you do setContentView(R.layout.main); an instance of TableLayout is created which you assign to the variable table. The TableLayout coming from your helper class is a different instance.

Categories

Resources