I have a Recycleview of multiple movie's poster. I tried to click each poster to start a new activity with details of the movie, now I've tried to use the details of movie like date and name of movie to be shared in detail activity so I used this code in MainActivity:
#Override
public void onClick(String MovieName, String MovieDate) {
Context context = this;
Class destinationClass = DetailActivity.class;
Intent intentToStartDetailActivity = new Intent(context, destinationClass);
intentToStartDetailActivity.putExtra(Intent.EXTRA_TEXT, String.valueOf(MovieName));
intentToStartDetailActivity.putExtra(Intent.EXTRA_CC, String.valueOf(MovieDate));
startActivity(intentToStartDetailActivity);
}
and in DetailActivity:
mMovieName = (TextView) findViewById(R.id.tv_movie_Name);
mMovieDate = (TextView) findViewById(R.id.tv_movie_date);
Intent intentThatStartedThisActivity = getIntent();
if (intentThatStartedThisActivity != null) {
if (intentThatStartedThisActivity.hasExtra(Intent.EXTRA_TEXT )) {
movieName = intentThatStartedThisActivity.getStringExtra(Intent.EXTRA_TEXT);
mMovieName.setText(movieName);
}
if (intentThatStartedThisActivity.hasExtra(Intent.EXTRA_CC )) {
movieDate = intentThatStartedThisActivity.getStringExtra(Intent.EXTRA_CC);
mMovieDate.setText(movieDate);
}
}
It works fine and I get the information in detail activity but I used Intent.EXTRA_TEXT and Intent.EXTRA_CC and I need to use more. So, my question is can I rename the EXTRA_ with some other word that I choose? Cuz I saw it when I search different names for Extra but don't know how to create a new one like Extra_DESCRIPTION.
And the second question - is it true to use a new if condition with hasExtra() like I did to get information? can't I use only on if condition with hasExtra() to get all information? if so then how to do that?
ofcourse you can use any key you like.
for example
intent.putExtra("username", yourUsername);
intent.putExtra("password", yourPassword);
and it's a good practice to check intent.hasExtra(String key) to avoid null pointer exception.
or you can just directly check if intent has any extra budle by intent.hasExtras()
Related
I am making a frisbee logger and have an ArrayList of Team objects. Each Team has an ArrayList of Player objects. Everything is using Serializable properly to be sent using Intent.
In my main activity I am displaying the list of Team objects in a ListView and an option to add another Team (only a name is needed). Once a Team is selected I pass the object to another activity using Intent. On this second activity I have it display the list of Player objects and have fields to enter another player object into the passed list.
When I return to the main activity and go back to the add Player activity, what I have added is gone.
I cannot use static because there is obviously more than one Team object. I think passing back the changed ArrayList could work but that seems a little lame, time-consuming, and frustrating.
Is there a built-in way in Android Studio that does this or am I on my own?
Note: I am not using SQLite as suggested in the comments
There's not a whole lot to show on this but here it is I guess:
MainActivity.java
private static ArrayList<Team> listOfTeams = new ArrayList<>();
private static ArrayList<Game> listOfGames = new ArrayList<>();
private ListView gameList, teamList;
.....
teamList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Team t = (Team)teamList.getItemAtPosition(position);
viewTeam(t);
}
});
.....
//Item select in teamList. Start the TeamViewActivity
public void viewTeam(Team t)
{
Intent i = new Intent(this, TeamViewActivity.class);
i.putExtra("teamView",t);
startActivity(i);
}
TeamViewActivity.java
private Team team;
private ListView rosterList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_team_view);
rosterList = (ListView) findViewById(R.id.playerList);
Intent i = getIntent();
Bundle extras = i.getExtras();
if(extras!=null)
{
if(extras.get("teamView")!=null)
{
team = (Team) extras.get("teamView");
}
}
populateRosterList(team.getRoster());
}
public void addPlayerToRoster(View view)
{
String checkFirst = ((EditText) findViewById(R.id.firstText)).getText().toString();
String checkLast = ((EditText) findViewById(R.id.lastText)).getText().toString();
String checkNumber = ((EditText) findViewById(R.id.numberText)).getText().toString();
if(!checkNumber.equals(""))
{
team.addPlayer(checkFirst, checkLast, Integer.parseInt(checkNumber));
((EditText) findViewById(R.id.firstText)).setText("");
((EditText) findViewById(R.id.lastText)).setText("");
((EditText) findViewById(R.id.numberText)).setText("");
populateRosterList(team.getRoster());
}
}
public void returnToMain(View view)
{
Intent i = new Intent(this, MainActivity.class);
i.putExtra("teamView", team);
startActivity(i);
}
private void populateRosterList(ArrayList<Player> list)
{
ArrayAdapter<Player> adapter = new ArrayAdapter<>(this,
R.layout.activity_list, R.id.genericText, list);
rosterList.setAdapter(adapter);
}
Consider your concept:
You serialize an object, i.e. you transform it into a transferrable format which is then copied over to the other activity and reconstructed as a new instance.
Consequently, you alter another instance, which is not available in the previous activity, if you do not return it - again, serialized - and finally reconstruct and copy it back into the respective instance.
What you need is a shared memory storage in your application, which can alter and retrieve data cross-activity OR a proper data routing using Intents w/ ISerializable.
Options:
Always serialize objects and pass and copy them around.
-> No multithreaded alteration, possibly slow, unbeautiful
Singleton application with global data storage ir Context Object (I do NOT recommend the due to memory management and Garbage
Collection inbetween Activity Switches BUT for consistency I'd
wanted to mention this option)
SQLite3
-> Quick, Simple and Scalable, But a bit cumbersome to get started with
Any other file-structure stored and maintained in the data folder
-> I'd expect a lot of boilerplate code here, and low performance
Webservice and remote database
Proper component setup, i.e. initialize all accessing components in your software with the appropriate reference to the data structs using for example fragments (Thanks to #mismanc, I actually missed that option initially)
In general you could abstract all that away using services and repositories, which allows you to under-the-hood test options like 3. 4. And 5. and find your best solution, and in addition, keeo the accessing code simple and clean.
in your case, you can use startActivityForResult instead of startActivity, then get your modified Team object from onActivityResult(int requestCode, int resultCode, Intent data) to update your list.
startActivityForResult example
You can use fragments. You hold the list in the MainActivity and pass its reference to ShowListFragment and AddPlayerFragment by interfaces. And you can also do other operations over them. If you dont want to use json or sqlite it can be a good way for you.
MainActivity.java
public class MainActivity extends Activity implements ShowListener{
public interface ShowListener{
ArrayList<Team> getTeamList();
}
private ArrayList<Team> listOfTeams = new ArrayList<>();
#Override
public ArrayList<Team> getTeamList() {
return listOfTeams;
}
}
ShowListFragment.java
public class ShowListFragment extends Fragment {
private ArrayList<Team> listOfTeams;
private ShowListener listener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
listener = (ShowListener)getActivity();
listOfTeams = listener.getTeamList();
}
}
As #Kingfisher Phuoc mentioned you could use srartActivityForResult in case you don't want to change your approach.
Otherwise I will suggest you use either :
SharedPreference to store your arraylist object (by converting the arraylist to json then store it as string in json format). In the PlayerActivity you retrieve the data, manipulate it then save it. see this post
SQLite
Currently I am working on the Google's Saved Games integration into an Android app.
I am trying to create a new snapshot after the user requests new save. I implemented onActivityResult as i found here:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
// requestCode and resultCode checks happen here, of course...
if (intent != null) {
if (intent.hasExtra(Snapshots.EXTRA_SNAPSHOT_METADATA)) {
// Load a snapshot.
SnapshotMetadata snapshotMetadata = intent.getParcelableExtra(Snapshots.EXTRA_SNAPSHOT_METADATA);
currentSaveName = snapshotMetadata.getUniqueName();
loadFromSnapshot(snapshotMetadata);
} else if (intent.hasExtra(Snapshots.EXTRA_SNAPSHOT_NEW)) {
// Create a new snapshot named with a unique string
// TODO: check for existing snapshot, for now, add garbage text.
String unique = new BigInteger(281, new Random()).toString(13);
currentSaveName = "snapshotTemp-" + unique;
saveSnapshot(null);
}
}
}
Obviously it is a good idea to check if a snapshot with the generated name already exists. How should I actually do it?
The list of existing saved games can be retrieved by calling [Snapshots.load()](https://developers.google.com/android/reference/com/google/android/gms/games/snapshot/Snapshots#load(com.google.android.gms.common.api.GoogleApiClient, boolean)). This is an asynchrounous call, so one way to use it is to call it before saving and keep the names in a list which you can then compare to the new name.
The sample CollectAllTheStars (https://github.com/playgameservices/android-basic-samples) demonstrates how to use this API to display a custom view to select a saved game.
Games.Snapshots.load(mGoogleApiClient, false).setResultCallback(
new ResultCallback<Snapshots.LoadSnapshotsResult>() {
#Override
public void onResult(Snapshots.LoadSnapshotsResult loadSnapshotsResult) {
mSavedGamesNames = new ArrayList<String>();
for (SnapshotMetadata m :loadSnapshotsResult.getSnapshots()) {
mSavedGamesNames.add(m.getUniqueName());
}
}
});
I have my 2 activities set up and linked.
What I'm trying to do:
Take a generated text view in my first activity, convert it to a string, pass it to my other activity, where is it displayed in a list view with other previous passed text views.
So in my first activity I currently have:
public void SaveMessage(View view) {
String saved = message.getText().toString();
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra("message",message);
Toast.makeText(getApplicationContext(), R.string.addedfavs, Toast.LENGTH_SHORT).show();
}
However I don't really know where to go from this, I've looked at trying store the strings in arrays or then in array lists, but to no avail.
Help would be much appreciated on how to receive each string and store it in some sort of arraylist (as arrays are of fixed size) or any format that could consequently be displayed in a ListView.
However I don't really know where to go from this,
First of all you must start the intent activity:
context.startActivity(intent);
Then, when necessary, in FirstActivity or SecondActivity, get the intent that started your activity with:
Intent intent = getIntent();
Now, you have also the extras with that intent. As you have the extra data as Strings, use intent.getStringExtra(String name) method.
In your case:
String message = intent.getStringExtra("message");
I've looked at trying store the strings in arrays or then in array lists, but to no avail.
You have other extra methods like getStringArrayListExtra to pass ArrayList<> or getStringArrayExtra to pass Arrays
I could not properly understand your question, but according to my understanding, there are two solutions.
Solution 1:
If you want to save previously passed texts, you can do that using a db. Whenever you pass a string from your first activity to second one, store that text in db and get all the strings from db and populate those in list.
Or you can save it in arraylist and save the array list to SharedPreferences like:
public void addMessage(String message) {
if (currentMessages == null) {
currentMessages = new ArrayList<String>();
}
currentMessages.add(message);
//save the task list to preference
SharedPreferences prefs = getSharedPreferences(SHARED_PREFS_FILE, Context.MODE_PRIVATE);
Editor editor = prefs.edit();
try {
editor.putString(MESSAGES, ObjectSerializer.serialize(currentMessages));
} catch (IOException e) {
e.printStackTrace();
}
editor.commit();
}
public ArrayList<String> getMessages() {
if (currentMessages == null) {
currentMessages= new ArrayList<String>();
}
// load tasks from preference
SharedPreferences prefs = getSharedPreferences(SHARED_PREFS_FILE, Context.MODE_PRIVATE);
try {
currentMessages = (ArrayList<String>) ObjectSerializer.deserialize(prefs.getString(MESSAGES, ObjectSerializer.serialize(new ArrayList<String>())));
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
You can use this arraylist as a data source for your adapter.
Solution 2:
If there are multiple messages that are passed via intent, then use this:
ArrayList<String> messages = new ArrayList<String>();
messages.add(message1);
messages.add(message2);
.
.
.
messages.add(messageN);
Then use this arraylist as a data source for your adapter.
Edited:
SHARED_PREFS_FILE can be a static final String like:
public static final String SHARED_PREFS_FILE = "sharedPrefsFile";
(Desired preferences file. If a preferences file by this name does not exist, it will be created when you retrieve an editor (SharedPreferences.edit()) and then commit changes (Editor.commit()).)
You can get ObjectSerializer class from here and add it to your project.
I have uploaded data onto parse.com and i am trying to retrieve the data from parse.com and display it in a textview.
i have a parseconstants class:
public static final String TYPE_STRING = "string";
public static final String KEY_FILE_TYPE = "fileType";
i send the message and it uploads to parse fine
String fileName = "text.txt";
String fileType = "text";
these 2 values are sent to parse.com as filename and filetype.
but when i get it back in inboxActivity here:
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
ParseObject message = mUserBio.get(position);
String messageType = message.getString(ParseConstants.KEY_FILE_TYPE);
ParseFile file = message.getParseFile(ParseConstants.KEY_FILE);
Uri fileUri = Uri.parse(file.getUrl());
if (messageType.equals(ParseConstants.TYPE_STRING)){
Intent intent = new Intent(getActivity(), ViewTextActivity.class);
intent.setData(fileUri);
startActivity(intent);
}
it does not call on the text activity class and does not show the class.
in the TextViewController i try to display the text into the TextView like below:
mDisplay = (TextView)findViewById(R.id.bioDisplay);
Uri textUri = getIntent().getData();
File string = new File(textUri.toString());
mDisplay.setText((CharSequence) string);
1) Why does the ViewtextActivity not show?
2) will the textview display the retrieved user bio?
Firstly, try to avoid calling constants like this:
ParseConstants.KEY_FILE_TYPE
Completely!
Rather import your class statically:
import static <your_package_name>.ParseConstants.*;
//now you can access your constants by calling it on its own:
String messageType = message.getString(KEY_FILE_TYPE);
EDIT
Your naming standards are not up to standard (An instance of File, should be called something to do with a File, and not "string")!! You are trying to display an object of type File within a TextView which won't work. Rather try this, instead of letting Android Studio cast it to a CharSequence:
mDisplay.setText(string.toString());
Thirdly, when calling ViewTextActivity, there are 3 ways to do this (as I am not sure if you are using a Fragment or not):
//if you are using a Fragment:
Intent intent = new Intent(getActivity(), ViewTextActivity.class);
//if you are using a FragmentActivity, you need to cast it:
Intent intent = new Intent((Your_Base_Activity) getActivity(), ViewTextActivity.class);
//if you are using a normal activity:
Intent intent = new Intent(Your_Activity_Name.this, ViewTextActivity.class);
As far as your TextView displaying data is concerned, your code does seem logically correct.
EDIT 2
From the ParseObject API, we see that getString will return the String value from that Key that is put in as the parameter (See Here).
According to you, you are checking if the return value is equal to the word "string". This doesn't make sense, as you are putting in the key value of "fileType".
My suggestion is check if the return is not null by using a log:
String messageType = message.getString(KEY_FILE_TYPE);
Log.e("MessageReturned: ", "Returned-" + messageType);
Or you can rethink, what the value that is supposed to equate to is supposed to be, as "string" doesn't make sense as far as I can see.
EDIT 3
Since you are saying that the value uploaded for the variable fileType is "text" should you not rather be doing this:
if (messageType.equals("text")){
EDIT 4
Your method of parsing information between the intents is obsolete. You need to try this:
if (messageType.equals(ParseConstants.TYPE_STRING)){
Intent intent = new Intent(getActivity(), ViewTextActivity.class);
intent.putExtra("fileUri", fileUri.toString());
startActivity(intent);
}
Then in your other class, you access it like so:
Bundle extras = getIntent().getExtras();
Uri receivedFileUri = Uri.parse(extras.getString("fileUri"));
I currently have a list view and I'm trying to direct the list view to different activities. So that if you click an item from let's say 1-4 you'll get the class that corresponds to that. The only way that I can think of doing it is grabbing the text of the item in the list view and starting the activity of that name. The code for it would go something like this:
final String chosen = "";
chosen = (String) ((TextView) view).getText();
Intent nextScreen = new Intent(getApplicationContext(), chosen.class);
That does not work. I get an error on the last line, saying that chosen cannot be resolved into a type.
I know that ((TextView) view).getText() works because
Log.d("Debug", "Test"+((TextView) view).getText());
gives me the correct chosen item in logcat.
Any ideas/suggestions? Thanks in advance
EDIT:
I tried changing my code to this:
String chosen = (String) ((TextView) view).getText();
try {
Intent nextScreen = new Intent(getApplicationContext(), Class.forName(chosen));
startActivity(nextScreen);
Log.d("Debug", "Good"+((TextView) view).getText());
}
catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.d("Debug", "Bad"+((TextView) view).getText());
}
Log.d("Debug", "Final"+((TextView) view).getText());
Log cat gave me an output of
BadItem1
FinalItem1
I think I'm going about this the wrong way as someone pointed out. I also think I should be using OnItemClickListener. I will try it and post my results for easier help in the future.
The error is here:
final String chosen = "";
chosen = (String) ((TextView) view).getText();
Since you declare chosen as final, you can assign it a value only once:
final String chosen = (String) ((TextView) view).getText();
Moreover I suppose you want to start the Activity which has the name that is stored in variable chosen. You cannot write chosen.class for this. The correct way to do this is:
Class.forName(chosen);
Hope this helps!
There is no Intent constructor that takes a Context and a String. You can probably do something like Class.forName(chosen) in the call to the Intent constructor.
Calling .class on a variable gets the class for that variable, not the class for the content of the variable.
I think that you should use the OnItemClickListener on the ListView to identity the clicked item. The position parameter, or calling getItemAtPosition(position), should be enough to identify uniquely a item in the listview and call the appropriate activity.
See documentation here: http://developer.android.com/reference/android/widget/AdapterView.OnItemClickListener.html
Make a Factory.
This way you don't have to tie your class names to the text the user is reading. giving you more flexibility / better user experience / easier code to maintain. Helping with your separation of concerns as well.
class NavFactory {
private static final int CLASS_FIRST = 1;
public static Intent getNavIntent(Context context, String name){
switch(getId(name)){
case CLASS_FIRST:
return new Intent(context, FirstClass.class);
default:
return null;
}
}
private static int getId(String name){
if("listItemOneText".equals(name)
return CLASS_FIRST;
return -1;
}
}
Ref: Java Factory Pattern
In your case:
String chosen = (String) ((TextView) view).getText();
Intent nextScreen = NavFactory.getNavIntent(this, chosen);
You are new sending String as the class of supposed Activity. This is what you need:
final String chosen = "";
chosen = ((TextView) view).getText();
Class<?> chosenActivity = Class.forName(chosen);
Intent nextScreen = new Intent(this, chosenActivity);