質問

I am new to Android development and am using the Android Studio after a short sting with AppInventor.

I have read up on starting an activity and getting the result back as well as examining the examples.

On my MainActivity I have a Login button which starts up the LoginActivity. For the sake of example I am passing an "extra" from the calling activity (MainActivity) to the called activity (LoginActivity) as follows and upon return (it doesn't really login anywhere) it sets two extra parameters that are supposed to be passed back to the MainActivity:

My LoginActivity is a slightly modified version of the template created by the New Activity Wizard. Basically I defined the OUTPARAM static strings (name of extra parameters) and added the code to read the incoming parameter and set the outgoing parameters:

package com.example.testapp.ui;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import android.view.MenuItem;
import android.support.v4.app.NavUtils;

/**
 * Activity which displays a login screen to the user, offering registration as
 * well.
 */
public class LoginActivity extends Activity {
    // DEGT : Activity parameters passed via intent.putExtra
    static public final String INPARAM_METHOD = "com.example.testapp.ui.loginMethod";
    static public final String OUTPARAM_USERID = "com.example.testapp.ui.userId";
    static public final String OUTPARAM_PASSW = "com.example.testapp.ui.password";

    /**
     * A dummy authentication store containing known user names and passwords.
     * TODO: remove after connecting to a real authentication system.
     */
    private static final String[] DUMMY_CREDENTIALS = new String[]{
            "foo@example.com:hello",
            "bar@example.com:world"
    };

    /**
     * The default email to populate the email field with.
     */
    public static final String EXTRA_EMAIL = "com.example.android.authenticatordemo.extra.EMAIL";

    /**
     * Keep track of the login task to ensure we can cancel it if requested.
     */
    private UserLoginTask mAuthTask = null;

    // Values for email and password at the time of the login attempt.
    private String mEmail;
    private String mPassword;

    // UI references.
    private EditText mEmailView;
    private EditText mPasswordView;
    private View mLoginFormView;
    private View mLoginStatusView;
    private TextView mLoginStatusMessageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_login);
        setupActionBar();

        // Set up the login form.
        mEmail = getIntent().getStringExtra(EXTRA_EMAIL);   // TODO modify
        mEmailView = (EditText) findViewById(R.id.email);
        mEmailView.setText(mEmail);

        mPasswordView = (EditText) findViewById(R.id.password);
        mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
                if (id == R.id.login || id == EditorInfo.IME_NULL) {
                    attemptLogin();
                    return true;
                }
                return false;
            }
        });

        mLoginFormView = findViewById(R.id.login_form);
        mLoginStatusView = findViewById(R.id.login_status);
        mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message);

        findViewById(R.id.sign_in_button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                attemptLogin();
            }
        });
    }

    /**
     * Set up the {@link android.app.ActionBar}, if the API is available.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void setupActionBar() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            // Show the Up button in the action bar.
            getActionBar().setDisplayHomeAsUpEnabled(true);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                // This ID represents the Home or Up button. In the case of this
                // activity, the Up button is shown. Use NavUtils to allow users
                // to navigate up one level in the application structure. For
                // more details, see the Navigation pattern on Android Design:
                //
                // http://developer.android.com/design/patterns/navigation.html#up-vs-back
                //
                // TODO: If Settings has multiple levels, Up should navigate up
                // that hierarchy.
                NavUtils.navigateUpFromSameTask(this);
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.login, menu);
        return true;
    }

    /**
     * Attempts to sign in or register the account specified by the login form.
     * If there are form errors (invalid email, missing fields, etc.), the
     * errors are presented and no actual login attempt is made.
     */
    public void attemptLogin() {
        if (mAuthTask != null) {
            return;
        }

        // Reset errors.
        mEmailView.setError(null);
        mPasswordView.setError(null);

        // Store values at the time of the login attempt.
        mEmail = mEmailView.getText().toString();
        mPassword = mPasswordView.getText().toString();

        boolean cancel = false;
        View focusView = null;

        // Check for a valid password.
        if (TextUtils.isEmpty(mPassword)) {
            mPasswordView.setError(getString(R.string.error_field_required));
            focusView = mPasswordView;
            cancel = true;
        } else if (mPassword.length() < 4) {
            mPasswordView.setError(getString(R.string.error_invalid_password));
            focusView = mPasswordView;
            cancel = true;
        }

        // Check for a valid email address.
        if (TextUtils.isEmpty(mEmail)) {
            mEmailView.setError(getString(R.string.error_field_required));
            focusView = mEmailView;
            cancel = true;
        } else if (!mEmail.contains("@")) {
            mEmailView.setError(getString(R.string.error_invalid_email));
            focusView = mEmailView;
            cancel = true;
        }

        if (cancel) {
            // There was an error; don't attempt login and focus the first
            // form field with an error.
            focusView.requestFocus();
        } else {
            // Show a progress spinner, and kick off a background task to
            // perform the user login attempt.
            mLoginStatusMessageView.setText(R.string.login_progress_signing_in);
            showProgress(true);
            mAuthTask = new UserLoginTask();
            mAuthTask.execute((Void) null);
        }
    }

    /**
     * Shows the progress UI and hides the login form.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
    private void showProgress(final boolean show) {
        // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
        // for very easy animations. If available, use these APIs to fade-in
        // the progress spinner.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
            int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);

            mLoginStatusView.setVisibility(View.VISIBLE);
            mLoginStatusView.animate()
                    .setDuration(shortAnimTime)
                    .alpha(show ? 1 : 0)
                    .setListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE);
                        }
                    });

            mLoginFormView.setVisibility(View.VISIBLE);
            mLoginFormView.animate()
                    .setDuration(shortAnimTime)
                    .alpha(show ? 0 : 1)
                    .setListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
                        }
                    });
        } else {
            // The ViewPropertyAnimator APIs are not available, so simply show
            // and hide the relevant UI components.
            mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE);
            mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
        }
    }

    /**
     * Represents an asynchronous login/registration task used to authenticate
     * the user.
     */
    public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
        @Override
        protected Boolean doInBackground(Void... params) {
            // TODO: attempt authentication against a network service.

            try {
                // Simulate network access.
                Thread.sleep(2000);
                // TODO DEGT
                // 1. Use Server setting to select Login Service URL
                // 2. Download list of exhibition rooms to populate spinner on MainActivity


            } catch (InterruptedException e) {
                return false;
            }

            // get the intent extras (parameters passed to activity)
            android.content.Intent intent = getIntent();
            if (intent.getStringExtra(LoginActivity.INPARAM_METHOD).equalsIgnoreCase("manual"))
            {
                for (String credential : DUMMY_CREDENTIALS) {
                    String[] pieces = credential.split(":");
                    if (pieces[0].equals(mEmail)) {
                        // Account exists, return true if the password matches.
                        return pieces[1].equals(mPassword);
                    }
                }
            }


            // TODO: register the new account here.
            return true;
        }

        @Override
        protected void onPostExecute(final Boolean success) {
            mAuthTask = null;
            showProgress(false);

            // get the intent extras passed to the activity by calling activity
            android.content.Intent intent = getIntent();
            if (success) {
                // TO-TEST pass the credentials back to the calling activity
                intent.putExtra(OUTPARAM_USERID, mEmailView.getText());
                intent.putExtra(OUTPARAM_PASSW, mPasswordView.getText());
                setResult(RESULT_OK, intent);   // otherwise it returns RESULT_CANCELED

                    setIntent(intent);
                finish();
            } else {
                // TO-TEST pass the credentials back to the calling activity
                intent.putExtra(OUTPARAM_USERID, "");
                intent.putExtra(OUTPARAM_PASSW, "");
                    setIntent(intent);

                mPasswordView.setError(getString(R.string.error_incorrect_password));
                mPasswordView.requestFocus();
            }
        }

        @Override
        protected void onCancelled() {
            mAuthTask = null;
            showProgress(false);
        }
    }
}

