Android:使用同步

时间:2016-05-04 15:26:51

标签: java android multithreading oop

我正在尝试让用户创建一个新的 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

2 个答案:

答案 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异常!