index list view with database cardview - java

I know there are alot of duplicates with issues like these but pleas do read mine and help me out.
I am very new to Android development as such I coded these with my own instincts and limited guides available.
I'd like to implement an indexable (A-Z) side panel just like in contacts. All the posts available are array strings with hard-coded entries but mine aren't, I am using DB Browser for SQLite and then populate each data in a cardview.
I have referred to (https://github.com/woozzu/IndexableListView/blob/master/src/com/woozzu/android/widget/IndexableListView.java) and tried all the solutions mentioned related to this post but to no avail. I believe I simply coded it the wrong way as the entries are hard-coded but mine aren't.
I am currently following this guide, (http://androidopentutorials.com/android-listview-with-alphabetical-side-index/) and have amended some codes here and there which I thought is necessary for my situation, such as adding my database into an array. However, there are multiple errors and I don't know what to do.
As such, I have no idea how to solve these errors proceed on. Please do help me out and provide me with, perhaps a step-by-step tutorial or even better video guides so that I could follow through.
Below are what I have tried:
Declaration
//indexable list view
Map<String, Integer> mapIndex;
List<String> dbList = new ArrayList<>();
OnCreate
//indexable list view
String[] dbList= database.getKeyword();
Arrays.asList(dbList);
dbList.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_expandable_list_item_1, dbList));
etIndexList(dbList);
displayIndex();
//indexable list view
private void getIndexList(String[] dbList){
mapIndex = new LinkedHashMap<String, Integer>();
for(int i = 0; i < dbList.length; i++){
String db = dbList[i];
String index = db.substring(0,1);
if(mapIndex.get(index) == null)
mapIndex.put(index, i);
}
}
private void displayIndex(){
LinearLayout indexLayout = (LinearLayout) findViewById(R.id.side_index);
TextView textView;
List<String> dbList = new ArrayList<String>(mapIndex.keySet());
for (String index : dbList){
textView = (TextView) getLayoutInflater().inflate(R.layout.side_index_item, null);
textView.setText(index);
textView.setOnClickListener(this);
indexLayout.addView(textView);
}
}
public void onClick(View view){
TextView selectedIndex = (TextView) view;
dbList.setSelection(mapIndex.get(selectedIndex.getText()));
}
The errors are:
If you require any more codes do let me know and I will update this post. Thank you in advance.

follow this lib for indexing list no need to write extra function this lib manage all the case

Answer to the errors that you are getting:
You are calling dbList.setAdapter(): dbList is not a ListView or RecyclerView
Call setAdapter() method on appropriate ListView or RecyclerView variable.
You are passing this to setOnClickListener() method: this is pointing to your KnowledgeActivity and not a View.OnClickListener.
Solution: Either implement View.OnClickListener in your activity or call new OnClickListener like this,
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}});
database.keyword() returns List and you are trying to cast it to String[]

Related

Sub arraylist output repeating itself after n elements

