I am a beginner at android development, and have reached the end of Building your First App. Before I move on, I would like to confirm and validate my understanding of using multiple activities and communicating from one activity to another.
/** Called when the user clicks the Send button */
public void sendMessage(View view) {
Intent intent = new Intent(this, DisplayMessageActivity.class);
EditText editText = (EditText) findViewById(R.id.edit_message);
String message = editText.getText().toString();
intent.putExtra(EXTRA_MESSAGE, message);
startActivity(intent);
}
1) Is my understanding correct that the second paramater in the constructor for Intent (Intent intent = new Intent(this, DisplayMessageActivity.class)) serves as a reference for startActivity(...) and reflection is used to call the method onCreate() in the class DisplayMessageActivity since the class DisplayMessageActivity was given as a class object?
2) What is the use of the first paramater (the context one in the constructor)? (Basically how does Android use the first parameter, a brief description please, to start the activity)?
3) As seen in the tutorial, last part of building your first app, it advises me to declare a variable as such: (public final static String EXTRA_MESSAGE = "me.marshac.myfirstapp.MESSAGE";). I know the purpose of this declaration and initialization, but why don't I have to specify the full package name (me.marshac.myfirstapp. (...) .MESSAGE) and where is the MESSAGE variable coming from? The only two variables similar to that are both local variables in sendMessage() and the other activity's onCreate(), but they are different case and local?
I am sorry for the very in-depth inquiries, I want to establish a firm understanding of the beginner concepts before I move on to intermediate/advanced ones.
1) Yes. I think that's what is happening behind the scenes. If you want to know exactly how they did it, you can go to read the Android OS source code. It is open source, you know. Just Google it!
2) Android uses a stack for storing activities. When you first started your app, it's like this:
MyActivity
Then when you start another activity, a new activity object is pushed onto the stack
DisplayMessageActivity
MyActivity
When you tap the back button, an activity from the stack is popped.
If you didn't give this as the parameter, how would the OS know where to push the new activity onto?
3) I think this is just a convention of some kind. I usually use simple names like message, and it works! It's similar to asking why should I name a class in PascalCase and a local variable in camelCase?
Related
Good day,
I was assigned to an android project inside my company and I'm having a little bit of a struggle. I have not touched Android in a few years. Figured you might be able to help me find what i am missing.
I have a project that calls an external libratry for reading a barcode, then the code does a parsing of the byte array and converts it into an object. The problem I am having is of comunication between my MainActivity and the activity that scans the barcode.
This is the piece of code that calls my barcode reader activity:
setContentView(R.layout.activity_main);
MyObjectActivity.setParentActivity(this);
Intent intent = new Intent(this, MyObjectActivity.class);
startActivityForResult(intent, 0);
This one should escalate the scanned data from MyObjectActivity object into my MainActivity (so i can actually do something with the data).
try
{
//MyObject objet contains child objects
MyObject content = MyObjectParser.retrieveContentData(data /*contains the byte array*/);
Intent data_toreturn = new Intent();
data_toreturn.putExtra("data_sent", true);
data_toreturn.putExtra(BARCODE_DATA_EXTRA_TAG, content);
if (getParent() == null)
{
setResult(RESULT_OK, data_toreturn);
} else
getParent().setResult(RESULT_OK, data_toreturn);
} catch(final RuntimeException e)
{
parentActivity.runOnUiThread(new Runnable()
{
#Override
public void run()
{
Toast.makeText(parentActivity, e.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
// stop the Activity
finish();
While debugging i manage to run all the code up until the finish(). Then i get the exception
Failure delivering result ResultInfo{who=null, request=0, result=-1, data=Intent { (has extras) }} to activity {MyObjectActivity}: java.lang.ClassCastException: java.lang.Object[] cannot be cast to ChildObject[]
According to what I remember from developping in android, in order to be able to pass Objects between Activities you need intents and Objects that are Parcelable or Serializable (not sure about this one). I've reviewed the code and the sub objects DO implement this.
I really don't know how to continue. It is either a thing of configuration, or I am doing something very wrong and I am not seeing it.
Thank you for your response.
So I see you are using
startActivityForResult(intent, Yournumber) //I would not use 0, use 1001 or something more custom.
so that you make yourself the parent of the launched activity.
So why are you doing the setParentActivity call? I assume just for doing your Toast? Seems like a unhealthy way to handle that, but that is a different issue.
Then override onActivityResult in that parent activity to handle the intent data returned. As I'm sure you have already done.
But I'm not certain of your "content" object if it is parcable or not. You can check by simply commenting out "adding that to the intent" and seeing if it gets delivered when that object is not inside the intent.
If it is delivered then you should ensure that your object implements Parceable so that it can be put in the intents. If it still does not get delivered then it would appear you are having an issue with your parent not pointing to the correct class somehow and we would need to see more code to help out on that.
I see you are passing the raw bytes, which should work fine, but you could try a wrapper object that implements parceable as well that holds the bytes as a member and pass back that object as a last ditch effort as well.
Let's assume you're sending an Object X via an explicit Intent from Activity A to Activity B.
Step 1 - make sure your class X implements Serializable interface (which you said you already have). Also make sure that all other objects inside your Object X do implement Serializable interface.
Step 2 - Somewhere inside your Activity A you'd have similar code:
X objectX = new X();
Intent intent = new Intent(A.this, B.class);
intent.putExtra("myObject", objectX);
startActivity(intent);
Step 3 - Inside your Activity B you will get the Object reference and typecast it to X:
Intent intent = getIntent();
X objectX = (X)intent.getSerializableExtra("myObject");
Hope this helps. This is the basic pattern of passing objects between Activities and there is nothing more to it.
I am following the android programming tutorial here: http://developer.android.com/training/basics/firstapp/starting-activity.html
It details how to start a new activity and send some data to it.
I have these activities now: SplashActivity, LoginActivity, RegisterActivity, and MainActivity.
SplashActivity does a quick preference read to see if you are logged in. If you are, it passes a user ID to MainActivity thus:
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra(EXTRA_USERID, userID);
Where userID is a user ID number as String.
Both Login and Register Activity does its thing, which returns a valid user ID from network. They pass it to main activity using the same code snippet above.
This is defined in all three activity classes: public final static String EXTRA_USERID= "com.example.myfirstapp.USERID";.
Following the tutorial, I have this code in the onCreate method of MainActivity:
Intent intent = getIntent();
String userID = intent.getStringExtra([LoginActivity].EXTRA_USERID);
Notice the square bracketed peice of code [LoginActivity]. I don't know what to put here. I don't know which activity starts the MainActivity. Putting LoginActivity seems to only work when the login activity starts the main activity. When people register or the user ID is read from preferences in SplashActivity, the return value is an empty string.
What is the method for determining which activity started MainActivity? Or is there a way to simply get the value passed to the activity without specifying from which Activity it is created?
Any help would be appreciated.
The first argument to putExtra is a string key you define that can be used to extract the value later on. The key should start with your app's package name.
It doesn't matter where you define the key as long as you pass the right key when you launch the intent - e.g.:
public class MainActivity extends Activity {
public static final String EXTRA_USERID = "com.my.app.USERID";
}
If you launch MainActivity from LoginActivity or SplashActivity, you'll want to reference the same MainActivity.EXTRA_USERID string anywhere the intent is created. It might be easier to define a common function that takes the user ID and creates an intent with the right extra parameters.
Hi I have just began working on the first android application on developer.android.com.
well to start with I got to learn many error origins and their solutions from S.O. , but i have been trying to figure out this statement
"DisplayMessageActivity cannot be resolved to a type" while we have to set an Intent for button onclick function. It shows this error in the line where the code line is:
Intent intent = new Intent (this, DisplayMessageActivity.class);
here is the java file:
MainActivity.java
}
/**called when the user clicks the send button*/
public void sendMessage(View view) {
Intent intent = new Intent (this, DisplayMessageActivity.class);
EditText editText = (EditText) findViewById (R.id.edit_message);
String message = editText.getText().toString();
intent.putExtra(EXTRA_MESSAGE, message);
startActivity (intent);
}
}
I tried a lot find which class do I need to import now, and searched but no avail.
may be I am a beginner is what I miss here.
Well, I think it's too late to answer and probably you figured out already.
However, just in case I'd like to put some more explanation.
Probably their "Starting Another Activity" section of Buidling Your First App" was revised after you posted your question, but I found that the user-defined "DisplayMessageActivity" is defined several lines below where you were guided to write code to create Intent and thus refer to DisplayMessageActivity.
At "Create Second Activity" section, the DisplayMessageActivity is created.
Well, Google's pedagogy style is not good, and I found out that their framework design ( and thus naming ) is not good and doesn't reveal what they are.
But.. if you choose Android platform to develop for, what can you do other than endure that. Good luck with that.
In that tutorial of developing first app, they create DisplayMessageActivity.java later part of tutorial. Please read the complete tutorial. The documentation have been corrected to indicate the same when using IDEs. You can visit here :
Note: The reference to DisplayMessageActivity will raise an error if you’re using an IDE such as Eclipse because the class doesn’t exist yet. Ignore the error for now; you’ll create the class soon.
http://developer.android.com/training/basics/firstapp/starting-activity.html#BuildIntent
DisplayMessageActivity is not a class predifined by android packages, so you should create it as ordinary java class and call from yours, here, MainActivity. Sure it doesn't require to be named as in the tutorial
You can create the display message activity class yourself by adding this code anywhere
public class DisplayMessageActivity {
}
I'm simply trying to carry a string onto the next activity without having to define an entire object for the task. I've seen similar solutions and gotten them to work BUT without using AsyncTask to create the intent.
protected void onPostExecute(Boolean result) {
if (loggedIn && hasPin) {
Intent intent = new Intent(UniteActivity.this,
WebViewActivity.class);
intent.putExtra(PASSED_USERNAME, passUser);
startActivity(intent);
}
if (loggedIn && !hasPin) {
Intent intent = new Intent(UniteActivity.this,
CreatePinActivity.class);
intent.putExtra(PASSED_USERNAME, passUser);
startActivity(intent);
PASSED_USERNAME is a public static constant to hold the package name, just as the putExtra() method requires. I then try to pull the value out in the next activity.
Intent extras = getIntent();
String username = extras.getStringExtra(UniteActivity.PASSED_USERNAME);
// carry username to next activity
Intent intent = new Intent(CreatePinActivity.this,WebViewActivity.class);
intent.putExtra(PASSED_USERNAME, username);
startActivity(intent);
There is never a String to pull out, the value of username is always null. I've gone through the debugger and found that the Eclipse IDE debugger shows different intent ID's between the activities, they are never consistant. Is it possible that AsyncTask is interfereing somehow because it splits into a seperate thread?
I don't know if this applies to your problem, because I can't see from your code snippet if the intermediary activity is freshly created or not.
BUT: the getIntent()-method always returns the first Intent that started the activity. If the activity remains in the background and receives a new Intent this value does not get updated automatically. You have to override onNewIntent(...) and manually call setIntent(...) for this to work (or do all your stuff directly there).
So just for the case that you do not run your posted code in the onCreate() method please check if you did not miss to fetch the real intent you are interested in.
Not sure of the exact answer for you solution.
You calling startActivity on the UI since it's in postExecute().
If all else fails you can just save that value to a sharedpreference.
The way you have handled the variable PASSED_USERNAME seems incorrect. You have used it in some palaces as simple PASSED_USERNAME whereas in some other places you have used it with the class named prefixed UniteActivity.PASSED_USERNAME. Since it is a Public Static Constant always use it prefixed with the class name.
I'm currently working on an Android App and, almost every time I use it, I get a an error. Most of the time it doesn't crash the app, but it is still frustrating that I'm seeing this error. I thought I did a check for it, but I could be wrong. Thanks for the help! The relevant code is below. (It's relevant because the line outside the if statement is throwing the NullPointerException.)
Activity activity;
if(activity == null)
{
activity = new Activity();
}
Intent intent = new Intent(activity, Service.class);
You don't usually instantiate the Activity class in this manner. Please see the documentation on the Android Activity class here:
http://developer.android.com/reference/android/app/Activity.html
You should post some more of the surrounding code, but your problem is that creating new Intent requires a valid Context. Usually you create an Intent within an Activity (or Service or BroadcastReceiver) class so you can just do something like:
Intent intent = new Intent(this, Service.class);
Occasionally you'll create it somewhere else and pass it that valid Context, but you should pretty much never create an Activity by calling the constructor directly. There's a lot of other initialization necessary to make it useful.
As postet previously there is more to initiate for an activity than calling the constructor. Probably you get a null pointer exception deep within the Intent Constructer where it is trying to get some of the Activityinformation usually provided.
If you really want to create a Service, heres a link for starting a Service, but you should really read the whole article and probably some more of the activity lifecycle ressources.
http://developer.android.com/guide/topics/fundamentals/services.html#StartingAService