Communicating between two autocompletetextviews - java

I'm fairly new to Android, and I'm using Android Studio for development.
I'm developing an app which communicates with SQL Server and retrieves data to Android and displays them on user request.
I'm currently running into an error. What I'm supposed to do is, there is an AutoCompleteTextView field for which I'm retrieving data and displaying for user selection (say, Organization/Company Names). Now, on selecting an option on this field, I have to send a query with this option (the Organization/Company Name) and retrieve data pertaining to this option from the database (say, the Contact Person Names in the selected Organization/Company) and display this data as options on the second AutoCompleteTextView field.
I did this within the OnCreate method using an ArrayAdapter, but the app kept crashing and now I realized that it's because the values for the second AutoCompleteTextView field are not available during OnCreate.
I need to be able to dynamically change the second AutoCompleteTextView field as and when the value for the first AutoCompleteTextView field is selected.
Any suggestions on how I could overcome this?

No need to try to set the result in the second AutoCompleteTextView inside onCreate(). You can do your task outside and when it's done, you set the values to it.Check out the AsyncTask, it might be so useful.

You can inspired with this code and use that :
txtSearch = (TextView) findViewById(R.id.txtSearch);
txtSearch.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence value, int start, int count, int after) {
if(value.length() > 0){
notes.clear();
cursorS = sql.rawQuery("SELECT CategoryID,Title from WebSite_CategoryDB WHERE ParentID = 0 AND Title LIKE + '" + "%" + value + "%" + "'",null);
try {
if (cursorS != null) {
if (cursorS.moveToFirst()) {
do {
StartActivity_Entity nte = new StartActivity_Entity();
nte._CategoryID = cursorS.getInt(cursorS.getColumnIndex("CategoryID"));
nte._Title = cursorS.getString(cursorS.getColumnIndex("Title"));
notes.add(nte);
} while (cursorS.moveToNext());
}
adapter.notifyDataSetChanged();
}
} catch (Exception e) {
} finally {
cursorS.close();
}
}else if(value.length() == 0){
populateListView();
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
Good look.

Related

ListView: setvisibility() forces refreshing all the rows

I have a ListView with rows with different layouts. So I'm using the pattern of ViewHolder.
If the user clicks on a row, one sub-layout of the same row must be shown/hidden.
viewHolder.btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = (int) v.getTag();
Log.d(TAG, "Line in position " + position + " clicked");
if (!checkBoxSendChoice[position]) {
checkBoxSendChoice[position] = true;
viewHolder.layout_choice.setVisibility(View.VISIBLE);
} else {
checkBoxSendChoice[position] = false;
viewHolder.layout_choice.setVisibility(View.GONE);
}
}
});
However I noticed that the entire ListView is refreshed (getView is called multiple times for all rows), because of setVisibility(). If I comment out the two setVisibility() instructions, the ListView isn't refreshed anymore.
Is it possible to optimize and avoid refreshing all the views in the ListView?
I think there is a better way of doing this. Instead of editing the view directly, you should have a Boolean isVisible inside the list item and change that, then notify the adapter that an item has changed. This will make the holder re-bind to the item. And inside the holder's bind function you can set the view's visibility depends on the boolean. Here is a rough example (half pseudo code):
List<MyItem> items;
viewHolder.btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = (int) v.getTag();
Log.d(TAG, "Line in position " + position + " clicked");
checkBoxSendChoice[position] != checkBoxSendChoice[position];
items.get(position).isVisible = heckBoxSendChoice[position];
adapter.notifyItemRangeChanged(position, 1);
}
});
class MyItem {
boolean isVisible = true;
}
class holder {
View layout_choice;
private void onBind(MyItem item) {
if (item.isVisible) {
layout_choice.setVisibility(View.VISIBLE);
} else {
layout_choice.setVisibility(View. GONE);
}
}
}
By notifying the adapter with notifyItemRangeChanged, the adapter will know what items have been update and therefore will only refresh them.
If you want i'll be happy to edit my answer with a working tested example. Hope this helps!

Cannot getText Because of wrong Id

