I'm trying to sort an array in alphabetical order (by word string). After I put this line Arrays.sort(word, String.CASE_INSENSITIVE_ORDER);, the other parallel string arrays such as example and flag don't match with word position anymore.
If word string changes its position after it is sorted, the others strings should be linked to it and change their position.
public class MainActivity extends Activity implements
SearchView.OnQueryTextListener {
ListView list;
SearchView mSearchView;
ArrayList<Vocabulary> vocabularylist;
ListViewAdapter adapter;
String[] definition;
String[] word;
String[] example;
int[] flag;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
// Get the view from listview_main.xml
setContentView(R.layout.listview_main);
// Generate sample data into string arrays
word = new String[] { "bimbo",
"heartthrob",
"good-for-nothing"};
definition = new String[] { "loira burra",
"arrasa-corações",
"vagabundo"};
example = new String[] { "She's a real bimbo.",
"He's a real heartthrob.",
"What are you doing wasting time here? Get a job, you good-for-nothing!"};
flag = new int[] { R.drawable.bimbo,
R.drawable.heartthrob,
R.drawable.vagabundo};
**// THE PROBLEM IS HERE**
**Arrays.sort(word, String.CASE_INSENSITIVE_ORDER);**
list = (ListView) findViewById(R.id.listview);
mSearchView = (SearchView) findViewById(R.id.search_view);
vocabularylist = new ArrayList<Vocabulary>();
for (int i = 0; i < word.length; i++) {
Vocabulary vocabulary = new Vocabulary(word[i], definition[i], example[i],
flag[i]);
vocabularylist.add(vocabulary);
}
// Pass results to ListViewAdapter Class
adapter = new ListViewAdapter(getApplicationContext(), vocabularylist, word, definition, example, flag);
// Binds the Adapter to the ListView
list.setAdapter(adapter);
list.setTextFilterEnabled(true);
setupSearchView();
// Capture ListView item click
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Intent i = new Intent(MainActivity.this, SingleItemView.class);
// Pass all data definition
Vocabulary voc = (Vocabulary) adapter.getItem(position);
i.putExtra("definition", voc.getDefinition());
// Pass word
i.putExtra("word", voc.getWord());
// Pass example
i.putExtra("example", voc.getExample());
// Pass flag
i.putExtra("flag", voc.getFlag());
// Pass position
i.putExtra("position", position);
// Open SingleItemView.java Activity
startActivity(i);
}
});
}
private void setupSearchView() {
mSearchView.setIconifiedByDefault(false);
mSearchView.setOnQueryTextListener(this);
mSearchView.setSubmitButtonEnabled(false);
mSearchView.setQueryHint("Pesquise aqui...");
}
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
public boolean onQueryTextSubmit(String query) {
return false;
}
}
You already have an object that stores all the data collectively from the arrays called Vocabulary and your adapter is using a list of those objects that you have already created.
All you need to do is sort the vocabularyList as follows:
Collections.sort(vocabularyList, new Comparator<Vocabulary>() {
#Override
public int compare(Vocabulary lhs, Vocabulary rhs) {
return lhs.getWord().compareToIgnoreCase(rhs.getWord());
}
});
You can add this just before assigning the adapter its value.
adapter = new ListViewAdapter(getApplicationContext(), vocabularylist,
word, definition, example, flag);
Also, the adapter should only need the vocabularyList since that list contains the information from the arrays word, definition, example, and flag. You should remove those from the ListViewAdapter if they are not used in it.
Instead of defining multiple arrays that must be associated in a order after sorting, create a class with all the attributes you need (definition, words ans example ), define ONE list with that object type and sort it by the desired criteria
At the end of the sortime you will get concordance with all the membersame in the list
You need to define a class and implement comparable interface:
public class Data implements Comparable<Data> {
String definition;
String word;
String example;
int flag;
public int compareTo(Data data)
{
return this.word.compareTo(data.word);
}
}
and instead of defining word, example,... define an array of Data:
Data[] dataArray;
and use:
Arrays.sort(dataArray);
now all of the indexes are linked together
Related
I saw all the questions which is similar to my question ( in this , this , this and this link )
I had myAdapter.notifyDataSetChanged() in my Activity but it doesn't work
I have 3 classes,
DBHelper - For storing and getting Database contents ( NO ISSUES HERE )
SimpleRecyclerAdapter - Adapter for RecyclerList
ThirdActivity
What i did in ThirdActivity :
I have TextBox to get data and store it in Database and a Button. In
the Onclicklistener of Button, i specified code to
get text from textbox
add it into table using DBHelper
retrive data as ArrayList from DBHelper
myAdapter.notifyDataSetChanged()
When i click the Button, I got Data in LogCat which i specified inside OnclickListener but it is not reflected to the listview.
Here is my code,
ThirdActivity:
public class ThirdActivity extends AppCompatActivity{
private DrawerLayout mDrawerLayout;
DbHelper dbHelper;
EditText et;
Button addButton;
RecyclerView rv;
ArrayList<String> myNotesList;
SimpleRecycler3Adapter adapter3;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.thirdactivity);
myNotesList = new ArrayList<>();
et=(EditText) findViewById(R.id.et);
addButton=(Button)findViewById(R.id.addButton);
rv = (RecyclerView) findViewById(R.id.dbListrv);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getBaseContext());
rv.setLayoutManager(linearLayoutManager);
rv.setHasFixedSize(true);
adapter3 = new SimpleRecycler3Adapter(myNotesList);
rv.setAdapter(adapter3);
dbHelper = new DbHelper(this, null, null, 1);
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("DB", "Constructor");
String note=et.getText().toString();
dbHelper.addNote(note);
printData();
}
});
}
public void printData(){
Log.d("DB","Constructor");
myNotesList=dbHelper.databasetostring();
Log.d("DB","Data came"+myNotesList.get(myNotesList.size()-1));
// adapter3 = new SimpleRecycler3Adapter(myNotesList);
// rv.setAdapter(adapter3);
adapter3.notifyDataSetChanged();
}
}
SimpleRecyclerViewAdapter :
public class SimpleRecycler3Adapter extends RecyclerView.Adapter<SimpleRecycler3Adapter.NotesHolder> {
private ArrayList<String> myNotesList=new ArrayList<String>();
String TAG="ThirdAdapter kbt";
RecyclerView rv;
public SimpleRecycler3Adapter(ArrayList<String> myList) {
Log.d(TAG,"Constructor");
Log.d(TAG,"Not null");
int i = 0;
while (i < myNotesList.size()) {
myNotesList.add(myList.get(i).toString());
}
Log.d(TAG,"finish");
}
#Override
public NotesHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
Log.d(TAG,"On create started");
View view2 = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recyclerlist3_item, viewGroup, false);
Log.d(TAG,"ADAP STAR ONCR second switch 2nd line");
NotesHolder viewHolder2 = new NotesHolder(view2);
Log.d(TAG,"ADAP STAR ONCR second switch 3nd line");
return viewHolder2;
}
#Override
public void onBindViewHolder(NotesHolder notesHolder, int i) {
Log.d(TAG, "ONBIND SECOND i value is " + i);
// notesHolder.thumbnail.setImageResource(R.drawable.placeholder);
notesHolder.dblistitem.setText(myNotesList.get(i));
Log.d(TAG,"ONBIND second title issssss");
}
#Override
public int getItemCount() {
return myNotesList.size();
}
class NotesHolder extends RecyclerView.ViewHolder {
protected ImageView thumbnail;
protected TextView dblistitem;
public NotesHolder(View itemView) {
super(itemView);
Log.d(TAG, "JSON Inside HOLDER");
rv=(RecyclerView)itemView.findViewById(R.id.dbListrv);
// thumbnail = (ImageView) itemView.findViewById(R.id.thumbnail);
dblistitem = (TextView) itemView.findViewById(R.id.dblistitem);
}
}
}
You're not updating the myNotesList that is in adapter class but in activity class. But the adapter uses it's local myNotesList.
So on button click, update myNotesList of adapter with latest data available and notify the adapter.
EDIT
Pass the latest data to adapter. Have this method in adapter class and call this before notifyDataSetChanged();
public void updateNotes(ArrayList<String> notesList) {
myNotesList = notesList;
}
1.you are intializing your dbhelper after setting adapter to listview so it couldn't contain any data initially
2.for updating recycler view data list do as follows
myNotesList.clear();
myNotesList.addAll(dbHelper.databasetostring());
adapter3.notifyDataSetChanged();
You have a problem in your SimpleRecyclerViewAdapter, just change this:
while (i < myNotesList.size()) {
myNotesList.add(myList.get(i).toString());
}
For this:
myNotesList = myList;
And in your activity's printData() change:
myNotesList=dbHelper.databasetostring();
for this:
myNotesList.clear();
myNotesList.addAll(dbHelper.databasetostring());
adapter3.notifyDataSetChanged();
Explanation:
First you initialize myNotesList variable:
myNotesList = new ArrayList<>();
Then you initialize adapter3
adapter3 = new SimpleRecycler3Adapter(myNotesList);
But your adapter is not saving the reference, instead you're copying its data into another variable:
while (i < myNotesList.size()) {
myNotesList.add(myList.get(i).toString());
}
Doing that, if you change myNotesList variable in your activity will not modify your adapter's dataset.
In your method printData() you change myNotesList variable. Which will not touch your adapter or its data
public void printData(){
Log.d("DB","Constructor");
myNotesList=dbHelper.databasetostring();
Log.d("DB","Data came"+myNotesList.get(myNotesList.size()-1));
// adapter3 = new SimpleRecycler3Adapter(myNotesList);
// rv.setAdapter(adapter3);
adapter3.notifyDataSetChanged();
}
You can't change myNotesList by changing myList.
public SimpleRecycler3Adapter(ArrayList<String> myList) {
Log.d(TAG,"Constructor");
Log.d(TAG,"Not null");
// int i = 0;
// while (i < myNotesList.size()) {
// myNotesList.add(myList.get(i).toString());
// }
this.myNotesList = myList;
Log.d(TAG,"finish");
}
Not a good idea to call notifyDataSetChanged() when you know exactly what changed in your data collection.
See this implementation here.
They have even documented to use notifyDataSetChanged() as a last resort in this doc.
You get nice animations for free if you use methods like notifyItemInserted() and the rest.
Also do not go on replacing the collection object entirely, see the implmentation link that has been attached.
I have a SQLite database in my app for which I made a ContentProvider class.
I also have a RecyclerView into which I load an ArrayList of objects into its adapter to populate the RecyclerView.
Currently, when the activity starts I get a Cursor via my ContentProvider, loop through the Cursor to create an ArrayList of objects that I then set as part of my RecyclerView.Adapter.
All that works, but what I really want is for my RecyclerView to dynamically update as new data is loaded into the SQLite database via the content provider.
I have seen posts listing this library CursorRecyclerAdapter but I do not want to use it because you do not get the nice RecyclerView animations on insert/delete.
I was trying to somehow use the LoaderManager.LoaderCallbacks<Cursor> call back methods to get a cursor, convert to arraylist, then swap that in my RecyclerView adapter but couldn't figure it out.
Could someone please show me some example code on how to set it up in my Activity so that the RecyclerView will refresh when new data is written into the local database via a local content provider?
Here is what my RecyclerView.Adapter looks like:
public class MyAdapter extends RecyclerView.Adapter<AdapterTodoList.Holder> {
private List<TodoItem> itemList;
private Context mContext;
//data
String message;
Long datetime;
//this class takes a context and a list of the items you want to populate into the recycler view
public AdapterTodoList(Context context, List<TodoItem> itemList) {
this.itemList = itemList;
this.mContext = context;
}
#Override
public Holder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
//our xml showing how one row looks
View row = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recycler_view_todo_item, viewGroup, false);
Holder holder = new Holder(row);
return holder;
}
#Override
public void onBindViewHolder(Holder holder, final int position) {
holder.recyclerLinearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(mContext, "Recycle Click" + position, Toast.LENGTH_SHORT).show();
}
});
//get one item
TodoItem data = itemList.get(position);
Log.d("Test", "onBindViewHolder position " + position);
message = data.getMessage();
datetime = data.getDatetime();
//convert long to date
String dateString = new SimpleDateFormat("MM/dd/yyyy").format(new Date(datetime));
//set the holder
holder.messageTextView.setText(message);
}
#Override
public int getItemCount() {
return itemList.size();
}
public class Holder extends RecyclerView.ViewHolder {
protected ImageView checkBoxImageView;
protected TextView messageTextView;
protected LinearLayout recyclerLinearLayout;
public Holder(View view) {
super(view);
//checkBoxImageView = (ImageView) view.findViewById(R.id.checkBoxImageView);
messageTextView = (TextView) view.findViewById(R.id.messageTextView);
//the whole view
recyclerLinearLayout = (LinearLayout) view.findViewById(R.id.recyclerItemLinearLayout);
}
}
}
Here is what my Activity looks like so far:
public class HomeRec extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>{
private Toolbar mToolbar;
//recyclerview and adapter
private RecyclerView mRecyclerView;
private MyAdapter adapter;
//the swipe refresh layout that wraps the recyclerview
private SwipeRefreshLayout mSwipeRefreshLayout;
//this will hold all of our results from our query.
List<TodoItem> itemList = new ArrayList<TodoItem>();
private Cursor mCursor;
//resources from layout
EditText toDoEditText;
Button cancelButton;
Button addButton;
//variables
private String message;
private long datetime;
//loader
private SimpleCursorAdapter mTodoAdapter;
private static final int TODO_LOADER = 0;
// These indices are tied to Projection. If Projection changes, these
// must change.
public static final int COL_ID = 0;
public static final int COL_MESSAGE = 1;
public static final int COL_DATETIME = 2;
public static final int COL_CHECKED = 3;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_rec);
mToolbar = (Toolbar) findViewById(R.id.app_bar);
//set the Toolbar as ActionBar
setSupportActionBar(mToolbar);
// Initialize recycler view //
mRecyclerView = (RecyclerView) findViewById(R.id.todoRecyclerView);
mRecyclerView.hasFixedSize();
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//set a grey line divider for each item in recycler view
mRecyclerView.addItemDecoration(
new DividerItemDecoration(this, null, false, true));
// END Initialize recycler view //
//initiate the swipe to refresh layout
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
// Refresh items
refreshItems();
}
void refreshItems() {
// Load items
// ...
// Load complete
onItemsLoadComplete();
}
void onItemsLoadComplete() {
// Update the adapter and notify data set changed
// ...
// Stop refresh animation
mSwipeRefreshLayout.setRefreshing(false);
}
});
//set colors for swipe to refresh
mSwipeRefreshLayout.setColorSchemeResources(
R.color.refresh_progress_2,
R.color.refresh_progress_3);
//fire my asynctask to get data for the first time
new MessagesAsyncTask().execute();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_home_rec, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
//Not sure what to do here or how to make this work.
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
//Not sure what to do here or how to make this work.
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
//Not sure what to do here or how to make this work.
}
public class MessagesAsyncTask extends AsyncTask<Void, Void, List<TodoItem>> {
//the cursor for the query to content provider
private Cursor mCursor;
#Override
protected void onPreExecute() {
}
#Override
protected List<TodoItem> doInBackground(Void... params) {
// A "projection" defines the columns that will be returned for each row
String[] projection =
{
DataProvider.COL_ID, // Contract class constant for the COL_ID column name
DataProvider.COL_MESSAGE, // Contract class constant for the COL_MESSAGE column name
DataProvider.COL_DATETIME, // Contract class constant for the COL_DATETIME column name
DataProvider.COL_CHECKED // Contract class constant for the COL_CHECKED column name
};
// Defines a string to contain the selection clause
String selectionClause = null;
// An array to contain selection arguments
String[] selectionArgs = null;
// An ORDER BY clause, or null to get results in the default sort order
String sortOrder = DataProvider.COL_DATETIME + " DESC";
// Does a query against the table and returns a Cursor object
mCursor = getContentResolver().query(
DataProvider.CONTENT_URI_TODO, // The content URI of the Todo table
projection, // The columns to return for each row
selectionClause, // Either null, or the word the user entered
selectionArgs, // Either empty, or the string the user entered
sortOrder); // The sort order for the returned rows
// Some providers return null if an error occurs, others throw an exception
if (null == mCursor) {
// Insert code here to handle the error.
} else if (mCursor.getCount() < 1) {
// If the Cursor is empty, the provider found no matches
} else {
// Insert code here to do something with the results
}
//convert cursor to arraylist of objects
while (mCursor.moveToNext()) {
itemList.add(new TodoItem(mCursor.getInt(mCursor.getColumnIndex(DataProvider.COL_ID)),
mCursor.getString(mCursor.getColumnIndex(DataProvider.COL_MESSAGE)),
mCursor.getLong(mCursor.getColumnIndex(DataProvider.COL_DATETIME)),
mCursor.getInt(mCursor.getColumnIndex(DataProvider.COL_CHECKED))
));
}
mCursor.close();
return itemList;
}
#Override
protected void onPostExecute(List<TodoItem> itemList) {
if (!itemList.isEmpty()) {
adapter = new MyAdapter(HomeRec.this, itemList);
mRecyclerView.setAdapter(adapter);
} else {
Toast.makeText(getApplicationContext(), "No data to display", Toast.LENGTH_LONG).show();
}
}
}
}
I m not sure what you need but I think you should add this method To adapter and call once your data was pulled
public void swapItems(List< TodoItem > todolist){
this.mTodoList = todolist;
notifyDataSetChanged();
}
Hope this would help :D
from your question I assume that you are loading the data from the database and somewhere there is a code that is updating the database. And on every update you want to update your RecyclerView, If this is the case continue reading. I am not going to explain this completely but there are a lot of source that will explain you this.
Use BroadcastReciever : In the place where you are updating your database sendBroadcast(). And in the activity use the BroadcastReceiver
example and in the onReceive() function call load the data in your ArrayList and call the adapter.notifyDataSetChanged()
Instead of making new adapter each time in onPostExecute and set it to recyclerview again you can notify adapter after modifying list elements.
OR
If you want to make adapter using arraylist instead of cursoradapter using loader i have made sample for you with data provided by you. You can use this as a reference:
public class DataBaseActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private List itemList;
private MyAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_data_base);
RecyclerView recycle=(RecyclerView)findViewById(R.id.rv_data);
SwipeRefreshLayout swipeRefreshLayout= (SwipeRefreshLayout) findViewById(R.id.srl_data);
recycle.setLayoutManager(new LinearLayoutManager(this));
itemList=new ArrayList();
mAdapter= new MyAdapter(this, itemList);
recycle.setAdapter(mAdapter);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
getContentResolver().notifyChange(DataProvider.CONTENT_URI_TODO, null); //if you are using content provider
//getSupportLoaderManager().restartLoader(100, null, DataBaseActivity.this); // if you are using support lib
//getLoaderManager().restartLoader(100, null, DataBaseActivity.this); //if you are not using support lib
}
});
// getLoaderManager().initLoader(100, null, this); //if you are not using support lib
getSupportLoaderManager().initLoader(100, null, this);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection =
{
DataProvider.COL_ID, // Contract class constant for the COL_ID column name
DataProvider.COL_MESSAGE, // Contract class constant for the COL_MESSAGE column name
DataProvider.COL_DATETIME, // Contract class constant for the COL_DATETIME column name
DataProvider.COL_CHECKED // Contract class constant for the COL_CHECKED column name
};
// Defines a string to contain the selection clause
String selectionClause = null;
// An array to contain selection arguments
String[] selectionArgs = null;
// An ORDER BY clause, or null to get results in the default sort order
String sortOrder = DataProvider.COL_DATETIME + " DESC";
return new CursorLoader(this,DataProvider.CONTENT_URI_TODO, // The content URI of the Todo table
projection, // The columns to return for each row
selectionClause, // Either null, or the word the user entered
selectionArgs, // Either empty, or the string the user entered
sortOrder);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if(data!=null && data.getCount()>0)
{
itemList.clear();
while (data.moveToNext()) {
itemList.add(new TodoItem(data.getInt(data.getColumnIndex(DataProvider.COL_ID)),
data.getString(data.getColumnIndex(DataProvider.COL_MESSAGE)),
data.getLong(data.getColumnIndex(DataProvider.COL_DATETIME)),
data.getInt(data.getColumnIndex(DataProvider.COL_CHECKED))
));
}
}
else
Toast.makeText(getApplicationContext(), "No data to display", Toast.LENGTH_LONG).show();
if(data!=null)
data.close();
mAdapter.notifyDataSetChanged();
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
}
For "listening" to your ContentProvider changes, you'll could try to integrate ContentObserver into your ContentProvider, so it can trigger the necessary events when a transaction is done on your ContentProvider. After which, you'll declare an ContentObserver to your CONTENT_URI, then you can trigger an update to your RecyclerView.
More info on implementing ContentObserver here.
A sample code for updating an item in your RecyclerView would be,
public void update(T data){
synchronized (mLock){
if(data != null && mData.contains(data)){
int index = mData.indexOf(data);
mData.set(index, data);
notifyItemChanged(index);
}
}
}
Wherein T is the type of object if your row returns, mLock is just an instance object to acquire a lock, mData the list of items you've provided to your RecyclerView. You get the gist. :D
Hope it helps.
Refresh cursor every second
final Handler handler = new Handler();
final int delay = 1000; //milliseconds
handler.postDelayed(new Runnable(){
public void run(){
//Call cursor loader to refresh cursor
getSupportLoaderManager().restartLoader(LOADER_ID, null, MainActivity.this);
handler.postDelayed(this, delay);
}
}, delay);
Further to my question "Extracting multiple data items from LinkedList() element" which now works fine on the demo "Book" app thanks to quocnhat7, now I'm stuck on the onItemClick where the method getId() method causes "error: cannot find symbol method getId()" on building the app.
public class MainActivity extends ListActivity implements OnItemClickListener {
JCGSQLiteHelper db = new JCGSQLiteHelper(this);
List list;
ArrayAdapter myAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db.createBook(new Book("The waves", "Virginia Woolf"));
db.createBook(new Book("Mrs Dalloway", "Virginia Woolf"));
db.createBook(new Book("War and Peace", "Leo Tolstoy"));
// get all books
List<Book> list = db.getAllBooks();
List<String> listTitle = new ArrayList<String>();
for (int i = 0; i < list.size(); i++) {
listTitle.add(i, list.get(i).getTitle());
}
myAdapter = new ArrayAdapter(this, R.layout.row_layout, R.id.listText, listTitle);
getListView().setOnItemClickListener(this);
setListAdapter(myAdapter);
}
#Override
public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) {
// start BookActivity with extras the book id
Intent intent = new Intent(this, BookActivity.class);
intent.putExtra("book", list.get(arg2).getId());
startActivityForResult(intent, 1);
}
}
You have 2 problems:
list is defined as non-generic List, thus it's get method returns an Object, and not Book, and Object doesn't have a method getId.
List<Book> list = db.getAllBooks(); hides the member List list, and so there is no assignment to the member list.
To fix it, you should do 2 things:
Change list definition:
public class MainActivity extends ListActivity implements OnItemClickListener {
JCGSQLiteHelper db = new JCGSQLiteHelper(this);
List<Book> list;
// ^^^^^^
Assign to the member, not to a local variable:
// get all Books
list = db.getAllBooks();
i have on my Activity1 a ListView with 10 items. Based on which item i click, i want to pass just a part of a StringArray to my next Activity. I want to bind passed StringArray over an ArrayAdapter to a GridView.
First Problem:
I don´t understand how can i pass something in the next Activity, DEPENDING on the clicked item in the ListView of my Activity1
Second Problem:
How can i get just parts of my StringArray. My String Array has 200 items. Now i want to pass (depending on itemclick in Activity1) just the items i really need.
Here is my code
public class MainActivity extends Activity {
// ListView items
String[] provinces = new String[]{
"Prozentrechnung, Terme und Brüche",
"Gleichungen",
"Ungleichungen und Beträge",
"Geraden, Parabeln und Kreise",
"Trigonometrie",
"Potenzen, Wurzeln und Polynome",
"Exponentialfunktionen und Logarithmen",
"Trigonometrische Funktionen",
"Differenzialrechnung",
"Integralrechnung"
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView provincelist = (ListView)findViewById(R.id.lvProvinceNames);
//add header to listview
LayoutInflater inflater = getLayoutInflater();
ViewGroup header = (ViewGroup)inflater.inflate(R.layout.listheader, provincelist, false);
provincelist.addHeaderView(header, null, false);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, provinces);
provincelist.setAdapter(adapter);
provincelist.setOnItemClickListener(new OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// TODO Auto-generated method stub
//we use the items of the listview as title of the next activity
String province = provinces[position-1];
//we retrieve the description of the juices from an array defined in arrays.xml
String[] provincedescription = getResources().getStringArray(R.array.provincedescription);
//List<String> aufgabenListe = new ArrayList<String>(Arrays.asList(provincedescription));
//final String provincedesclabel = provincedescription[position-1];
Intent intent = new Intent(getApplicationContext(), DetailActivity.class);
intent.putExtra("position",position);
intent.putExtra("province", province); //aktualisieren der Titel in der DetailActivity
intent.putExtra("provincedescription", provincedescription); //befüllen der GridView
startActivity(intent);
}
});
}
}
Here is the Activity2 where i have to bind my items to a GridView.
public class DetailActivity extends Activity {
String title;
String[] array;
int position;
//int image;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.detailactivity);
TextView tvTitleLabel = (TextView)findViewById(R.id.tvTitleLabel);
GridView gridView = (GridView) findViewById(R.id.gridView);
ArrayAdapter<String> adapter;
Bundle extras = getIntent().getExtras();
position = extras.getInt("position");
if (extras != null) {
title = extras.getString("province");
tvTitleLabel.setText(title);
/////Fehlermeldung: array = null --> NullPointerException
array = extras.getStringArray("provincedescription");
gridView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, array));
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
}
});
//adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, array);
//gridView.setAdapter(adapter);
}
}
}
UPDATE: Here is my string array
<string-array name="provincedescription">
<item>A1.1</item>
<item>A1.2</item>
<item>A1.3</item>
<item>A1.4</item>
<item>A1.5</item>
<item>A1.6</item>
<item>A1.7</item>
<item>A1.8</item>
<item>A1.9</item>
<item>A1.10</item>
<item>A1.11</item>
<item>A1.12</item>
<item>A1.13</item>
<item>A1.13</item>
<item>A1.14</item>
<item>A2.1</item>
<item>A2.2</item>
<item>A2.3</item>
<item>A2.4</item>
<item>A2.5</item>
<item>A2.6</item>
<item>A2.7</item>
<item>A2.8</item>
<item>A2.9</item>
<item>A2.10</item>
<item>A2.11</item>
<item>A2.12</item>
<item>A3.1</item>
<item>A3.2</item>
<item>A3.3</item>
<item>A3.4</item>
<item>A3.5</item>
<item>A3.6</item>
<item>A3.7</item>
<item>A3.8</item>
<item>A3.9</item>
<item>A3.10</item>
<item>A3.11</item>
<item>A3.12</item>
</string-array>
if I understand what you want maybe you should take a look at Singleton, I use and works great for now
https://gist.github.com/Akayh/5566992
Credits: https://stackoverflow.com/a/16518088/3714926
For resources like yours that are fixed its better to use string-array in your xml file. From Java I prefer to use static array in your case. Heres a sample:
public class Constants {
public static final String[] provinces = new String[] {
"Prozentrechnung, Terme und Brüche", "Gleichungen",
"Ungleichungen und Beträge", "Geraden, Parabeln und Kreise",
"Trigonometrie", "Potenzen, Wurzeln und Polynome",
"Exponentialfunktionen und Logarithmen",
"Trigonometrische Funktionen", "Differenzialrechnung",
"Integralrechnung" };
}
Then I can access the provinces from anywhere from my class like this:
String iWant = Constants.provinces[0];
Very Important Note
Static objects are dangerous in a number of scenarios and they are usually present in memory so use them sparingly.
As for the string array you cannot get a single element directly from the string-array defined in xml. For that you need to first get all the elements from the array:
Resources res = getResources();
String[] planets = res.getStringArray(R.array.provincedescription);
I am new to Android development and I ran into a problem which I find difficult to solve. I am trying to figure out how to use an AutoCompleteTextView widget properly. I want to create a AutoCompleteTextView, using XML data from a web service. I managed to get it to work, but I am defenitely not pleased with the output.
I would like to put a HashMap with id => name pairs into the AutoCompleteTextView and get the id of the clicked item. When I click on the autocomplete filtered set output, I want to populate a list underneath the autocompletion box, which I also managed to get to work.
Done so far:
autocomplete works well for simple ArrayList, all data filtered
correct
onItemClick event fires properly after click
parent.getItemAtPosition(position) returns correct String
representation of the clicked item
The event onItemClick(AdapterView parent, View v, int position, long id) does not behave as I would like. How can I figure out the unfiltered array position of the clicked item? The position of the filtered one is the one I am not interested in.
Further questions:
How to handle HashMaps or Collections in AutoCompleteTextView
How to get the right itemId in the onItemClick event
I did very extensive research on this issue, but did not find any valuable information which would answer my questions.
The event onItemClick(AdapterView parent, View v, int position, long
id) does not behave as I would like.
This is a normal situation when filtering an adapter. Although the adapter keeps a reference to the initial unfiltered data from its point of view it has a single set of data on which is based(no matter if is the initial one or resulted from a filter operation). But this shouldn't raise any problems. With the default sdk adapters(or with a subclass), in the onItemClick() you get the position for the current list on which the adapter is based. You could then use getItem() to get data item for that position(again it doesn't matter if initial or filtered).
String data = getItem(position);
int realPosition = list.indexOf(data); // if you want to know the unfiltered position
this will work for lists and Maps(assuming that you use the SimpleAdapter). And for a Maps you always have the option of adding an additional key to set the unfiltered position in the initial list.
If you use your own adapter along with an AutoCompleteTextView you could make the onItemClick() give you the right id(the position however you can't change).
public class SpecialAutoComplete extends AutoCompleteTextView {
public SpecialAutoComplete(Context context) {
super(context);
}
#Override
public void onFilterComplete(int count) {
// this will be called when the adapter finished the filter
// operation and it notifies the AutoCompleteTextView
long[] realIds = new long[count]; // this will hold the real ids from our maps
for (int i = 0; i < count; i++) {
final HashMap<String, String> item = (HashMap<String, String>) getAdapter()
.getItem(i);
realIds[i] = Long.valueOf(item.get("id")); // get the ids from the filtered items
}
// update the adapter with the real ids so it has the proper data
((SimpleAdapterExtension) getAdapter()).setRealIds(realIds);
super.onFilterComplete(count);
}
}
and the adapter:
public class SimpleAdapterExtension extends SimpleAdapter {
private List<? extends Map<String, String>> mData;
private long[] mCurrentIds;
public SimpleAdapterExtension(Context context,
List<? extends Map<String, String>> data, int resource,
String[] from, int[] to) {
super(context, data, resource, from, to);
mData = data;
}
#Override
public long getItemId(int position) {
// this will be used to get the id provided to the onItemClick callback
return mCurrentIds[position];
}
#Override
public boolean hasStableIds() {
return true;
}
public void setRealIds(long[] realIds) {
mCurrentIds = realIds;
}
}
If you also implement the Filter class for the adapter then you could get the ids from there without the need to override the AutoCompleTextView class.
Using the Luksprog approach, I made some similar with ArrayAdapter.
public class SimpleAutoCompleteAdapter extends ArrayAdapter<String>{
private String[] mData;
private int[] mCurrentIds;
public SimpleAutoCompleteAdapter(Context context, int textViewResourceId,
String[] objects) {
super(context, textViewResourceId, objects);
mData=objects;
}
#Override
public long getItemId(int position) {
String data = getItem(position);
int index = Arrays.asList(mData).indexOf(data);
/*
* Atention , if your list has more that one same String , you have to improve here
*/
// this will be used to get the id provided to the onItemClick callback
if (index>0)
return (long)mCurrentIds[index];
else return 0;
}
#Override
public boolean hasStableIds() {
return true;
}
public void setRealIds(int[] realIds) {
mCurrentIds = realIds;
}
}
Implement onItemClickListener for AutoCompleteTextView, then use indexOf on your list to find the index of selected item.
actvCity.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
int index = cityNames.indexOf(actvCity.getText().toString());
// Do Whatever you want to do ;)
}
});
First add your data into custom arraylist
// mList used for adding custom data into your model
private List<OutletListSRModel> mList = new ArrayList<>();
// listdata used for adding string data for auto completing.
ArrayList<String> listdata = new ArrayList<String>();
for (int i = 0; i < JArray.length(); i++) {
JSONObject responseJson = JArray.getJSONObject(i);
OutletListSRModel mModel = new OutletListSRModel();
mModel.setId(responseJson.getString("id"));
mModel.name(responseJson.getString("outlet_name"));
listdata.add(responseJson.getString("outlet_name"));
}
ArrayAdapter adapter = new
ArrayAdapter(getActivity(),
android.R.layout.simple_list_item_1, listdata);
searchOutletKey.setAdapter(adapter);
Now for getting any value from model which we added above. we can get like this.
searchOutletKey.setOnItemClickListener ( new AdapterView.OnItemClickListener ( ) {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String txtOutletId = mOutletListSRModel.get(position).getId();
}
});