Newbie. I'm coding a quiz app full code on Github that loads an arrayList with four arguments:
question
image (from drawables)
key answer
possible answers presented in a radioGroup (sub-arrayList)
from the strings.xml as below
...
<string name="questionOne">Who is the "Modern Love" rock star singer?</string>
<string name="answerOne">David Bowie</string>
<string-array name="celebrityOne">
<item>Jaimie Hendrix</item>
<item>David Bowie</item>
<item>Jim Morrison</item>
<item>Elvis Presley</item>
</string-array>
...
Below is how the arguments are loaded in MainActivity (The third argument is a sub-arraylist)
ArrayList<Object> arrayList = new ArrayList<>();
loaddata()
...
public void loadData() {
arrayList.add(new Quiz(getResources().getString(R.string.questionOne),
getResources().getDrawable(R.drawable.celebrity_one_image, null),
new ArrayList<>(Arrays.asList(getResources().getStringArray(R.array.celebrityOne))),
getResources().getString(R.string.answerOne)));
arrayList.add(new Quiz(getResources().getString(R.string.questionTwo),
getResources().getDrawable(R.drawable.celebrity_two_image, null),
new ArrayList<>(Arrays.asList(getResources().getStringArray(R.array.celebrityTwo))),
getResources().getString(R.string.answerTwo)));
...
}
The issue is after N iterations, the sub-arrayList starts repeating itself (See image below).
Also I think maybe the source of the problem is in the Adapter, where for each string in sub-array is assigned to a radioButton;
void createRadioButtons(String[] arrayAnswer) {
if (mRadioGroup.getChildAt(0) != null)
return;
for (int i = 0; i < arrayAnswer.length; i++) {
mRadioGroup.addView(createRadioButtonAnswerAndSetOnClickListener(arrayAnswer[i]));
}
}
RadioButton createRadioButtonAnswerAndSetOnClickListener(String string) {
RadioButton radioButton = new RadioButton(mContext);
radioButton.setText(string);
radioButton.setOnClickListener(this);
return radioButton;
}
My situation might be similar to this but I have no static fields and arrayList is initialized as new so no need to clear().
From Documentation:
The RecyclerView creates only as many view holders as are needed to display the on-screen portion of the dynamic content, plus a few extra. As the user scrolls through the list, the RecyclerView takes the off-screen views and rebinds them to the data which is scrolling onto the screen.
This means RecyclerView reuses already created view holders when you are scrolling it(that is why your data repeats), and you must repopulate views with new data. So, instead of returning from createRadioButtons method, when mRadioGroup.getChildAt(0) != null, you must change RadioButtons texts to your new data from arrayAnswer.
in your adapter just change this:
if (mRadioGroup.getChildAt(0) != null)
return;
To this:
if (mRadioGroup.getChildAt(0) != null)
mRadioGroup.removeAllViews();
At some moment your adapter, began to reuse view holders which were created at the top of the recyclerView, but it was already filled with data, so when you call return, you just leave your old data, while you need to delete it and then add new data...

Room query with dynamic values using placeholders

I am implementing a Room database (because I want to move away from Loaders) and I have a query that selects objects based on the IN operator:
#Query(SELECT * FROM table WHERE icon IN(:icons))
LiveData<List<Result>> getResults(String[] icons);
The issue is that the :icons array is generated dynamically during runtime, first I generate placeholders for it and then replace them with the values, like so:
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String[] iconsArray = generateIconArray();
mViewModel = ViewModelProviders.of(this, new MyViewModelFactory(getActivity().getApplication(), iconsArray)).get(MyViewModel.class);
mViewModel.getResults().observe(this, new Observer<List<Result>>() {
#Override
public void onChanged(#Nullable List<Result> results) {
RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), 3);
mRecyclerView.setLayoutManager(layoutManager);
GridAdapter adapter = new GridAdapter(getActivity(), results);
mRecyclerView.setAdapter(adapter);
}
});
}
The problem is that I receive an empty RecyclerView, but when I pass an array with a single icon, the query works normally.
Is it not possible to achieve the same in Room because it checks queries during compile time?
And if not, instead of that should I just use db.query(...) in my repository constructor?
I know this sort of question was asked here, but it also says that they are working on it, and I couldn't find any signs of it.
EDIT:
In case someone stumbles upon this question, I made a small mistake while implementing this feature, the code provided in onActivityCreated actually works. It's also worth mentioning that it works with String[] and lists, but not with a single string: "ab,cd,ef".
I made a small mistake while implementing this feature, the code provided in onActivityCreated actually works. It's also worth mentioning that it works with String[] and List, but not with a single String: "ab,cd,ef", which was my mistake.

Java - adding existing objects to view iterating through an array list