I have been trying to solve this issue for a while but seems not to work. I am getting a nullPointer Exception on this Line school.setClasses(classesName.getText().toString());in the code block below.
Which is the code that actually posts to the SQLite Database
public void postSchoolSetuptoSQLite() {
school.setSchoolName(nameOfSchool.getText().toString());
school.setSchoolLocation(schoolLocation.getText().toString());
school.setClasses(classesName.getText().toString());
academeaSQL.addSchool(school);
if (demeaSQL != null) {
StringBuilder sb = new StringBuilder();
for (School s : demeaSQL.getAllSchools()) {
sb.append(" SchoolName= " + s.getSchoolName() + " SchoolLocation= " + s.getSchoolLocation()
+ " ClassName= " + s.getClasses());
sb.append("\n");
}
Log.i("Database content", sb.toString());
Toast.makeText(getApplicationContext(), "Added Successfully", Toast.LENGTH_LONG).show();
} else {
Log.i("Database Err", "Database Error");
}
}
I am creating the field for the classesName dynamically by clicking an "Add New Class" Button through this onAddField Method
public void onAddField(View v) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflater.inflate(R.layout.field, null);
rowView.setId(ViewIdGenerator.generateViewId());
// Add the new row before the add field button.
parentLinearLayout.addView(rowView, parentLinearLayout.getChildCount() - 1);
Log.i("ids", String.valueOf(rowView.getId()));
}
The field Id is dynamically generated through the ViewIdGenerator Class.
The Error is at this point classesName = rowView.findViewById(rowView.getId()); when getting the Ids from the dynamically created fields in this code block
public void findByIds() {
rowView = new View(this);
parentLinearLayout = findViewById(R.id.parent_linear_layout);
nameOfSchool = findViewById(R.id.nameOfSchool);
schoolLocation = findViewById(R.id.schoolLocation);
addSchoolAndMoveNext = findViewById(R.id.addSchoolAndMoveNext);
classesName = rowView.findViewById(rowView.getId());
Log.i("Classname", String.valueOf(classesName));
Log.i("SchoolLoca", String.valueOf(schoolLocation));
}
Here is where I am calling the findByIds();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_school_search_setup);
findByIds();
intitializeListeners();
initializeObjects();
}
For the Nullpointer exception. the error is pointing at these areas
school.setClasses(classesName.getText().toString());
and
classesName = rowView.findViewById(rowView.getId());
Please why am I getting the nullpointer exception and How can I resolve it. Thank you. I will really appreciate your responses.
Your problem is that if you are calling findByIds() inside of onCreate() then rowView.getId() will return null, because you are setting the id in the default id generator AFTER the button gets pressed. onCreate() gets called when the activity first starts up.
It also looks like you are trying to add a list of classes when you hit the button. There are built in ways to do this in Android that have a bit more overhead than what you are doing (in terms of time it takes to implement) but that are going to be much more reliable for scrolling, adding new classes, deleting classes, etc.
Look into the recyclerview in order to do this
Inside of the Display Cursor contents in a RecyclerView section here will show you how to add data from the database to the RecyclerView

Getting EditableText from EditText in RecyclerView

I've recycler view with 0 items, I've added an option to manually add the items, my stracture is simple :
RV_Item.xml (contains EditText).
MyItem, which is an Object for RV ( contains private String Text; ).
MainActivity.java, where the stuff happen.
// My List<Object>
List<MyItem> Items = new ArrayList<>();
// For Adding, I've added FAB-Button, When Clicked, it does the following :
Items.add(new MyItem());
CheckForEmptyItems();
mAdapter.notifyItemInserted(0);
Now, When the user click the save button, i want to take all the edittext in all the items he had added, i'm doing in the following way :
for(MyItem items : Items){
Log.i("PrintingInfo", items.getText() );
}
The problem is, i'm not getting the text he entered in all EditText fields, and it's returning Null in all of them, What's the issue in this ?
So, i don't know why always i know the answer after posting, but here's how you gonna know what the user typed :
in your Adapter Class, in onBindViewHolder method, add textlistener for the EditText, here's an example :
holder.MyEditText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
itemList.get(position).setText(s.toString());
}
});
Hope that helps you!

Dynamic List never Loading - Using parse.com

