Android: Create new object and manipulate/call new methods serially with Synchronized - java

I am attempting to have a user create a new Flow object and add it to an ArrayList to keep track when they press then "+" on the tool bar.
I am struggling with the multithreading of Java, because my methods that require the object and its properties, are running before the object is instantiated caused all sorts of problems
I want my methods to execute serially (ie. show dialog, get name, use object constructor, add new object to list) which is why I've attempted to use the Synchronized action on an object which I declared but did not instantiate.
This strategy can't seem to work because the object locked onto cannot be null.
java.lang.NullPointerException: Null reference used for synchronization (monitor-enter)
Any thoughts on how I could make my methods run in serial like this pseudo code:
private Flow newFlow; //Blank flow object declared.
private static List<Flow> flowsInStream = new ArrayList<Flow>();
synchronized (newFlow) {
flowDialog();
// presents user a dialog box to receive input.
// takes user input, invokes separate method to actually instantiate
// the newFlow object using the user input.
// Originally blank newFlow object now has:
// newFlow.name = userInput
// --X END X--
addToStream(newFlow);
// adds the newly instantiated newFlow object to the flowsInStream
// array to keep track of them.
// --X END X--
executedCorrectly();
// displays log message showing both the newFlow.name & the current
// elements in the flowsInStream array.
// --X END X--
} // end of synchronized
TheStream.java
public class TheStream extends AppCompatActivity {
private static final String TAG = TheStream.class.getName();
private Toolbar streamToolbar;
private Flow theFlow; //Blank flow object declared.
private static List<Flow> flowsInStream = new ArrayList<Flow>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_the_stream);
streamToolbar = (Toolbar) findViewById(R.id.streamToolbar);
setSupportActionBar(streamToolbar);
}
#Override
public boolean onPrepareOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.menu_thestream, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_settings:
// User chose the "Settings" item, show the app settings UI...
return true;
case R.id.action_newFlow:
flowDialog();
addToStream(theFlow);
executedCorrectly();
return true;
default:
// If we got here, the user's action was not recognized.
// Invoke the superclass to handle it.
return super.onOptionsItemSelected(item);
}
}
public void flowDialog() {
//Creates dialog box asking for name for the new flow
AlertDialog.Builder newFlowDialog = new AlertDialog.Builder(TheStream.this);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
params.setMarginStart(70);
params.setMarginEnd(150);
//Create edit text field for name entry
final EditText nameInputET = new EditText(TheStream.this);
//Sets maximum length of the EditText
nameInputET.setFilters(new InputFilter[]{new InputFilter.LengthFilter(30)});
//Adds the ET and params to the layout of the dialog box
layout.addView(nameInputET, params);
newFlowDialog.setTitle("Name your new Flow.");
newFlowDialog.setIcon(R.drawable.new_flow);
newFlowDialog.setView(layout);
newFlowDialog.setPositiveButton("Lets Roll",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
if (nameInputET.getText().toString().equals("")) {
Toast.makeText(TheStream.this, "Every Flow deserves a good name :(", Toast.LENGTH_LONG).show();
flowDialog(); //Recall the dialog
} else {
// Sets name of flow object
theFlow = instantiateFlow(nameInputET.getText().toString());
}
}
});
newFlowDialog.setNegativeButton("Nevermind",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dialog.dismiss();
}
});
//Display Alert
newFlowDialog.show();
}
protected Flow instantiateFlow(String userInput) {
//Instantiates (Constructor) the newFlow object.
Flow newFlow = new Flow(userInput);
Log.d(TAG, "Your flow's name is " + newFlow.getFlowName());
/** Returns errors attached below */
return newFlow;
}
public void addToStream(Flow flow) {
flowsInStream.add(flow);
}
public void executedCorrectly() {
Log.d(TAG, "The synchronized activity executed correctly because the new Flow object's name is " + theFlow.getFlowName());
Log.d(TAG, "The new Flow list is also updated check it out: " + flowsInStream);
}
}
Flow.java
public class Flow {
private String flowName;
public Flow() {
} // End of default constructor
public Flow(String flowName) {
this.flowName = flowName;
} // End of constructor
/** Getters & Setters **/
public void setFlowName(String flowName) {
this.flowName = flowName;
}
public String getFlowName() {
return this.flowName;
}
If any additional code would help, just let me know and I'd be happy to post some. And if possible in your answer please mention where my technical understanding was lacking in attempting this.
ERROR RECEIVED:
java.lang.NullPointerException: Attempt to invoke virtual method
'java.lang.String nhacks16.flow.Main.Flow.getFlowName()' on a null object
reference

Yoy are using synchronized (newFlow), when newFlow is still null. You can't use synchronized on a null reference. If you really want to synchronize, create a different Object (any Object will do) and synchronize on that one, or synchronize on this (just using synchronized { without parenthesis). Which one is correct, depends on what kind of parallelism you want to guard against, which brings me to the next point:
I don't see any multithreading, so I'm not sure, if you even need synchronization.

#mastov was completely correct in that there doesn't appear to be any multi threading in the code and my newFlow object was null. But I just wanted to clarify what my own technical mistake was after reading his comments and a friend of mine pointed it out, in case someone else finds useful!
I was under the impression that that the dialog box FREEZES all activity (ie. the methods: addToStream(theFlow); and executedCorrectly();will wait until flowDialog()finished before executing themselves).
Thus, because the methods seemed to execute before the dialog was gone, I was under the impression that they were running on different threads.
The reason for the nullPointerException was that the object was not instantiated until user clicked on the button and input text. So once the flowDialog was set up, the next method would run, but because the flow object was not instantiated it threw the null exception!

Related

Linked List not updating values

So I've debugged my program and have found that the part of my program is updating, whilst another isn't.
I have a method:
public void storeApplication(String name, String item){
Application app = new Application(name, item);
peopleAttending.add(app);
}
The debugger reports that an object is contained in the LinkedList (peopleAttending).
In another method:
public void populateListView() {
int noOfPeopleAttending = peopleAttending.size();
String noPeopleAttending = String.valueOf(noOfPeopleAttending);
Toast.makeText(GuestsAttending.this, noPeopleAttending, Toast.LENGTH_SHORT).show();
}
This method can be called after the previous one and states that there isn't an object within the LinkedList.
I've checked the object references just to make sure that they are pointing at the same reference and they are.
Any help would be greatly appreciated.
EDIT: Entire Class:
public class GuestsAttending extends Activity {
private LinkedList<Application> peopleAttending = new LinkedList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_guests_attending);
populateListView();
}
public void storeApplication(String name, String item){
Application app = new Application(name, item);
peopleAttending.add(app);
}
public void populateListView() {
// GuestsAdapter adapter = new GuestsAdapter(this, peopleAttending);
// ListView listView = (ListView) findViewById(R.id.listView);
// listView.setAdapter(adapter);
peopleAttending.size();
int noOfPeopleAttending = peopleAttending.size();
String noPeopleAttending = String.valueOf(noOfPeopleAttending);
Toast.makeText(GuestsAttending.this, noPeopleAttending, Toast.LENGTH_SHORT).show();
}
Second Edit:
Java Booking Screen Method:
public void saveBookingInfo(View view) {
GuestsAttending sendApplication = new GuestsAttending();
EditText applicantNameText = (EditText) findViewById(R.id.applicantNameTextField);
EditText itemToBurnText = (EditText) findViewById(R.id.itemToBurnTextField);
String appName = applicantNameText.getText().toString();
String appItemToBurn = itemToBurnText.getText().toString();
if (appItemToBurn.isEmpty() || appName.isEmpty()) {
Toast.makeText(BookingScreen.this, "Please fill in all fields.", Toast.LENGTH_SHORT).show();
}
else {
sendApplication.storeApplication(appName, appItemToBurn);
}
}
GuestsAttending Java Class: -- See Above.
Useful hint: It's really popular to set type of List as a List<> interface from java.util package instead of LinkedList<> itself.
Anyway, i am pretty sure that storeApplication method is not automatically triggered before onCreate method ran by Activity framework. Maybe your debugger is stopoing on it in different order (because of using threads or smth), but you should to log some invoke. Try to find it out.
I've found out what the problem is:
When I submit the booking information, it runs all the necessary methods. However, when the "storeApplication()" method has finished executing, the ArrayList 'empties' all the objects out.
I only noticed this when I used breakpoint and tried running the method twice, on the second time I entered booking details, the ArrayList stated it was empty.
I'm going to see if I can try and store the ArrayList in a more secure place.