what I want to do is press a button to add previously declared TableRow objects (refers to TableRow objects already created in XML file) that I have hidden using table.removeView(row1) etc on program start.
Then I want to be able to click a button to add each TableRow back to the view one at a time until all the rows are visible again. I have tried a few different ways without any luck and the last method I tried was creating an array list in my onCreate method like so:
final ArrayList<TableRow> rowlist = new ArrayList<TableRow>();
rowlist.add(row4);
rowlist.add(row5);
rowlist.add(row6);
rowlist.add(row7);
rowlist.add(row8);
rowlist.add(row9);
rowlist.add(row10);
Then trying to iterate through like this:
public void onClick(View v) {
Iterator<TableRow> rowiterator = rowlist.iterator();
while (rowiterator.hasNext()) {
table.addView(rowiterator.next());
}
}
What I get now is when I press my button it just adds all the rows back in at once, when I want it to iterate through the list adding rows one at a time.
Can anyone help me resolve this problem, or tell me if I'm being a complete idiot and suggest an entirely new and better method of achieving what I want to achieve?
Note: I'm pretty new to Java programming and on this problem I am absolutely stumped!
You're iterating over the entire array when you click the button and adding them all back in. Something like this is probably more like what you want:
public void onClick(View v) {
if(rowlist.size() > 0)
{
table.addView(rowlist.get(0));
rowlist.remove(0);
}
}

java.lang.ArrayIndexOutOfBoundsException on android input form

