recently I been reading about the mvp pattern on Internet and to be honest, it has been a little bit confusing.
I'm trying to re-write an app using the mvp pattern but I reached a point using AsyncTask where I can't figure out how to pass the Object in the Interactor back to the View.
Here'e the code:
View:
public class DetailsActivity extends BaseActivity {
private DetailsPresenter presenter;
private Pet pet;
private TextView name, description, breed, lostAt, age;
private int idList;
#Override
protected void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
setContentView(R.layout.details_layout);
DetailsPresenter presenter = new DetailsPresenter();
Typeface font0 = Typeface.createFromAsset(getAssets(), "fonts/CaviarDreams.ttf");
Typeface font1 = Typeface.createFromAsset(getAssets(), "fonts/CaviarDreams_Bold.ttf");
TextView txtDescription = findViewById(R.id.textView8);
TextView txt1 = findViewById(R.id.textView6); //Age, Type
TextView txt2 = findViewById(R.id.textView9); //LostAt
Button btnContact = findViewById(R.id.button6);
description = findViewById(R.id.details);
menuRes = R.menu.details_menu;
name = findViewById(R.id.textView10);
breed = findViewById(R.id.breed);
lostAt = findViewById(R.id.lostAt);
age = findViewById(R.id.age);
name.setTypeface(font1);
breed.setTypeface(font0);
description.setTypeface(font0);
lostAt.setTypeface(font0);
txtDescription.setTypeface(font1);
txt2.setTypeface(font1);
txt1.setTypeface(font1);
btnContact.setTypeface(font0);
idList = getIntent().getExtras().getInt("TAG_LIST");
id = getIntent().getExtras().getInt("TAG_ID");
if(idList == 0){
txt1.setText(R.string.type);
txt2.setText(R.string.txt2);
} else{
txt1.setText(R.string.txt0);
txt2.setText(null);
}
btnContact.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(), ChatFragment.class);
startActivity(intent);
}
});
// Get pet details from database on background
pet = presenter.getPet(idList, id);
}
#Override
protected void onPostCreate(#Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
if(idList == 0){
name.setText(pet.getName());
breed.setText("(" + pet.getBreed() + ")");
description.setText(pet.getDescription());
lostAt.setText(pet.getLocation());
}else{
name.setText(pet.getBreed());
description.setText(pet.getDescription());
lostAt.setText(pet.getGender());
age.setText(pet.getAge());
}
}
}
Presenter:
public class DetailsPresenter {
private DetailsInteractor interactor;
public Pet getPet(int idList, int id) {
interactor = new DetailsInteractor(idList, id);
interactor.execute();
return interactor.pet;
}
}
Interactor:
public class DetailsInteractor extends AsyncTask<String, String, Pet> {
public Pet pet;
private int idList;
private int id;
private DBAction database;
public DetailsInteractor (int idList, int id) {
this.idList = idList;
this.id = id;
database = new DBAction();
}
#Override
protected Pet doInBackground(String... strings) {
pet = database.requestItem(idList, id);
return pet;
}
I need that after getting the data from the database, it updates the View, using object Pet.
Any answers and suggestions will be welcomed, Thanks!
When You create/initialize a presenter in Activity(This is your view) you should pass the view to the presenter. Something like this.
DetailsPresenter presenter = new DetailsPresenter(View view);
View can be any object with which you can update the UI or can call the methods in the activity.
Moreover, you have to go through few more good site to learn about MVP.
http://valokafor.com/learn-android-mvp-pattern-example/ this is really nice one.
Related
I am programming a small game app in with every player gets to choose a drawable which is then set for the following activity which is the small game.
This is my code so far:
public class Nameeingabespieler2 extends AppCompatActivity {
public static final String EXTRA_NAME1 = "com.example.die_trinkspielapp.EXTRA_NAME1";
public static final String EXTRA_NAME2 = "com.example.die_trinkspielapp.EXTRA_NAME2";
public static final String Dinonametest1 = "com.example.die_trinkspielapp.DinoSpieler1";
private TextInputLayout namespieler1;
private TextInputLayout namespieler2;
private ArrayList<DinoWahl> mDinoWahl;
private DinoAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nameeingabespieler2);
namespieler1 = findViewById(R.id.Spieler_1_input);
namespieler2 = findViewById(R.id.Spieler_2_input);
final TextView testtest = (TextView) findViewById(R.id.textView3);
initList();
final Spinner dinospinner = findViewById(R.id.spinner);
Spinner dinospinner2 = findViewById(R.id.spinner2);
mAdapter = new DinoAdapter(this, mDinoWahl);
dinospinner.setAdapter(mAdapter);
dinospinner2.setAdapter(mAdapter);
dinospinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
DinoWahl clickedItem = (DinoWahl) adapterView.getItemAtPosition(i);
String DinoName = clickedItem.getmDinoName();
Toast.makeText(Nameeingabespieler2.this,DinoName + " ausgewählt", Toast.LENGTH_SHORT).show();
}
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
dinospinner2.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
DinoWahl clickedItem = (DinoWahl) adapterView.getItemAtPosition(i);
String DinoName2 = clickedItem.getmDinoName();
Toast.makeText(Nameeingabespieler2.this,DinoName2 + " ausgewählt", Toast.LENGTH_SHORT).show();
}
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
}
private void initList(){
mDinoWahl = new ArrayList<>();
mDinoWahl.add(new DinoWahl("Brutus",R.drawable.alkdino));
mDinoWahl.add(new DinoWahl("Skitty",R.drawable.coolerdino));
mDinoWahl.add(new DinoWahl("Pharmi",R.drawable.drogendino));
mDinoWahl.add(new DinoWahl("Luise",R.drawable.frauendino));
mDinoWahl.add(new DinoWahl("Rex",R.drawable.koenigsdino));
mDinoWahl.add(new DinoWahl("Cookie",R.drawable.kochdino));
mDinoWahl.add(new DinoWahl("Divi",R.drawable.magierdino));
mDinoWahl.add(new DinoWahl("Fumu",R.drawable.shishadino));
mDinoWahl.add(new DinoWahl("Dr. Saurum",R.drawable.streberdino));
}
private boolean wertspieler1() {
String usernameInput = namespieler1.getEditText().getText().toString().trim();
if (usernameInput.isEmpty()) {
namespieler1.setError("Spieler bitte eintragen");
return false;
} else if (usernameInput.length() > 15) {
namespieler1.setError("Name zu lang");
return false;
} else {
namespieler1.setError(null);
return true;
}
}
private boolean wertspieler2() {
String usernameInput = namespieler2.getEditText().getText().toString().trim();
if (usernameInput.isEmpty()) {
namespieler2.setError("Spieler bitte eintragen");
return false;
} else if (usernameInput.length() > 15) {
namespieler2.setError("Name zu lang");
return false;
} else {
namespieler2.setError(null);
return true;
}
}
public void starteaktivity(View view) {
if (!wertspieler1() | !wertspieler2()) {
return;
}
EditText editText1 = (EditText) findViewById(R.id.spieler1id);
String name1 = editText1.getText().toString();
EditText editText2 = (EditText) findViewById(R.id.Spieler2id);
String name2 = editText2.getText().toString();
if(name1.equals(name2)) {
Toast.makeText(Nameeingabespieler2.this, "bitte unterschiedliche Namen eingeben",Toast.LENGTH_LONG).show();
} else {
Intent intent = new Intent(this, Trinkspiel2spieler.class);
intent.putExtra(EXTRA_NAME1, name1);
intent.putExtra(EXTRA_NAME2, name2);
startActivity(intent);
}
}
}
This is my code so far and the most relevant Part is this one.
initList();
final Spinner dinospinner = findViewById(R.id.spinner);
Spinner dinospinner2 = findViewById(R.id.spinner2);
mAdapter = new DinoAdapter(this, mDinoWahl);
dinospinner.setAdapter(mAdapter);
dinospinner2.setAdapter(mAdapter);
dinospinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
DinoWahl clickedItem = (DinoWahl) adapterView.getItemAtPosition(i);
String DinoName = clickedItem.getmDinoName();
Toast.makeText(Nameeingabespieler2.this,DinoName + " ausgewählt", Toast.LENGTH_SHORT).show();
}
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
dinospinner2.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
DinoWahl clickedItem = (DinoWahl) adapterView.getItemAtPosition(i);
String DinoName2 = clickedItem.getmDinoName();
Toast.makeText(Nameeingabespieler2.this,DinoName2 + " ausgewählt", Toast.LENGTH_SHORT).show();
}
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
I don't get the choosen drawable to transfer and I really need your help.
EDIT
This is now my updated code
I have different classes
Nameeingabespieler2 (Class where I want the spinner type to be selceted and transfered to Trinkspiel2spieler.java)
Trinkspiel2spieler (this is the class where the Value should go and set the drawable for each player choosen in Nameeingabespieler2)
DinoWahl (for the Spinner)
DinoAdapter (adapter for the Spinner)
My Problem Now is, that I just wont get the Value transfered, even if I type(line: 162) everything as you said.
If I add (line 26 & 27) these Spinner declarations, they wont be used and if I remove (line: 41 & 42) then the app crashes.
But even with this version now, the next Activity (Trinkspiel2spieler) won't open.
I really don't know what to do now.
I am really sorry to bother you this much but I would be really really thankfull if you can help me.
public class Nameeingabespieler2 extends AppCompatActivity {
public static final String EXTRA_NAME1 = "com.example.die_trinkspielapp.EXTRA_NAME1";
public static final String EXTRA_NAME2 = "com.example.die_trinkspielapp.EXTRA_NAME2";
public static final String EXTRA_DINO1 = "com.example.die_trinkspielapp.DinoSpieler1";
public static final String Dinonametest2 = "com.example.die_trinkspielapp.DinoSpieler2";
private TextInputLayout namespieler1;
private TextInputLayout namespieler2;
private Spinner dinospinner;
private Spinner dinospinner2;
private ArrayList<DinoWahl> mDinoWahl;
private DinoAdapter mAdapter;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nameeingabespieler2);
namespieler1 = findViewById(R.id.Spieler_1_input);
namespieler2 = findViewById(R.id.Spieler_2_input);
Spinner dinospinner = findViewById(R.id.spinner);
Spinner dinospinner2 = findViewById(R.id.spinner2);
initList();
mAdapter = new DinoAdapter(this, mDinoWahl);
dinospinner.setAdapter(mAdapter);
dinospinner2.setAdapter(mAdapter);
dinospinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
DinoWahl clickedItem = (DinoWahl) adapterView.getItemAtPosition(i);
String DinoName = clickedItem.getmDinoName();
Toast.makeText(Nameeingabespieler2.this,DinoName + " ausgewählt", Toast.LENGTH_SHORT).show();
}
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
dinospinner2.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
Context ctx = view.getContext();
DinoWahl clickedItem = (DinoWahl) adapterView.getItemAtPosition(i);
String DinoName2 = clickedItem.getmDinoName();
Toast.makeText(Nameeingabespieler2.this,DinoName2 + " ausgewählt", Toast.LENGTH_SHORT).show();
Intent intent = new Intent();
intent.setClass(ctx, Constants.class);
intent.putExtra(Dinonametest2, DinoName2);
}
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
}
private void initList(){
mDinoWahl = new ArrayList<>();
mDinoWahl.add(new DinoWahl("Brutus",R.drawable.alkdino));
mDinoWahl.add(new DinoWahl("Skitty",R.drawable.coolerdino));
mDinoWahl.add(new DinoWahl("Pharmi",R.drawable.drogendino));
mDinoWahl.add(new DinoWahl("Luise",R.drawable.frauendino));
mDinoWahl.add(new DinoWahl("Rex",R.drawable.koenigsdino));
mDinoWahl.add(new DinoWahl("Cookie",R.drawable.kochdino));
mDinoWahl.add(new DinoWahl("Divi",R.drawable.magierdino));
mDinoWahl.add(new DinoWahl("Fumu",R.drawable.shishadino));
mDinoWahl.add(new DinoWahl("Dr. Saurum",R.drawable.streberdino));
}
private boolean wertspieler1() {
String usernameInput = namespieler1.getEditText().getText().toString().trim();
if (usernameInput.isEmpty()) {
namespieler1.setError("Spieler bitte eintragen");
return false;
} else if (usernameInput.length() > 15) {
namespieler1.setError("Name zu lang");
return false;
} else {
namespieler1.setError(null);
return true;
}
}
private boolean wertspieler2() {
String usernameInput = namespieler2.getEditText().getText().toString().trim();
if (usernameInput.isEmpty()) {
namespieler2.setError("Spieler bitte eintragen");
return false;
} else if (usernameInput.length() > 15) {
namespieler2.setError("Name zu lang");
return false;
} else {
namespieler2.setError(null);
return true;
}
}
public void starteaktivity(View view) {
if (!wertspieler1() | !wertspieler2()) {
return;
}
EditText editText1 = (EditText) findViewById(R.id.spieler1id);
String name1 = editText1.getText().toString();
EditText editText2 = (EditText) findViewById(R.id.Spieler2id);
String name2 = editText2.getText().toString();
if(name1.equals(name2)) {
Toast.makeText(Nameeingabespieler2.this, "bitte unterschiedliche Namen eingeben",Toast.LENGTH_LONG).show();
}
else{
Intent intent = new Intent(this, Trinkspiel2spieler.class);
intent.putExtra(EXTRA_NAME1, name1);
intent.putExtra(EXTRA_NAME2, name2);
intent.putExtra(EXTRA_DINO1, ((DinoWahl) dinospinner.getSelectedItem()).getmDinoName());
startActivity(intent);
}
}
}
Trinkspiel2spieler (not finished yet)
public class Trinkspiel2spieler extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_trinkspiel2spieler);
Button testnamentest = (Button) findViewById(R.id.namenbuttonid);
testnamentest.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startetest();
}
});
}
public void startetest() {
//namen einlesen
Intent intent = getIntent();
String nametextstring1 = intent.getStringExtra(Constants.EXTRA_NAME1);
String nametextstring2 = intent.getStringExtra(Constants.EXTRA_NAME2);
String Dino_uerbertragung1 = intent.getStringExtra(Constants.Dinonametest1);
String Dino_uerbertragung2 = intent.getStringExtra(Constants.Dinonametest2);
String Namen[] = {nametextstring1,nametextstring2};
//TextViews deklarieren
TextView Textview1 = (TextView) findViewById(R.id.nameanzeige1);
TextView Textview2 = (TextView) findViewById(R.id.nameanzeige2);
ImageView Dinoimage = (ImageView) findViewById(R.id.imageView2);
//TextView Textview3 = (TextView) findViewById(R.id.nameanzeige3);
Random random = new Random();
int num = random.nextInt(Namen.length);
Textview1.setText(Namen[num]);
if (Namen[num] == nametextstring1){
if (Dino_uerbertragung1 == "Cookie")
Dinoimage.setImageResource(R.drawable.kochdino);
}
else {
Dinoimage.setImageResource(R.drawable.coolerdinomrk2klein);
}
Resources resources = getResources();
String[] Trinkspielfragen = resources.getStringArray(R.array.Trinkspiel);
Random random1 = new Random();
int num2 = random1.nextInt(Trinkspielfragen.length);
Textview2.setText(Trinkspielfragen[num2]);
}
}
DinoWahl
public class DinoWahl {
private String mDinoName;
private int mDinoWahl;
public DinoWahl(String Dinoname,int dinoBild) {
mDinoName = Dinoname;
mDinoWahl = dinoBild;
}
public String getmDinoName() {
return mDinoName;
}
public int getDinoWahl(){
return mDinoWahl;
}
}
DinoAdapter
public class DinoAdapter extends ArrayAdapter <DinoWahl>{
public DinoAdapter(Context context, ArrayList<DinoWahl> DinoListe) {
super(context, 0, DinoListe);
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
return initView(position, convertView, parent);
}
#Override
public View getDropDownView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
return initView(position, convertView, parent);
}
private View initView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(
R.layout.dino_spinner, parent, false
);
}
ImageView imageViewDino = convertView.findViewById(R.id.alkoholdino);
TextView textViewName = convertView.findViewById(R.id.Dinoname);
DinoWahl curentItem = getItem(position);
if (curentItem != null) {
imageViewDino.setImageResource(curentItem.getDinoWahl());
textViewName.setText(curentItem.getmDinoName());
}
return convertView;
}
}
Constants
package com.example.die_trinkspielapp;
public class Constants {
public static final String EXTRA_NAME1 = "com.example.die_trinkspielapp.EXTRA_NAME1";
public static final String EXTRA_NAME2 = "com.example.die_trinkspielapp.EXTRA_NAME2";
public static final String EXTRA_NAME3 = "com.example.die_trinkspielapp.EXTRA_NAME3";
public static final String EXTRA_NAME4 = "com.example.die_trinkspielapp.EXTRA_NAME4";
public static final String EXTRA_NAME5 = "com.example.die_trinkspielapp.EXTRA_NAME5";
public static final String EXTRA_NAME6 = "com.example.die_trinkspielapp.EXTRA_NAME6";
public static final String EXTRA_NAME7 = "com.example.die_trinkspielapp.EXTRA_NAME7";
public static final String EXTRA_NAME8 = "com.example.die_trinkspielapp.EXTRA_NAME8";
public static final String EXTRA_NAME9 = "com.example.die_trinkspielapp.EXTRA_NAME9";
public static final String Dinonametest1 = "com.example.die_trinkspielapp.DinoSpieler1";
public static final String Dinonametest2 = "com.example.die_trinkspielapp.DinoSpieler2";
public static final String Dinonametest3 = "com.example.die_trinkspielapp.DinoSpieler3";
public static final String Dinonametest4 = "com.example.die_trinkspielapp.DinoSpieler4";
public static final String Dinonametest5 = "com.example.die_trinkspielapp.DinoSpieler5";
public static final String Dinonametest6 = "com.example.die_trinkspielapp.DinoSpieler6";
public static final String Dinonametest7 = "com.example.die_trinkspielapp.DinoSpieler7";
public static final String Dinonametest8 = "com.example.die_trinkspielapp.DinoSpieler8";
public static final String Dinonametest9 = "com.example.die_trinkspielapp.DinoSpieler9";
}
If you could help me here I will name one of the Drawables(Dinos) the player can choose after you if you want
In your "starteaktivity" method you already have the answer, you just have to pass the selected value through extra to the intent.
Edit: To be more accurate
Hi #MarcStumpp
I already tried that but the value wont go to the startactivity. It won't recognize it if I set it in the Spinner function as a String Value.Do you know how I could fix this?
I think your code is not complete in this case.
First you should declare your spinner as property variables of your Activity
public class Nameeingabespieler2 extends AppCompatActivity {
private TextInputLayout namespieler1;
private TextInputLayout namespieler2;
private Spinner dinospinner;
private Spinner dinospinner2;
private ArrayList<DinoWahl> mDinoWahl;
private DinoAdapter mAdapter;
...
Then in your "starteaktivity" method you can get the value of the spinners to pass it as extra of your intent:
if(name1.equals(name2)) {
Toast.makeText(Nameeingabespieler2.this, "bitte unterschiedliche Namen eingeben",Toast.LENGTH_LONG).show();
} else {
Intent intent = new Intent(this, Trinkspiel2spieler.class);
intent.putExtra(EXTRA_NAME1, name1);
intent.putExtra(EXTRA_NAME2, name2);
intent.putExtra(EXTRA_NAME3, ((DinoWahl) dinospinner.getSelectedItem()).getmDinoName());
...
startActivity(intent);
}
Retrieve the value in your "Trinkspiel2spieler" activity :
public class Trinkspiel2spieler extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_trinkspiel2spieler);
String firstSpinnerVal = getIntent().getStringExtra(Constants.EXTRA_NAME3);
...
}
}
Advice
I recommend you to create a Constants class for your extra like that for example:
public class Constants {
public static final String EXTRA_NAME1 = "com.example.die_trinkspielapp.EXTRA_NAME1";
public static final String EXTRA_NAME2 = "com.example.die_trinkspielapp.EXTRA_NAME2";
public static final String EXTRA_NAME3 = "com.example.die_trinkspielapp.EXTRA_NAME3";
...
public static final String Dinonametest1 = "com.example.die_trinkspielapp.DinoSpieler1";
}
So like this you can use the same extra key across your activity and reduce risk of typo.
I don't have the line number on SO, the best is to copy and paste the lines that you think are an issue. Or take screenshot for example. Anyway, I copy the code in my IDE.
About the edited part:
My Problem Now is, that I just wont get the Value transfered, even if I type(line: 162) everything as you said. If I add (line 26 & 27) these Spinner declarations, they wont be used and if I remove (line: 41 & 42) then the app crashes.
It's normal let's see what's android studio code inspector said:
You shouldn't keep you static key here as they are already in your Constant class now. If you keep double reference you will increase the risk of mistakes.
Pay attention to the color of your variable name, dinospinner and dinospinner2 are in grey why? The IDE can give you the answers(just over one of them) :
Android Studio tells you that the value is never assigned ! To understand we should have a look at the line 41 and 42 you mentioned:
Here you are assigned the spinner value to a whole new variable, because of the Spinner at the beginning of the line. Once again, pay attention to the color of the variables dinospinner and dinospinner2. There are in white that mean there are local to the current function (OnCreate in this case). So you will not be able to call them outside of the onCreate.
We can see at line 162 the dinospinner is purple:
It's purple because you are refer to the property one but it's not assigned so when the code will be executed it will crash because of a NullPointerException because it was never assigned.
To make it work you should remove Spinner at lines 41 and 42
But even with this version now, the next Activity (Trinkspiel2spieler)
won't open. I really don't know what to do now. I am really sorry to
bother you this much but I would be really really thankfull if you can
help me.
In the next activity, I don't see a update about your extras. If you want your first spinner value you should at least get it with the key "EXTRA_DINO1" if I update my anwser:
String firstSpinnerVal = getIntent().getStringExtra(Constants.EXTRA_DINO1);
Please note that "EXTRA_DINO1" should be define in Constant and not in your activity.
On my side I was able to launch the next activity without any issue. Can you be more accurate? Whats really happens? Nothing? Did you have some leading logs?
Anyway, I think your original question is answered. If you need more help I suggest you for exemple upload the code to a repository and to share it with me. It will be way easier to review your code and provide help.
Since you seems to start on android, I recommend you to use codelab to improve your skills:
https://developer.android.com/courses/fundamentals-training/toc-v2?authuser=1
Please have a look at this:
https://www.tutorialspoint.com/what-is-a-variable-field-property-in-java
I'm currently working on an app in which users can create groups and add members to groups. Today I created a new user to test the app. When I logged in this new user I checked to see if it was a part of any groups, which I didn't expect it to be seeing as it was new. And it wasn't. But then when I logged in my usual user and clicked groups I saw the name of the test user. Why does it appear that this user is a part of a group it was never added to?
It should be noted that when looking through my firebase this test user doesn't appear to have been invited either. I'm using firestore recycler adapter to fetch data in a recyclerView.
Below is the code for my adapter responsible for adding members to a specific group.
FirestoreMemberAdapter.java:
public class FirestoreMemberAdapter extends FirestoreRecyclerAdapter<MemberModel, FirestoreMemberAdapter.MemberViewHolder> {
private static final String TAG = FirestoreMemberAdapter.class.getSimpleName();
private Context context;
private String projectId;
private String projectName;
public FirestoreMemberAdapter(#NonNull FirestoreRecyclerOptions<MemberModel> options, Context context, String projectId, String projectName) {
super(options);
this.context = context;
this.projectName = projectName;
this.projectId = projectId;
}
#Override
protected void onBindViewHolder(#NonNull MemberViewHolder holder, int position, #NonNull final MemberModel model) {
holder.mTextView.setText(model.getName());
if (model.getProfile_image() == null) {
Picasso.get().load(R.drawable.profile_image).into(holder.mImageview);
} else {
Picasso.get().load(model.getProfile_image()).into(holder.mImageview);
}
holder.mLinearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d(TAG, "onClick: Clicked on FirestoreMemberAdapter ");
Intent intent = new Intent(context, ProfileMemberPage.class);
intent.putExtra(StringCreator.PROJECT_TITLE, projectName);
intent.putExtra(StringCreator.PROJECT_ID, projectId);
intent.putExtra(StringCreator.NAME, model.getName());
intent.putExtra(StringCreator.EMAIL, model.getEmail());
intent.putExtra(StringCreator.USER_ID, model.getUser_id());
intent.putExtra(StringCreator.USER_INFORMATION, model.getUser_information());
context.startActivity(intent);
}
});
}
#NonNull
#Override
public MemberViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_projectmembers, parent, false);
return new MemberViewHolder(view);
}
public class MemberViewHolder extends RecyclerView.ViewHolder {
private LinearLayout mLinearLayout;
private TextView mTextView;
private ImageView mImageview;
public MemberViewHolder(#NonNull View itemView) {
super(itemView);
mTextView = itemView.findViewById(R.id.memberTitle);
mLinearLayout = itemView.findViewById(R.id.layout_members);
mImageview = itemView.findViewById(R.id.memberImage);
}
}
}
Here is the activity in wihch the adapter is used.
projectClicked.java:
//widgets
private RecyclerView recyclerViewMembers;
private TextView projectName;
private Button cameraBtn;
private FloatingActionButton addUserBtn;
//Firebase
private FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();
private Query query;
private FirestoreRecyclerOptions<MemberModel> options;
private FirestoreMemberAdapter adapter;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_project_clicked);
projectName = findViewById(R.id.projectName);
addUserBtn = findViewById(R.id.addUserBtn);
cameraBtn = findViewById(R.id.cameraBtn);
initRecyclerView();
addUserBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent newIntent = new Intent(projectClicked.this, UserToProject.class);
Bundle projectBundle = getIntent().getExtras();
if (projectBundle != null) {
newIntent.putExtras(projectBundle);
}
startActivity(newIntent);
}
});
}
private void initRecyclerView() {
Log.d(TAG, "InitRecyclerView: init recyclerview");
if (getIntent().hasExtra(StringCreator.PROJECT_TITLE) && getIntent().hasExtra(StringCreator.PROJECT_ID)) {
final String pName = getIntent().getStringExtra(StringCreator.PROJECT_TITLE);
final String pID = getIntent().getStringExtra(StringCreator.PROJECT_ID);
projectName.setText(pName);
recyclerViewMembers = findViewById(R.id.recyclerView_members);
query = firebaseFirestore.collection("users");
options = new FirestoreRecyclerOptions.Builder<MemberModel>().setQuery(query, MemberModel.class).build();
adapter = new FirestoreMemberAdapter(options, projectClicked.this, pID, pName);
recyclerViewMembers.setHasFixedSize(true);
recyclerViewMembers.setAdapter(adapter);
recyclerViewMembers.setLayoutManager(new LinearLayoutManager(projectClicked.this));
}
}
#Override
public void onStart() {
super.onStart();
adapter.startListening();
}
#Override
public void onStop() {
super.onStop();
adapter.stopListening();
}
Hope this makes sense, please reach out if it doesn't. Thank you in advance.
As #McSlinPlay mentioned, the reason could be pointed out to your code in projectClicked.java where you created your query and all the users (including the test user) are part of this collection:
query = firebaseFirestore.collection("users");
I'm trying to complete this small in class exercise where we have to save data using Room Database and then display that information in a ListView.
This app is about a player. The player has 4 fields (Id, Name, Position, Number of Goals scored).
The ID of the very first player saved should be #1, #2 for the second player and so on.
The user must enter the name of the player through the EditText field.
There are then three radio buttons of which, the user has to select one in order to choose their position (Goalie, Defence, Forward). Finally, the last field the user must enter the number of goals this player has scored through the use of the EditText field.
Finally, the last field the user must enter the number of goals this player has scored through the use of the EditText field.
Once the user clicks the "SAVE" button, all the fields previously selected will be cleared and their will be a quick toast message displaying the ID# of the player.
In order to view all the saved data the user must click the "VIEW ALL" button which will take them to the second activity and display the Name of the Player, Position, Number of Goals scored in the next activity.
I'm not too familiar with room so whenever I press the "Save"Save button my app crashes. Any help would be greatly appreciated, Thanks!
MainActivity.Java
public class MainActivity extends AppCompatActivity {
private EditText playerEdt, goalsEdt;
private int id = 0;
private RadioGroup groupRad;
private RadioButton radioButton;
private MyDatabase myDb;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
playerEdt = findViewById(R.id.edtPlayer);
goalsEdt = findViewById(R.id.edtGoals);
myDb = MyDatabase.getInstance(MainActivity.this);
}
public void saveData(View view) {
id++;
String name = playerEdt.getText().toString();
groupRad = findViewById(R.id.radGroup);
int selectedId = groupRad.getCheckedRadioButtonId();
radioButton = findViewById(selectedId);
String position = radioButton.getText().toString();
String goalsString = goalsEdt.getText().toString();
int goals = Integer.valueOf(goalsString);
Player player = new Player(id, name, position, goals);
myDb.playerDao().insert(player);
playerEdt.setText("");
goalsEdt.setText("");
groupRad.clearCheck();
}
public void viewData(View view) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
}
SecondActivity.Java
public class SecondActivity extends AppCompatActivity {
ListView listView;
MyDatabase database;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
listView = findViewById(R.id.listView);
database = MyDatabase.getInstance(SecondActivity.this);
List<Player> players = database.playerDao().getAll();
ArrayAdapter adapter = new ArrayAdapter(SecondActivity.this, android.R.layout.simple_list_item_1, players);
listView.setAdapter(adapter);
}
}
Player.Java
#Entity
public class Player {
#PrimaryKey
private int id;
#ColumnInfo(name = "player_name")
private String name;
#ColumnInfo(name = "player_position")
private String position;
#ColumnInfo(name = "player_goals")
private int goals;
public Player(int id, String name, String position, int goals) {
this.id = id;
this.name = name;
this.position = position;
this.goals = goals;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
public int getGoals() {
return goals;
}
public void setGoals(int goals) {
this.goals = goals;
}
}
PlayerDao.java
#Dao
public abstract class PlayerDao {
#Insert
public abstract void insert (Player player);
#Delete
public abstract void delete (Player player);
#Update
public abstract void update (Player player);
#Query("select * from Player")
public abstract List<Player> getAll();
}
MyDatabase.Java
#Database(entities = Player.class, version = 1)
public abstract class MyDatabase extends RoomDatabase {
public abstract PlayerDao playerDao();
private static MyDatabase instance;
public static MyDatabase getInstance(Context context){
if( instance == null){
instance = Room.databaseBuilder(context, MyDatabase.class, "PlayerDb")
.allowMainThreadQueries()
.build();
}
return instance;
}
}
activity_main.xml: https://www.codepile.net/pile/d5rq8mx2
activity_second.xml: https://www.codepile.net/pile/2vbYzXq3
It would appear that you have a number of issues:-
You need to have getters for all the members of the Player class.
These were added (and setters) :-
public int getGoals() {
return goals;
}
public void setGoals(int goals) {
this.goals = goals;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
The core issue is that the attemps to find the views in the saveData is returning nulls and hence you are getting a null pointer exception (NPE) because the views don't exist within the SAVE button.
The solution is to find the views (i.e use findViewById in the onCreate method).
There is also a lack of data verification which will causes issue. The following version of MainActivity.java handles the issues :-
public class MainActivity extends AppCompatActivity {
private EditText playerEdt, goalsEdt;
private int id = 0;
private RadioGroup groupRad;
private RadioButton radioButton;
private MyDatabase myDb;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
playerEdt = findViewById(R.id.edtPlayer);
goalsEdt = findViewById(R.id.edtGoals);
groupRad = findViewById(R.id.radGroup);
myDb = MyDatabase.getInstance(MainActivity.this);
}
public void saveData(View view) {
id++;
String name = playerEdt.getText().toString();
if (name.length() < 1) {
Toast.makeText(view.getContext(),"Player Name is blank. Try again.",Toast.LENGTH_SHORT).show();
playerEdt.requestFocus();
}
radioButton = findViewById(groupRad.getCheckedRadioButtonId());
if (radioButton == null) {
Toast.makeText(view.getContext(),"You must select Goalie Defence or Forward. Try again",Toast.LENGTH_SHORT).show();
return;
}
String position = radioButton.getText().toString();
String goalsString = goalsEdt.getText().toString();
int goals = 0;
try {
goals = Integer.valueOf(goalsString);
} catch (Exception e) {
Toast.makeText(view.getContext(),"You must give the number of Goals. try again.",Toast.LENGTH_SHORT).show();
goalsEdt.requestFocus();
}
Player player = new Player(id, name, position, goals);
if (myDb.playerDao().insert(player) < 1) {
Toast.makeText(view.getContext(),"Player not Added (duplicate)",Toast.LENGTH_SHORT).show();
return;
}
playerEdt.setText("");
goalsEdt.setText("");
groupRad.clearCheck();
Toast.makeText(view.getContext(),"Player Added. Name is " + name + " Position is " + position + " Goals = " + goals,Toast.LENGTH_SHORT).show();
}
public void viewData(View view) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
}
Additionally PlayerDao.java has been changed to not fail if the player name is duplicated and to also return useful values when inserting, deleting or updating. it is :-
#Dao
public abstract class PlayerDao {
#Insert(onConflict = OnConflictStrategy.IGNORE)
public abstract long insert (Player player);
#Delete
public abstract int delete (Player player);
#Update
public abstract int update (Player player);
#Query("select * from Player")
public abstract List<Player> getAll();
}
First of all, it would be better if you use autoGenerate = true in your Player.java class for id:
#Entity
public class Player {
#PrimaryKey(autoGenerate = true)
private int id;
By doing this you don't have to give your players ids and Room does the job for you.
And for the app crash when saving, you must check the log and see what is causing the app to crash. Update your question with that so users can help you.
I have implemented the firebase recycler like this
public class HomeActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final String REQUIRED = "Required";
// [START declare_database_ref]
private DatabaseReference mDatabase;
// [END declare_database_ref]
private FirebaseAuth mAuth;
private static String LOG_TAG = "CardViewActivity";
public static class PostHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
View mView;
public PostHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
mView = itemView;
}
public void setName(String name) {
TextView field = (TextView) mView.findViewById(R.id.name);
field.setText(name);
}
public void setText(String text) {
TextView field = (TextView) mView.findViewById(R.id.body);
field.setText(text);
}
public void setImage(String image){
ImageView pp = (ImageView) mView.findViewById(R.id.image);
Picasso.with(Application.getAppContext()).load(image).placeholder(R.drawable.nodp).error(R.drawable.nodp).transform(new CircleTransform()).into(pp);
}
#Override
public void onClick(View mView) {
//what to do here
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
findViewById(R.id.progressBar3).setVisibility(View.VISIBLE);
findViewById(R.id.nopost).setVisibility(View.GONE);
//mListview = (ListView) findViewById(R.id.listview);
mAuth = FirebaseAuth.getInstance();
//the post list shit is happening here
final DatabaseReference root = FirebaseDatabase.getInstance().getReference();
FirebaseUser user = mAuth.getCurrentUser();
DatabaseReference postRef = root.child("users").child(user.getUid().toString()).child("posts");
RecyclerView recycler = (RecyclerView) findViewById(R.id.recyclerview);
recycler.setHasFixedSize(true);
recycler.setLayoutManager(new LinearLayoutManager(this));
FirebaseRecyclerAdapter mAdapter = new FirebaseRecyclerAdapter<PostList, PostHolder>(PostList.class, R.layout.row_one, PostHolder.class, postRef) {
#Override
public void populateViewHolder(PostHolder postViewHolder, PostList postList, int position) {
//try catch block to catch events of no posts, it will most likely return a null error, so im catching it, else
//find its exception and catch it
try {
String firstname = postList.getFirstname();
String lastname = postList.getLastname();
firstname = firstname.substring(0, 1).toUpperCase() + firstname.substring(1); //convert first string to uppercase
lastname = lastname.substring(0, 1).toUpperCase() + lastname.substring(1);// same thing happening here
String name = (firstname + " " + lastname); // concatenate firstname and lastname variable.
postViewHolder.setName(name);
postViewHolder.setText(postList.getBody()); // set the vew holder
//note that picasso view holder was applied in the view holder instead
String image = postList.getImgUrl().toString();
postViewHolder.setImage(image);
findViewById(R.id.progressBar3).setVisibility(View.GONE);
}
catch(NullPointerException e) {
findViewById(R.id.nopost).setVisibility(View.VISIBLE);
}
}
};
recycler.setAdapter(mAdapter);
}
}
and it works perfectly for my use case, I have gone through questions about how to set up onClick listeners for recycler adapter, and I think I've got it as seen in my code above.
My question is:
minor issue: when an item is clicked, I want to pass data through an intent to another activity to display details about the post. I can achieve this through intent.putExtra() on my ViewHolder as referenced by another question. But my problem is that my view holder class is outside the activity's onCreate() (that's the only way it seemed to work) so I can't call start activity from within ViewHolder,
major issue: since PostList, from which my data is from, is not yet set in the ViewHolder, so I can't put postList.getName() and getBody() in an intent, but I think it would be okay if my onClick() can go inside the firebase block itself, here:
FirebaseRecyclerAdapter mAdapter = new FirebaseRecyclerAdapter<PostList, PostHolder>(PostList.class, R.layout.row_one, PostHolder.class, postRef) {
#Override
public void populateViewHolder(PostHolder postViewHolder, PostList postList, int position) {
//try catch block to catch events of no posts, it will most likely return a null error, so im catching it, else
//find its exception and catch it
try {
String firstname = postList.getFirstname();
String lastname = postList.getLastname();
firstname = firstname.substring(0, 1).toUpperCase() + firstname.substring(1); //convert first string to uppercase
lastname = lastname.substring(0, 1).toUpperCase() + lastname.substring(1);// same thing happening here
String name = (firstname + " " + lastname); // concatenate firstname and lastname variable.
postViewHolder.setName(name);
postViewHolder.setText(postList.getBody()); // set the vew holder
//note that picasso view holder was applied in the view holder instead
String image = postList.getImgUrl().toString();
postViewHolder.setImage(image);
findViewById(R.id.progressBar3).setVisibility(View.GONE);
}
catch(NullPointerException e) {
findViewById(R.id.nopost).setVisibility(View.VISIBLE);
}
}
//onclick goes here with all the put extra and startactivity stuff
};
recycler.setAdapter(mAdapter);
You mean that you cannot get the origin activity to create the intent? have you tried getContext(), getActivity() or getBaseContext()?
Context context = getContext();
final Intent intent = new Intent(context, FirstActivity.class);
// all your stuff
context.startActivity(intent);
If you want to perform good item click functionality with a proper way then create a separate class for FirebaseRecyclerAdapter and use Interface as item click listener so you can perform intent functionality from HomeActivity.
OR
Create reference of HomeActivity class and use that reference at
#Override
public void onClick(View mView) {
//what to do here
//mcontect will be your class reference
Intent i = new (mcontext,SecondActivity.class);
startActivity(i);
}
I have the following RecyclerView adapter in place. It's working fine to display the items however I want to pass arguments to a Dialog or Fragment when I click one of the items:
public class NovaAdapter extends RecyclerView.Adapter<NovaListRowHolder> {
ArrayList<HashMap<String, String>> novaList = new ArrayList<HashMap<String, String>>();
public static final String STATUS = "status";
public static final String NAME = "name";
public static final String ID = "id";
private Context mContext;
public NovaAdapter(Context context, ArrayList<HashMap<String, String>> novaList) {
this.novaList = novaList;
this.mContext = context;
}
#Override
public NovaListRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.instances_list, null);
NovaListRowHolder mh = new NovaListRowHolder(v);
return mh;
}
#Override
public void onBindViewHolder(NovaListRowHolder novaListRowHolder, int i) {
HashMap<String, String> e = novaList.get(i);
novaListRowHolder.name.setText(e.get(NAME));
novaListRowHolder.status.setText(e.get(STATUS));
novaListRowHolder.setId(e.get(ID));
}
#Override
public int getItemCount() {
return (null != novaList ? novaList.size() : 0);
}class NovaListRowHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
protected TextView name;
protected TextView status;
protected String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public NovaListRowHolder(View view) {
super(view);
view.setOnClickListener(this);
this.name = (TextView) view.findViewById(R.id.nameInstance);
this.status = (TextView) view.findViewById(R.id.statusInstance);
}
public void onClick(View view){
Dialog dialog = new Dialog(view.getContext());
dialog.setContentView(R.layout.instances_listdetail);
dialog.setTitle("Details " + name.getText() + " " + getPosition());
dialog.show();
}
At the moment the click is only opening a placeholder dialog but it isn't passing any data. I tried to search everywhere for examples or tutorials on how to do it but didn't find it anywhere.
Sorry in advance it it's too obvious but it's my first app and I don't have much experience.
You should set the onClickListener in onBindViewHolder to each of the views. You can access the itemView directly from your viewHolder.
Now you can set a tag (or a few) to the view with the click listener, and retrieve them inside your onClick method.
If you need to pass values from recycler view to dialog means then use this
code of onBindViewHolder
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Offers offers = offersList.get(position);
holder.topic.setText(offers.getTopic());
holder.expiry.setText(offers.getExpiry());
}
Simply pass the values of by setText
//TextView inside dialog
offers_dialog_topic = (TextView) dialog.findViewById(R.id.offers_dialog_offer_type);
date_year = (TextView) dialog.findViewById(R.id.date_year);
offers_dialog_topic.setText(topic.getText().toString());
date_year.setText(expiry.getText().toString());
Hope this helps for other.
Thank you.