In the UserLoginTask class (defined inside LoginActivity class) I check the input parameter (INPARAM_*) on the doInBackground() method. A debug breakpoint indicates I am getting the correct value set by the MainActivity.

On the onPostExecute() method I am setting both OUTPARAM extras. During debug I confirmed that these values are actually inserted in the Intent's Bundle. However, when control is passed back to the (calling) MainActivity, all the parameters (INPARAM, OUTPARAM) are ABSENT from the passed Intent in the data parameter of the onActivityResult method:

The (calling) MainActivity is as follows:

package com.example.testapp.ui;

import android.os.Bundle;
import android.app.Activity;
import android.provider.ContactsContract;
import android.view.Menu;
import android.widget.Button;   // Button
import android.view.View;       // View
import android.content.Intent;  // Intent
import android.widget.TextView;

public class MainActivity extends Activity {
    static public final int AUTHENTICATE_TICKET = 2;   // Login to server

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Create the Login button onClick to start LoginActivity
        Button button= (Button) findViewById(R.id.buttonLogin);
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                //startActivity(new Intent(MainActivity.this, LoginActivity.class));
                Intent intent = new Intent(MainActivity.this, LoginActivity.class);
                intent.putExtra(LoginActivity.INPARAM_METHOD, "manual"); // DEGT dummy for now
                startActivityForResult(intent, AUTHENTICATE_TICKET);

            }
        });
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);

        return true;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        // Check which request we're responding to
        if (requestCode == AUTHENTICATE_TICKET)
        {   // Successful LoginActivity result.
            if (resultCode == RESULT_OK)
            {
                // Get a reference to the TextView we will update
                final TextView txtMainMessage = (TextView)findViewById(R.id.textViewMainMessage);
                // Update the TextView with a personalized message. TODO Localize

                String userId = data.getExtras().getString(LoginActivity.OUTPARAM_USERID);
                String msg = "Hello " + userId + ". Now select the exhibition room please.";
                txtMainMessage.setText(msg);
            }
        }
    }
}
役に立ちましたか?