SEE REVISION AT BOTTOM This is a fight card, so it has two people fighting one another, a red vs blue. It has to be a dynamic list that is populated information from parse.com. The first Query is fightOrder. This is a class on Parse.com that has two objectId's on a row. The redCorner and blueCorner find this information in my database (also on parse.com) and display the information accordingly. My problem, is my progressDialog box appears, and it never goes away. My list is never populated. I tried doing it without the dialog box, and populating my list with ever query and had same results.
NOTE: the list is working properly. This is a list I have used successfully before when I would load my information differently. I am just changing the way I load information because I need to have a database of all fighters, and load my fight card from that list.
NOTE: GetCallBack and FindCallBack are asynchronous, that is why this is an odd loop. I have to wait for the done().
Here is the java
public class databaseFightCard extends Activity {
int I;
int size;
private HomeListAdapter HomeListAdapter;
private ArrayList<HomeItem> HomeItemList;
private SeparatedListAdapter adapter;
//this int is to test for main and coMain events. If one is TRUE, It will assign the array position to main or coMain.
int main, coMain;
ParseQuery<ParseObject> blueCorner = ParseQuery.getQuery("FightersDB");
ParseQuery<ParseObject> redCorner = ParseQuery.getQuery("FightersDB");
String name1, name2;
List<String> red = new ArrayList<String>();
List<String> blue = new ArrayList<String>();
private ListView listView;
ProgressDialog progressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_list);
progressDialog = ProgressDialog.show(this, "", "Loading bout...", true);
initialization();
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
HomeItem homeItem = (HomeItem) adapter.getItem(position);
AlertDialog.Builder showFighter = new AlertDialog.Builder(databaseFightCard.this, android.R.style.Theme_DeviceDefault_Dialog);
showFighter.setTitle(homeItem.getHomeItemLeft().toString() + " and " + homeItem.getHomeItemRight().toString());
showFighter.setMessage("166 - 165\nLogan Utah - Richmond Utah");
showFighter.setPositiveButton("DONE", null);
showFighter.setNegativeButton("Cancel", null);
AlertDialog dialog = showFighter.show();
TextView messageView = (TextView) dialog.findViewById(android.R.id.message);
messageView.setGravity(Gravity.CENTER);
Toast.makeText(getBaseContext(), homeItem.getHomeItemLeft().toString() + " " + homeItem.getHomeItemRight().toString(), Toast.LENGTH_LONG).show();
System.out.println("Selected Item : " + homeItem.getHomeItemID());
}
});
HomeListAdapter = new HomeListAdapter(getApplicationContext(), 0, HomeItemList);
//find the fight card, and read the ids
ParseQuery<ParseObject> fightOrder = ParseQuery.getQuery("FightCard");
fightOrder.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> parseObjects, ParseException e) {
if (e == null) {
size = parseObjects.size();
int i = 0;
while (i < size) {
if (parseObjects.get(i).getBoolean("main")) {
main = i;
}
if (parseObjects.get(i).getBoolean("coMain")) {
coMain = i;
}
red.add(i, parseObjects.get(i).getString("redCorner"));
blue.add(i, parseObjects.get(i).getString("blueCorner"));
i++;
}
displayRed();
} else {
e.printStackTrace();
}
}
});
}
private void displayRed() {
adapter = new SeparatedListAdapter(this);
//find one fighter at a time. in the done() method, start the second fighter.
redCorner.getInBackground(red.get(I), new GetCallback<ParseObject>() {
#Override
public void done(ParseObject parseObject, ParseException e) {
if (e == null) {
HomeItemList = new ArrayList<HomeItem>();
HomeItem homeItem = new HomeItem();
homeItem.setHomeItemID(I);
name1 = parseObject.getString("Name");
homeItem.setHomeItemLeft(name1);
HomeItemList.add(homeItem);
if (HomeListAdapter != null) {
if (I == main) {
adapter.addSection(" MAIN EVENT ", HomeListAdapter);
} else if (I == coMain) {
adapter.addSection(" Co-MAIN EVENT ", HomeListAdapter);
} else {
adapter.addSection(" FIGHT CARD ", HomeListAdapter);
}
}
displayBlue();
} else {
e.printStackTrace();
}
I++;
while (I < size){
displayRed();
}
if (size == I) {
listView.setAdapter(adapter);
progressDialog.dismiss();
}
}
});
}
private void displayBlue() {
//find the red fighters then call the dismiss();
blueCorner.getInBackground(blue.get(I), new GetCallback<ParseObject>() {
#Override
public void done(ParseObject parseObject, ParseException e) {
if (e == null) {
HomeItemList = new ArrayList<HomeItem>();
HomeItem homeItem = new HomeItem();
homeItem.setHomeItemID(I);
name2 = parseObject.getString("Name");
homeItem.setHomeItemLeft(name2);
HomeItemList.add(homeItem);
if (HomeListAdapter != null) {
if (I == main) {
adapter.addSection(" MAIN EVENT ", HomeListAdapter);
} else if (I == coMain) {
adapter.addSection(" Co-MAIN EVENT", HomeListAdapter);
} else {
adapter.addSection(" FIGHT CARD ", HomeListAdapter);
}
}
} else {
e.printStackTrace();
}
//if it is done running through all the IDS, set the listView, and dismiss the dialog.
I++;
while (I < size){
displayRed();
}
if (size == I) {
listView.setAdapter(adapter);
progressDialog.dismiss();
}
}
});
}
private void initialization() {
listView = (ListView) findViewById(R.id.Listview);
}
LogCat
java.lang.RuntimeException: This query has an outstanding network
connection. You have to wait until it's done.
That is pointing to this line:
while (I < size){
displayRed();
}
EDIT
I believe that it is the async tasks that are causing this.
On a previous build: I would call for one line item at a time, add it to my list, repeat until finished, then display list.
On the this build: I want to call for redCorner add it to my list, call blueCorner add it to the same line, repeat until finished, then display the list. Here is what it would look like (previous build):
Revised My question is still unanswered. Maybe I need to simplify it. I will have +-20 objectId's from one class. I took out all the code that is irrelevant. Still getting unexpected results with this code.
redCorner.getInBackground(red.get(i), new GetCallback<ParseObject>() {
#Override
public void done(ParseObject parseObject, ParseException e) {
if (e == null) {
Log.d("NAME " + i, name1 + " ");
i++;
while (i < size) {
redCorner.cancel();
displayRed();
}
if (i == size) {
progressDialog.dismiss();
}
} else {
e.printStackTrace();
}
}
});
This is yet another case of not understanding the nature of Async coding (I've seen a lot of questions with the same issue).
In your case you are calling the displayRed() method that fires off some async code, then returns.
Here's how your code might run:
First call to displayRed() (dr1)
(dr1) Async redCorner.getInBackground(..) (async1) started
(dr1) returns
.. some time passes ..
(async1) getInBackground(..) call returns with data, runs code block
calls displayBlue() (db1)
(db1) blueCorner.getInBackground(..) (async2) started
(db1) returns
begins the while loop
calls displayRed() (dr2)
(dr2) Async redCorner.getInBackground(..) (async3) started
(dr2) nothing has touched I yet, tries to start another async redCorner.getInBackgroud(..) (async4)
ERROR
You're writing your code as if the async blocks are running sync instead. Keep in mind that getInBackground means "make a web call to get this data, and when something happens (error or success) run this block of code I'm giving you, possibly on another thread".
Think about the order you want to achieve things, realise that you're asking it to start a process that takes some time, and adjust your code accordingly.

Retrieving data and passing to textview

I'm trying to think of the logic behind how I should do this. The way I am doing it right now is sort of a hack, but it works. It's just too many API requests and unnecessary, so hopefully someone here can help me envision on how I should do this.
I'm using the parse.com SDK for android to retrieve data to display videos.
Here is my code for the video function
int count = 9;
private void getVideos()
{
ParseQuery<ParseObject> query = ParseQuery.getQuery("Videos");
query.whereEqualTo("videoid", count);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> videoData, ParseException e) {
if (e == null) {
/** check to see if there are any more videos **/
if(videoData.size() == 0){
Toast.makeText(getApplicationContext(), "No more videos found.", Toast.LENGTH_LONG).show();
}else{
for(int i=0; i<videoData.size(); i++){
String videoUrl = videoData.get(i).getString("url");
String videoTitle = videoData.get(i).getString("title");
String videoUser = videoData.get(i).getString("user");
TextView title = (TextView)findViewById(R.id.videoTitle);
title.setTextColor(Color.parseColor("#FFFFFF"));
title.setText(videoTitle);
TextView user = (TextView)findViewById(R.id.videoUser);
user.setTextColor(Color.parseColor("#FFFFFF"));
user.setText("By: " + videoUser);
myVideoView = (VideoView) findViewById(R.id.myvideoview);
myVideoView.setVideoPath(vineVideoUrl);
myVideoView.setMediaController(null);
myVideoView.start();
/** loop video **/
myVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
myVideoView.start();
}
});
/** next video **/
Button button= (Button) findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
count++;
Toast.makeText(getApplicationContext(), "Loading...", Toast.LENGTH_LONG).show();
getVideos();
}
});
}
}
} else {
Toast.makeText(getApplicationContext(), "Unable to retrieve videos, please check back later.", Toast.LENGTH_LONG).show();
}
}
});
}
Each time the button is pressed, it increments count, and gets the video for that ID from the API. What I am trying to figure out is how can I retrieve say the latest 20 videos from the API the correct way?
The way I can think the proper way to do it is this:
Get latest 20 videos from API, store in array, then when button is pressed loop thru each. How would I pass them each to the textview? And how should I know when it's the last video (20) and to call the API again and pass back the new results?
You can create a List<String> oldMovies which will hold the ids of the movies you already received, now each time you want bring more movies in your query add this constraint movieQuery.notConteindIn("onjectId", oldMovies). That shall return a list of movies that doesn't have one of the objectsId contained in the oldMovies. Each time you will need to update the oldMovie list of ids.

Categories

Resources