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
Related
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.
I'm doing this code for my android programming school project and I've come into a problem which it seems that the JSON has an error in retrieving some of the data from the API it was to take from.
This is an water intake app I'm working on and I'm using the free API provided by openweathermap.org while referencing the code from http://code.tutsplus.com/tutorials/create-a-weather-app-on-android--cms-21587 . The difference is that instead of using a activity and a fragment, I've combined the fragment and activity together with minor modifications to make it runnable on Eclipse.
Here's my code where it goes wrong:
private void updateWeatherInfo(final String city) {
new Thread(){
public void run(){
final JSONObject json = FetchData.getJSON(MainActivity.this, city);
if(json == null) {
handleWeather.post(new Runnable() {
public void run() {
Toast.makeText(MainActivity.this, R.string.place_not_found, Toast.LENGTH_LONG).show();
}
});
}
else {
handleWeather.post(new Runnable() {
public void run() {
renderWeather(json);
}
});
}
}
}.start();
}
private void renderWeather(JSONObject json) {
try {
cityData.setText(json.getString("name").toUpperCase(Locale.US) + ", " + json.getJSONObject("sys").getString("country"));
JSONObject details = json.getJSONArray("weather").getJSONObject(0);
JSONObject main = json.getJSONObject("main");
detailsData.setText(details.getString("description").toUpperCase(Locale.US) + "\n" + "Humidity: " + main.getString("humidity") + "%" + "\n" + "Pressure: " + main.getString("pressure") + " hPa");
currentTemperatureData.setText(String.format("%.2f", main.getDouble("temp"))+ " ℃");
DateFormat df = DateFormat.getDateTimeInstance();
String updatedOn = df.format(new Date(json.getLong("dt")*1000));
updatedData.setText("Last update: " + updatedOn);
getWeatherIcon(details.getInt("id"), json.getJSONObject("sys").getLong("sunrise") * 1000, json.getJSONObject("sys").getLong("sunset") * 1000);
}
catch(Exception e) {
Log.e("SimpleWeather", "One or more fields not found in the JSON data");
}
}
The exception at the try/catch keeps one happening once it reaches cityData and detailsData. I know this because when I debugged it and reaching there it goes straight to the catch after a few step ins, and with commenting out the cityData the next time it got routed to the catch again was at detailsData.
Could anyone see what's wrong and help me point it out?
EDIT: here's the API im using - http://api.openweathermap.org/data/2.5/weather?q=Singapore,sg
EDIT2: It seems it is because my onCreateView which initialises my textViews was after the updateWeatherData and I've since moved it first before the updateWeatherData was called. Now, however, I realise that my onCreateView has also no #Override, and upon putting in the #Override an error occurs that it must implement a supertype method.
The code is as such:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_main, container, false);
cityData = (TextView)rootView.findViewById(R.id.city_field);
updatedData = (TextView)rootView.findViewById(R.id.updated_field);
detailsData = (TextView)rootView.findViewById(R.id.details_field);
currentTemperatureData = (TextView)rootView.findViewById(R.id.current_temperature_field);
weatherIcon = (TextView)rootView.findViewById(R.id.weather_icon);
weatherIcon.setTypeface(weatherIcons);
return rootView;
}
I understand that this code was meant for a fragment, but implementing it into an Activity it seems I have missed a step in modifying it here. How do I proceed from here?
EDIT3: I have now implemented the onCreateView data into the onCreate , since the onCreateView is the fragment version of onCreate . However, I have run into another problem that is out of this question's scope in that my setTypeface returns a NullPointerException. he code of which can be seen below:
public class MainActivity extends Activity {
TextView cityData;
TextView updatedData;
TextView detailsData;
TextView currentTemperatureData;
TextView weatherIcon;
Typeface weatherIcons;
Handler handleWeather;
public MainActivity() {
handleWeather = new Handler();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
cityData = (TextView) findViewById(R.id.city_field);
updatedData = (TextView) findViewById(R.id.updated_field);
detailsData = (TextView) findViewById(R.id.details_field);
currentTemperatureData = (TextView) findViewById(R.id.current_temperature_field);
weatherIcon = (TextView) findViewById(R.id.weather_icon);
weatherIcons = Typeface.createFromAsset(getAssets(), "weather.ttf");
weatherIcon.setTypeface(weatherIcons);
As such, I will continue my search to this problem for a while, and if I find my answer, I will not post up another question. However, I shall close this question as answered.
I have a listview in my android app which does two functions with the listview itself.
Fist, I can delete an item from the listview.
Second, I can rename something in the listview.
Anytime any of the above happens,
How do I display a different XML layout if the last item on the listview is deleted?
adapter = new SetRowsCustomAdapter(getActivity(), R.layout.customlist, rowsArray);
dataList = (ListView) mFrame3.findViewById(R.id.lvFiles); //lvfiles from xml layout
dataList.setAdapter(adapter);
dataList.setEmptyView(noFilesDisplayed); //not working
Second, once I rename anything within the listview, how do I update the listview to reflect the changes?
adapter.notifyDataSetChanged(); //not working
I have two choices in my ContextMenu, Delete and Rename.
If Delete is chosen, the following code executes:
if (menuItemIndex == 0) {
if (folder.exists()) {
//File flEachFile = new File(folder.toString() + "/" + currentFileName + ".tp");
flEachFile = new File(folder.toString() + "/" + txt + ".tp");
flEachFile2 = new File(folder.toString() + "/." + txt + ".tp");
if (flEachFile.exists()) {
flEachFile.delete();
}
if (flEachFile2.exists()) {
flEachFile2.delete();
}
adapter.remove(adapter.getItem(info.position)); //updated the list
//adapter.notifyDataSetChanged();
dataList.invalidate();
dataList.setEmptyView(noFilesDisplayed);//should display the noFilesDisplayed layout but it's not.
//getActivity().getActionBar().setSelectedNavigationItem(1);
}
}
This works fine as in the list updates itself as I delete a list. So if I have two lists in the view and I delete one the list updates to show one:
adapter.remove(adapter.getItem(info.position)); //updated the list
But if I delete the last item on the list and I want to display another xml layout as in this line:
dataList.setEmptyView(noFilesDisplayed);//should display the noFilesDisplayed layout but it's not.
It doesn't work.
======================================================
If Rename is chosen the following code executes:
if (menuItemIndex == 1) {
// custom dialog
final Dialog dialog = new Dialog(getActivity());
dialog.setContentView(R.layout.renamefile);
dialog.setTitle("Rename Existing Trip");
currTrip = (TextView) dialog.findViewById(R.id.tvCurrentFileName);
currTrip.setText(txt);
etRT = (EditText) dialog.findViewById(R.id.etRenameTo);
Button btnCancel = (Button) dialog.findViewById(R.id.btnCancel);
Button btnApply = (Button) dialog.findViewById(R.id.btnApply);
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
btnApply.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(folder.exists()) {
flEachFile = new File(folder.toString() + "/" + currTrip.getText().toString() + ".tp");
flEachFile2 = new File(folder.toString() + "/." + currTrip.getText().toString() + ".tp");
if (flEachFile.exists()) {
if (etRT.getText().toString().matches("")) {
rTo = (TextView) dialog.findViewById(R.id.tvRenameTo);
rTo.setTextColor(Color.parseColor("#A60000"));
}
else {
File toFile = new File(folder.toString() + "/" + etRT.getText().toString() + ".tp");
flEachFile.renameTo(toFile);
if (flEachFile2.exists()) {
File toFile2 = new File(folder.toString() + "/." + etRT.getText().toString() + ".tp");
flEachFile2.renameTo(toFile2);
}
//adapter.notifyDataSetChanged();
dataList.invalidate();
dialog.dismiss();
//getActivity().getActionBar().setSelectedNavigationItem(1);
}
}
else {
Toast.makeText(getActivity(), "File does not exist", Toast.LENGTH_SHORT).show();
}
}
}
});
// if cancel is clicked, close the custom dialog
btnCancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.show();
}
I can only see the changes if I switch tab and come back to this tab.
It's best to interact with a ListView through its associated adapter, in this case your SetRowCustomAdapter. To remove items you should do adapter.remove(position), which will automatically handle the notifyDataSetChanged() function and internally remove it from whatever data structure it's in. As for renaming something, it depends on how your modeled the data behind the scenes in your adapter. Could you provide some more code for your customer adapter? Are you using an array internally?
UPDATE
Regarding setEmptyView(noFilesDisplayed) not working, is noFilesDisplayed in the same the layout hierarchy where the ListView is? In my experience, which has also been verified by other people, the empty view (in this case noFilesDisplayed) must be in the same layout XML file and, more specifically, must be in the same hierarchy. I personally don't know why it has to be this way, but it seems like that's the only way it works. Here's the example of what I mean...
<ListView
android:id="#+id/list_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<View
android:id="#+id/empty_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone" />
Then in code, you can point noFilesDisplayed to the resource ID empty_view. I'm not entirely sure if setting the visibility to gone is necessary, try playing around with that. I hope that answers your question about the empty view.
call adpater.notifyDataSetChanged(); after you have made changes to your ListView, if notifyDataChanged() is still not working, you can set the adapter and pass the new updated data to the adapter constructor in onResume method. So whenever you delete/rename data in your listView, it will be updated automatically. (This second method will work only if you are starting a new activity for deleting or renaming listView items.)
#Override
protected void onResume() {
super.onResume();
SetRowsCustomAdapter adapter = new SetRowsCustomAdapter(getActivity(), R.layout.customlist, rowsArray);
dataList.setAdapter(adapter);
}
NOTICE: THIS QUESTION HAS BEEN RESOLVED DUE TO ME CATCHING MY OWN STUPIDITY
I want to add a custom class to a LinearLayout, but for some reason I keep getting a NullPointerException.
Here is the method that deals with the addition:
protected void onPostExecute(String results) {
System.out.println("ON POST EXECUTE : " + results);
try {
if(!results.equals(((MessageBlurb)container.getChildAt(0)).getMessage())){
try {
container.removeViewAt(30);
for (int i = 29; i > 0; i--) {
container.addView(container.getChildAt(i-1), i);
container.removeViewAt(i-1);
}
container.addView(new MessageBlurb(getApplicationContext(), results, Color.BLACK), 0);
} catch (NullPointerException e) {
// TODO: handle exception
}
}
}
catch (Exception e) {
MessageBlurb mb = new MessageBlurb(getApplicationContext(), results, Color.BLACK);
mb.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
System.out.println(mb);
container.addView(mb, 0);
}
}
where MessageBlurb extends ViewGroup, because I have a TextView inside the MessageBlurb.
The MessageBlurb class looks like this:
public MessageBlurb(Context context, String message, int color){
super(context);
myTV = new TextView(context);
this.addView(myTV);
myTV.setText(message);
System.out.println("THE BLURB IS CREATED");
this.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
System.out.println("YOU CLIKED THE BLURB");
}
});
}
I printed out the description of mb, and it gives me a memory location. As well as that, the logcat error points to this line:
container.addView(mb, 0);
The container itself is a LinearLayout defined in the activity_main.xml file. It is initialized through the line of code:
container = (LinearLayout)findViewById(R.id.container);
The id of the Layout in the xml file is also called container
Can someone see what I'm doing wrong?
Thanks!
I'm not 100% sure if this is where the problem is, but the following code looks like it's just asking for trouble:
container.removeViewAt(30);
for (int i = 29; i > 0; i--) {
container.addView(container.getChildAt(i-1), i);
container.removeViewAt(i-1);
}
container.addView(new MessageBlurb(getApplicationContext(), results, Color.BLACK), 0);
It looks like you are trying to remove the last view in the container and add a new MessageBlurb at the top. But you don't need to shift all the views down manually like that, simply adding a new view at position 0 will do all that for you. Try replacing it with this:
container.removeViewAt(30);
container.addView(new MessageBlurb(getApplicationContext(), results, Color.BLACK), 0);
Also, do you have a good reason for using getApplicationContext() when creating the message blurb? Your code looks like its part of an AsyncTask class nested inside an Activity class, so you can and should pass the activity itself as the context (i.e. new MessageBlurb(Activity.this, results, Color.BLACK) or something similar).
Hope that helps!
It turns out that I was being a complete idiot. I looked through my onCreate() and found that I had commented out the line:
setContentView(...)
Even so, I want to thank everyone who replied to this thread.
Sorry for all the trouble! :)
is it possible to create a View which is driven by a SimpleCursorAdapter. The content from this view is ever time a entry from DB.
The View (dataView) looks like:
txtData1
txtData2
txtData3
btnPrev btnNext
I read around and tryd to setup this behavior. Hope its make sens:
public class mActivity extends Activity {
public Context me = this;
public SimpleCursorAdapter mAdapter = null;
public Cursor mCursor = null;
private OnClickListener btnStart_onClick = new OnClickListener() {
public void onClick(View v) {
setContentView(R.layout.dataView);
mCursor = mDB.rawQuery("SELECT * FROM Data", null);
startManagingCursor(mCursor);
mAdapter = new SimpleCursorAdapter(
me,
R.layout.dataView,
mCursor,
new String[] {"Data1", "Data2", "Data3"},
new int[] {R.id.txtData1 , R.id.txtData2, R.id.txtData3});
mAdapter.setViewBinder(VIEW_BINDER);
mCursor.moveToFirst();
}
};
static final ViewBinder VIEW_BINDER = new ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex)
{
switch (view.getId())
{
case R.id.txtData1:
TextView txt = (TextView) view;
if (txt != null)
{
int index = cursor.getColumnIndex("Data1");
txt.setText(cursor.getString(index));
}
return true;
case R.id.txtData2:
TextView txt = (TextView) view;
if (txt != null)
{
int index = cursor.getColumnIndex("Data2");
txt.setText(cursor.getString(index));
}
return true;
case R.id.txtData3:
TextView txt = (TextView) view;
if (txt != null)
{
int index = cursor.getColumnIndex("Data3");
txt.setText(cursor.getString(index));
}
return true;
default:
return false;
}
}
};
}
When I run from the btnStart_onClick I dont get Data in my Textboxes :-(
Can somebody help? Can it work like this?
Next question: how can I use the Prev or Next Buttons? Possible this is the only thing I miss to "load" the first data...
EDIT: I extended my example with the global mCursor and the call to mCursor.moveToFirst()
On my app I also tested with the next / prev buttons and the function mCursor.moveToNext() and mCursor.moveToPrevious()
But its not change :-(
As far as I can tell, there are a lot of what I think are conceptual/organizational/syntactical problems with your code. First of all, an adapter is usually exploited by a view such as ListView or Spinner, that gets populated with the data retrieved by the adapter via the cursor (or whatever data structure is backing it). However, I don't see this pattern in your code, and I'm left wondering what use an adapter would have in your case.
Second, you perform a whole SELECT * query in your click listener, i.e. you retrieve all your 1000 records for each click on... well, on what, exactly? You define the click listener, but never set it onto anything - just as you define the adapter, but you don't bind it to anything. The code that sets up the adapter, with the database query and the binder should really be placed outside the listener.
Last, I believe you mocked variable names a bit before posting the code, because in the following snippet:
TextView txt = (TextView) view;
if (txt != null)
{
int index = cursor.getColumnIndex("Data1");
String txt = cursor.getString(index);
txt.setText(txt);
}
I could hardly see how the compiler is intended to distinguish the two txt variables on the last line of the if body.