prevent java from multiple openings of the same window-JFrame

for example i create this on click
//this creates autor object with default constructor properties defined in autor class
menuAutor.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e)
{
autor Autor = new autor("Autor");
}
});
so object named Autor is created, and when i click again on the button, it pops up again the same Autor object.. how can prevent opening the same window if one is already opened?
EDIT: FINALY A SOLUTION!
After lots of thinking about this.. i made my solution...
default value for autorOpen="no" i declaired at the beginning of my class, just to let you know because its not visible in code below, the solution itself:
public void mouseClicked(MouseEvent e)
{
if(autorOpen=="no") {
autor Autor = new autor("Autor");
autorOpen = "yes";
Autor.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e)
{
autorOpen = "no";
}
});
}
else
JOptionPane.showMessageDialog(null, "Demo notice... you can't open that window again.. its opened already!","Error",JOptionPane.ERROR_MESSAGE);
}
});
Store the variable a little bit more globally, and check whether it exists before creating a new one.
You could also consider implementing Autor as a singleton class (to ensure only one is ever instantiated).
public class Autor {
private static Autor instance = null;
//Must be protected or private, get a reference to this class with getInstance().
protected Autor() {
}
/**
* Returns reference to this class - use in place of constructor
*/
public static Autor getInstance() {
if(instance == null) {
instance = new Autor();
}
return instance;
}
}
Use a boolean flag to indicate if the dialog is up or not. Set it to true if the dialog is popped up, and set it to false when you close that dialog.
If you're creating something with 'new' on each click, you'll get a new window each time. One solution is to create autor before any clicks happen, then have the event move it from hidden to visible.

