2016-05-04 6 views
0

ユーザに新しいフローオブジェクトを作成させ、それをArrayListに追加してツールバーの"+"を押したときの経過を追跡しようとしています。Android:新しいオブジェクトを作成し、同期メソッドを使用して新しいメソッドを操作/呼び出しする

オブジェクトがインスタンス化される前に、オブジェクトとそのプロパティを必要とする私の方法は、実行されているので、私は、Javaをマルチスレッドに苦しんでいますが問題

のすべての種類は、私は私の方法は、連続的に(つまり実行したい原因。ダイアログの表示、名前の取得、オブジェクトコンストラクタの使用、リストへの新しいオブジェクトの追加)。これは、私が宣言したがインスタンス化しなかったオブジェクトに対してSynchronizedアクションを使用しようとした理由です。

ロックされたオブジェクトはnullにできないため、この方法は機能していないようです。

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: Null reference used for synchronization (monitor-enter) 

私は私の方法を作ることができる方法上の任意の考えでは、この擬似コードのようなシリアルで実行されます

追加コードがあれば私は助けて、私に知らせて、私はいくつかを投稿することを嬉しく思います。可能であれば、私の技術的な理解が欠けていた箇所を答えてください。受領

ERROR:newFlowはまだnullとき

java.lang.NullPointerException: Attempt to invoke virtual method 
'java.lang.String nhacks16.flow.Main.Flow.getFlowName()' on a null object 
reference 

答えて

1

前年比、synchronized (newFlow)を使用しています。 nullの参照では​​を使用できません。本当に同期したい場合は、別のObject(任意のObjectを作成)を作成し、同期させるか、this(かっこなしのsynchronized {のみ)で同期してください。どちらが正しいかは、どのような並列性を守りたいかによって決まります。

マルチスレッドは表示されません。同期が必要な場合でも、わかりません。

+0

こんにちはmastov、返信いただきありがとうございます。同期を使用しない場合、メソッドをシリアルで実行するにはどうすればよいですか?実行する前に、最初のメソッド(flowDialog)が完了するまで、2つ目のメソッド(addToStream)を待つようにします。 – Rob

+1

@RobertSimoes:マルチスレッドを使用しない場合、何もする必要なしに「シリアルに」実行されます。あなたはマルチスレッドが進行中であると思いますか? – mastov

+0

元々は、同期化されたブロックを使わずにメソッドを次々に入れただけで、ログメッセージを受け取ることになりました。 "新しいFlowオブジェクトの名前が** null **であるため同期化されたアクティビティが正しく実行されました" オブジェクトがflowDialog()でインスタンス化される前に、LogメッセージがnewFlow.nameを取得したことを示します。 – Rob

1

@mastovは、コードにマルチスレッドが含まれていないと表示され、newFlowオブジェクトがnullであるという点で完全に正しいです。しかし、私はちょうど私の自身の技術的な間違いが彼のコメントを読んだ後であることを明らかにするために、私の友人が他の誰かが役に立つと思った場合にそれを指摘しました!

私は、ダイアログボックスがすべてのアクティビティをフリーズしている(つまり、メソッド:addToStream(theFlow);executedCorrectly();は、実行前にflowDialog()が終了するまで待つという印象を受けました)。

このように、ダイアログが消える前にメソッドが実行されているように見えたため、別のスレッドで実行されていたという印象を受けました。

nullPointerExceptionが発生した理由は、オブジェクトではなく、ユーザーがボタンをクリックしてテキストを入力するまでインスタンス化されていないためです。だからflowDialogが設定されたら、次のメソッドが実行されますが、のフローオブジェクトがではないため、null例外がスローされました!

+0

+1ありがとうございます、私はあなたのコードを分析するときに同じことに落ちました! Dialog.show()への非ブロッキング呼び出しは、直感的ではありませんが、IMHOです。 – mastov

関連する問題