解決

The keys must match. Don't use static string as key. When your call finish() in onPostExecute() you activity is destroyed. So the static fields may be garbage collected. Hence won't match. I am not sure but a guess.

In your onPostExecute()

  Intent intent = getIntent();
  if (success) 
  {
      Toast.makeText(LoginActivity.this, mEmailView.getText(),1000).show();
      intent.putExtra("key",mEmailView.getText().toString());
      // intent.putExtra(OUTPARAM_PASSW, mPasswordView.getText());
      setResult(RESULT_OK, intent);   // otherwise it returns RESULT_CANCELED
      finish();
  }

In your onActivityResult

   final TextView txtMainMessage = (TextView)findViewById(R.id.textView1);
            // Update the TextView with a personalized message. TODO Localize

            String userId = data.getStringExtra("key");
            if(userId==null)
            {
                txtMainMessage.setText("Null");
            }else
            {
                    String msg = "Hello " + userId + ". Now select the exhibition room please.";
                 txtMainMessage.setText(msg);
            }

Snap shot of emulator

enter image description here

他のヒント

Create a new Intent to send data back through onActivityResult instead of using getIntent().

Intent intent = new Intent();
if (success) {
    // TO-TEST pass the credentials back to the calling activity
    intent.putExtra(OUTPARAM_USERID, mEmailView.getText());
    intent.putExtra(OUTPARAM_PASSW, mPasswordView.getText());
    setResult(RESULT_OK, intent);   // otherwise it returns RESULT_CANCELED

    finish();
} else {
    ...
}

You have to use onNewIntent in your activity to read the passed parameters.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top