How to return a value from a inner class?

My code is here:
public static boolean showConfirmationDialog(Context context, String title, String dialogContent) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setTitle(title);
builder.setMessage(dialogContent);
builder.setPositiveButton("Confirm", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// what to do ?
}
});
right now, I want to return true after I clicked the "confirm" button. so how do I return "true" from a inner class - OnClickListener for the method.
Need some help, thanks.
You can't return things from an inner class in this instance. In this case it doesn't make much sense. Is the program supposed to wait inside your onClick function until it returns something? That's not really how listeners work. What you need to do is take what ever code you plan on executing if "true" was returned, and put it inside your inner class.
OnClickListeners dont return values. Without knowing what exactly you need to do when the click listener fires I cant give you any specifics but
private boolean classBoolean = false;
public static boolean showConfirmationDialog(Context context, String title, String dialogContent) {
//local variables must be declared final to access in an inner anonymous class
final boolean localBoolean = false;
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setTitle(title);
builder.setMessage(dialogContent);
builder.setPositiveButton("Confirm", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// what to do ?
//you can't change a local var since to access it it needs to be final
//localBoolean = true; can't do this
//so you can change a class var
classBoolean = true;
//or you can also call some method to do something
someMethod();
}
});
You either need to set your return on an instance variable (not within a method) - but this may lead to concurrency issues, or use a "container" object. Pass-in, or use a "final" method variable, on which you can set the return value you want to return. However, I use the term "return" loosely, as at least in your example, this code won't immediately execute, so you really need to do the processing you're interested within the inner class instead.
The onClick paradigm doesn't let you return values, it lets you respond to "events" later, so you'll have to rethink your code paradigm a bit.
For followers, in the event that the inner class is "blocking" (i.e. not this case), you can return values using AtomicReference, ex:
AtomicReference<String> returnValue = new AtomicReference<>();
someMethod( new Runnable() { returnValue.set("my inner class value");} );
return returnValue.get();
though better would be (if possible) have someMethod modified so it can return your value out itself (and use something besides Runnable in this instance). GL!
You can do follow simple step:
create a POJO class object inside method.
call setter method by setting return value and use it.
Example:
public void process(){
Contact contact=new Contact();
String selectCount="select * from firmId where id=? for update";
PreparedStatementCreatorFactory pscf = new
PreparedStatementCreatorFactory(selectCount,new int[] {Types.INTEGER});
pscf.setUpdatableResults(true);
pscf.setResultSetType(ResultSet.CONCUR_UPDATABLE);
RowCallbackHandler rch = new RowCallbackHandler() {
#Override
public void processRow(ResultSet resultSet) throws SQLException {
// Here You can set your value
contact.setContactId(incrementCount);
resultSet.updateLong("firmCount",incrementCount);
resultSet.updateRow();
return;
}
};
return contact.getId();
}

