我正在尝试让用户创建一个新的 Flow 对象并将其添加到ArrayList,以便在他们按下工具栏上的"+"
时跟踪它们。
我正在努力解决Java的多线程问题,因为我的方法需要对象及其属性,在对象实例化之前运行会导致各种问题
我希望我的方法能够串行执行(即显示对话框,获取名称,使用对象构造函数,将新对象添加到列表中)这就是为什么我试图在对象上使用Synchronized
动作的原因声明但没有实例化。
此策略似乎无法正常工作,因为锁定的对象不能为null。
java.lang.NullPointerException: Null reference used for synchronization (monitor-enter)
关于如何让我的方法像这个伪代码一样以串行方式运行的任何想法:
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;
}
如果任何其他代码有帮助,请告诉我,我很乐意发布一些代码。如果可能,在你的回答中请提及我在尝试此项时缺乏技术理解的地方。
收到错误:
java.lang.NullPointerException: Attempt to invoke virtual method
'java.lang.String nhacks16.flow.Main.Flow.getFlowName()' on a null object
reference
答案 0 :(得分:1)
当synchronized (newFlow)
仍为newFlow
时,Yoy正在使用null
。您无法在synchronized
引用上使用null
。如果你真的想要同步,请创建一个不同的Object
(任何Object
将会这样做)并在那个上进行同步,或者在this
上进行同步(仅使用synchronized {
不加括号) 。哪一个是正确的,取决于你想要防范什么样的并行性,这让我想到了下一点:
我没有看到任何多线程,所以我不确定,如果你甚至需要同步。
答案 1 :(得分:1)
@mastov完全正确,因为代码中似乎没有任何多线程,而我的newFlow对象是null
。但我只是想在阅读他的评论之后澄清我自己的技术错误,并且我的一位朋友指出了这一点,万一其他人觉得有用!
我的印象是,对话框冻结了所有活动(即方法:addToStream(theFlow);
和executedCorrectly();
将等到flowDialog()
完成后再执行自己)。
因此,因为这些方法似乎在对话框消失之前执行,所以我觉得它们在不同的线程上运行。
nullPointerException的原因是,在用户单击按钮并输入文本之前,对象未实例化。所以一旦设置了flowDialog,下一个方法就会运行,但由于流对象没有实例化,所以它抛出了null异常!