I have an input form that has 38 fields
I know it's too much but my boss want it to be like that
There are 4 edit texts and spinners as the rest and 1 imageView that'll be uploaded to server using http client
I use AsyncTask to send the data like this :
new asyncTask().execute(array, array, array);
Because there's too many of items, I think I missed one of them
I've checked many times but I still get the indexOutOfBounds exception
Can you help me find them or give me solution / advice to make simpler code
Here's the code (your eyes might hurt coz it's the whole code) :
http://pastebin.com/0dUss9ak
(it's too much to write here)
Why i'm using alphabets for the variable's name?
If I use name for each of them i'll be dead.
Thanks before
On this line
new KirimData().execute(id_user, nama, lokasi, keterangan, a, b, c, d, e, f, g, h, i, k, l, m, n, o, p, q, ad, bd, cd, dd, ed, fd, gd, hd, id, jd, kd, ld, md, nd, od, pd, qd, savedImagePath);
You seem to be missing parameter j, which will (very probably) cause an exception in
KirimData#doInBackground
To make your code and variables easier to manage, I would highly recommend using HashMaps that use the field names (i.e. a, b, c, etc. in your code) as keys:
HashMap<String, String> fieldValues = new HashMap<String, String>();
HashMap<String, Spinner> fieldSpinners = new HashMap<String, Spinner>();
You could drastically reduce your code replication (and the mistakes like this that code replication brings about) by iterating over the keys in your HashMap and executing the same same logic during each iteration (as opposed to copying/pasting the same lines of code for each field).
Also, I would recommend using more meaningful field names. It might not yield as compact code as you have now, but it will be easier to read and maintain in the long run.
Actually I found a malicious code in onCreate:
File nfile = new File(Environment.getExternalStorageDirectory()+"/Android/data/com.nigmagrid.jm.demo/");
nfile.mkdir();
why you always create directory every time the application start ?
If you want really bad to put that many spinner,
I suggest you should add your spinner on the way which add it programmatically.
- First you may inflating your main layout
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
ViewGroup inflatedLayout = (ViewGroup) inflater.inflate(<your layout xml>, null);
Then put the Spinner content on ArrayAdapter
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
adapter.add("Jembatan 1");
adapter.add("Jembatan 2");
adapter.add("Jembatan 3");
I don't know if every Spinner have a different content.
if they did, you may declare different adapter or create it from a resource.
Then add all spinner that you want:
for(int i=0;i<35;i++){
Spinner s = new Spinner(this);
s.setAdapter(adapter);
s.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
Spinner s = (Spinner) parent;
String selectedItem = (String) s.getSelectedItem();
Toast.makeText(InflateCoba.this, selectedItem, Toast.LENGTH_SHORT).show();
// or you can assign it to a variable
// selectedStr[i] = selectedItem;
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
inflatedLayout.addView(s);
}
set as main View
setContentView(inflatedLayout);
on btn_proses click listener, I suggest you should not create new Object of asyncTask,
declare it in initialization and use the instance that you declare.
HashMap<String, Object> kirimPaket = new HashMap<String, Object>();
kirimPaket.put("nama", nama);
kirimPaket.put("keterangan", keterangan); // and do the rest ..
kirimPaket.put("spinnerItem", selectedStr);
kirim.execute(kirimPaket);
which kirim is an instance of KirimData.
Use HashMap and put your packet on there, it will make it simple.
protected class KirimData extends AsyncTask<HashMap<String, Object>, Void, String>
Actually I don't like the way asyncTask send parameters, Google should do it simple.
then the finalize it
#Override
protected String doInBackground(HashMap<String, Object>... params) {
try{
HttpClient httpClient = CustomHttpClient.getHttpClient();
HttpPost postRequest = new HttpPost(VarsUrl.getServerAddress()+"simpan-inspeksi-jembatan.php");
MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
String nama = params[0].get("nama");
String keterangan = params[0].get("keterangan"); // and do the rest ..
String[] selectedStr = params[0].get("spinnerItem");
reqEntity.addPart("nama", new StringBody(nama));
reqEntity.addPart("keterangan", new StringBody(keterangan)); // and do the rest ..
for(int i=0;i<selectedStr.length;i++){
reqEntity.addPart("item_"+i, new StringBody(selectedStr[i]));
}
....

Populating single ListView with different row layouts

I am attempting to populate a ListView with a column from a database. I can achieve this successfully, but the problem is i would like to use a different layout resource depending on if the id matches a PendingIntent.
This is to check if an alarm exists with the rowid, and i plan to have visual feedback in the listview to show the user which alarms exist. I can successfully check the rowid against PendingIntents and get a return boolean.
The issue I run into is populating the ListView with different layout resources for different rows (is this even possible?) and i have no idea where to go from here.
I currently have the following code:
for(int x = 0; x < numNotes; x++) {
if(existAlarm(intarray[x])){
String[] from = new String[] { TodoDbAdapter.KEY_SUMMARY };
int[] to = new int[] { R.id.label1};
cursor = dbHelper.fetchTodo(intarray[x]);
SimpleCursorAdapter notes = new SimpleCursorAdapter(this,
R.layout.todo_row_green, cursor, from, to);
setListAdapter(notes);
} else if (!existAlarm(intarray[x])){
String[] from = new String[] { TodoDbAdapter.KEY_SUMMARY };
int[] to = new int[] { R.id.label};
cursor = dbHelper.fetchTodo(intarray[x]);
SimpleCursorAdapter notes = new SimpleCursorAdapter(this,
R.layout.todo_row, cursor, from, to);
setListAdapter(notes);
}
}
But the ListView just shows the final database entry from the loop.
I would be very grateful for any guidance, Thanks.
Of course, only the last item will be shown. This is because you keep changing the list adapter each time you enter the loop and execute. Get rid of the loop.
If I understand correctly, you want to display a either a green row or not depending on the ToDo. If so, write your own list adapter which is a subclass of the SimpleCursorAdapter. Then override the newView (Context context, Cursor cursor, ViewGroup parent) method to choose view to use to display the row. The cursor parameter is already moved to the correct position, so you can retrieve values from the DB for any necessary comparisons.
For example: I assume (because of the fetchTodo(intarray[x])) that you are comparing based on the id of the ToDo. In that case your code may look like:
public View newView (Context context, Cursor cursor, ViewGroup parent){
long id = cursor.getLong(TodoDbAdapter.ROW_ID_COLUMN);
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (existAlarm(id)){
return inflater.inflate(R.layout.todo_row_green, null);
} else {
return inflater.inflate(R.layout.todo_row, null);
}
}
I don't know if I understood your code well, but you can adapt this to suit your needs.
Its quite possible to use a different view in each row: you however can't use a standard SimpleCursorAdapter for it: you have to overload the getView() function. An example is at Trying to override getView in a SimpleCursorAdapter gives NullPointerExceptio (there are a couple of errors which are answered in the post, but the basic technique is correct).
As far as showing only the last post, your code is creating a NEW SimpleCursorAdapter for every row, which is incorrect. You want to use the getView() override and then do the for loop and comparison in there.

Categories

Resources