Android MapView - Extending OverlayItem to store a URL for access in onTap

[Update: Thanks to Craigy's suggestion below, I cleaned up my code a little and added 'final' before the string in onTap, and everything works great!]
I'm trying to store a URL (along with a title and snippet) in a custom OverlayItem on my app's mapview. When a user taps on the OverlayItem (in my case, a NewsMapItem), I want a dialog to pop up with the title and description. Below that, there are 'Open' and 'Dismiss' buttons. When the user taps the Open button, I'd like to access a URL stored in the NewsMapItem and load that in a WebView.
Please see the relevant code snippets below:
NewsMapItem - where I'd like to add in a link (in addition to the point, title, and snippet provided by the default OverlayItem class).
private class NewsMapItem extends OverlayItem {
private String mLink;
public NewsMapItem(GeoPoint point, String title, String snippet, String mLink) {
super(point, title, snippet);
this.mLink = mLink;
}
public String getLink() {
return mLink;
}
}
onTap override (inside my class extending ItemizedOverlay):
#Override
protected boolean onTap(int index) {
NewsMapItem item = overlays.get(index);
AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
dialog.setTitle(item.getTitle());
dialog.setMessage(item.getSnippet());
// Added the line below...
final String url = item.getLink();
dialog.setCancelable(true);
dialog.setPositiveButton(R.string.mapview_open, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Removed this call...
// String url = item.getLink();
Intent showContent = new Intent(getApplicationContext(), JJGWebViewActivity.class);
showContent.setData(Uri.parse(url));
startActivity(showContent);
}
});
dialog.setNegativeButton(R.string.mapview_dismiss, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
dialog.show();
return true;
}
The item accessors are underlined in red, and Eclipse tells me "Cannot refer to a non-final variable item inside an inner class defined in a different method."
Any help, or is there a better way to do what I'm trying?
For simplicity's sake, I could not display the snippet at all, and store the URL in there, but I'd like to show a title and description in the dialog, so the user can choose whether or not to open a story more easily.
You can only access variables from an inner class in Java if the variables are declared as final (making them constants). More information
Cannot refer to a non-final variable inside an inner class defined in a different method
so try putting final in front of the declaration of the variables it complains about, or use the Eclipse code-complete to do it for you.

How to link classes and menus

I am really struggling with linking menus together. The app I want to create os a collection of menus that leads to url links to various sites I plan to open within the application. I have created a list activity menu with 8 options and I have eight classes with further options. My problem is how to link the menus together.
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// Create an array of Strings, that will be put to our ListActivity
String[] names = new String[] { "P", "Ch", "Le", "Le", "B", "Sk", "Awa", "Tra"};
// Create an ArrayAdapter, that will actually make the Strings above
// appear in the ListView
this.setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_checked, names));
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
// Get the item that was clicked
Object o = this.getListAdapter().getItem(position);
String keyword = o.toString();
Toast.makeText(this, "You selected: " + keyword, Toast.LENGTH_LONG)
.show();
}
}
At the moment all this does is print the selection using the toast method but how do I get it to switch to the p.java class when I have selected it. In basic I would take the names variable and say if names = p goto p.java, I have googled and although I get part of the answer I cannot figure out how to implement it.
Many Thanks In Advance.
I suspect that rather than a class, what you want is an instance of the class in question. One way to do that would be with a Map:
Map<String, Runner> runners = new HashMap<String, Runner>();
runners.put("P", new P());
runners.put("Ch", new Ch());
// etc.
(where Runner is an interface that all your classes implement). Then, inside your onListItemClick() method, where you have the toast:
runners.get(keyword).run();
(where run() is the method you want to launch).
Update (to address your comment)
It's hard to say exactly where to place which bits of code, but based on your question:
You could make runners a field in your Activity, and initialize it in your same onCreate function. So that part's handled.
The Runner interface could be as simple as this (in its own file):
public interface Runner {
public void run();
}
and each of your classes (P, Ch, Le, etc.) would have an implements bit in the constructor:
public class P implements Runner {
And would have to include a run() method (which could simply call whatever existing method you want called for the URL):
public void run() {
// do whatever you want done here
}

Categories