new version explan: http://litotom.com/2016/05/20/2016-firebase/
we want to buld a shopping App
Create a App on fire base
Connect to Firebase
1.
dependencies {
compile 'com.firebase:firebase-client-android:2.3.1+'
and
add the below because need to exclude the duplicate file
android {
...
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE-FIREBASE.txt'
exclude 'META-INF/NOTICE'
}
}
|
2
<uses-permission android:name="android.permission.INTERNET" />
|
3.
onCreate in ShoppingListApplication.java
public class ShoppingListApplication extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
Firebase.setAndroidContext(this);
// other setup code
}
}
|
4.do if you want to share the code on the github,and dpn’t want other people lnow your URL
in program
public static final String FIREBASE_URL= BuildConfig.UNIQUE_FIREBASE_ROOT_URL;
|
app gradle
buildTypes.each{
it.buildConfigField 'String','UNIQUE_FIREBASE_ROOT_URL' , UniqueFIREBaseRootUrl
}
|
grandle.properties
UniqueFIREBaseRootUrl="https://shopistplusplus-po.firebaseio.com/"
|
Write value to the Firbase
the data save in Firebase use key-value pair
Now,we want to cretae a Lista name and save on Firebase
in AddListDialogFragment
public void addShoppingList() {
Firebase ref=new Firebase(Constants.FIREBASE_URL);
ref.child("listName").setValue(mEditTextListName.getText().toString());
}
|
Finally,we can see the value on yhe Firebase data base
no need any async task and deal with thread!!!
Firebase Data Basics
save as Json:
each key has its own link.
Firebase Terminology
Firebase Database - This entire JSON object which is part of the Firebase app backend.
Key - A node name or key in Firebase. It is on the left of it's value.
List, Map, Collection - A key/value pair that has multiple children.
Location - URL location of a node in the Firebase database.
Node - A specific location that has a key/value pair.
Object - A key value pair that represents a key and all the data in an analogous Java object.
Property - A key/value pair that holds a single value.
Root Node - The top level node of a Firebase database. Its' location will be your base Firebase URL (the url you see when you first click on your Firebase App Backend).
Value - The actual value of a certain location in the Firebase database. This can be a string, number, boolean or a Firebase object.
Get dat from the database
Concpet
Firebase use listen method.
choose a node to listen
listen at B,E change, also sent to the other device
Code:
Firebase listNameRef = new Firebase(Constants.FIREBASE_URL).child("listName");
listNameRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
String name = (String) dataSnapshot.getValue();
mTextViewListName.setText(name);
}
@Override
public void onCancelled(FirebaseError firebaseError) {
}
});
|
explain .
add a listener to a node
when data change on this Node,onDataChange call
and will get the dataSnapshot
from the data scapshot,we got the value,and other information of the database start from the node we listen
Save a object on a Fire Base database
very not good
use Plain Old Java Objects
example:
public class ShoopingList {
String listname;
String owner;
public ShoopingList() {
}
public ShoopingList(String listname, String owner) {
listname = listname;
this.owner = owner;
}
public String getListname() {
return listname;
}
public String getOwner() {
return owner;
}
}
|
change the add Shop List
public void addShoppingList() {
Firebase ref = new Firebase(Constants.FIREBASE_URL);
String userEnterdName = mEditTextListName.getText().toString();
ShoopingList shoplist = new ShoopingList(userEnterdName, "AnonymousName");
ref.child("activeList").setValue(shoplist);
}
|
cahnge the read code
ShoopingList shoopinglist = dataSnapshot.getValue(ShoopingList.class);
mTextViewListName.setText(shoopinglist.getListname());
|
get back the ShoopingList object
in ShoppingListsFragment
public void onDataChange(DataSnapshot dataSnapshot) {
ShoopingList shoopinglist = dataSnapshot.getValue(ShoopingList.class);
mTextViewListName.setText(shoopinglist.getListname());
mTextViewCreatedBy.setText(shoopinglist.getOwner());
}
private void initializeScreen(View rootView) {
mListView = (ListView) rootView.findViewById(R.id.list_view_active_lists);
mTextViewListName = (TextView) rootView.findViewById(R.id.text_view_list_name);
mTextViewCreatedBy = (TextView) rootView.findViewById(R.id.text_view_created_by_user);
}
|
EX1 add Last Edited Timestamp Field Spec
notes
Use ServerValue.TIMESTAMP
Whenever you're trying to set the "current time" on Firebase you should pass Firebase the Map constant ServerValue.TIMESTAMP. When Firebase receives this map, it changes it to a long value representing the current time the data was recieved and saved in Firebase. You might be wondering why you shouldn't just get the time from the client. If you use a time you take from the client (such as a value from the Calendar class) it will always be the time that the data was sent from the client. Since the time it takes for data to travel from the client to server can vary wildly depending on the client's internet connection, the client side timestamp can be pretty inaccurate in relation to when the data was actually recorded in the server. For more information about ServerValue.TIMESTAMP you can read about it in the docs.
How to Use ServerValue.TIMESTAMP
Using ServerValue.TIMESTAMP in a POJO is currently not trivial. This is because the timestamp is passed into Firebase as a HashMap but it is converted to a long value on the server. This Stackoverflow post I wrote describes the issue in details and provides sample code which you can base your answer off of.
Code Snippets
You can use R.id.text_view_edit_time in the single_active_list.xml layout.
In the Utils there is a SimpleDateFormat constant Utils.SIMPLE_DATE_FORMAT that you can use to format the timestamp to be something human readible.
|
Now ,we wnat to add the detail screen:
V 0.2.01 Add The Detail Screen
Main Goal
Add a Shopping List details screen to the app. This screen should display a single Shopping List object's information.
Specifications
Connect the ShoppingListsFragment and the ActiveListDetailsActivity so that when you click the text of the shopping list name in ShoppingListsFragment, it launches ActiveListDetailsActivity.
The ActiveListDetailsActivity should then make a listener so that you can load up the shopping list object from the Firebase database, into ActiveListDetailsActivity.
Using the data from the ShoppingList POJO, you should set the title of the activity to the list name, as seen below.
Steps
Add the following constants to Constants
Refactor the hardcoded String "active_lists" with the constant FIREBASE_LOCATION_ACTIVE_LIST.
Add an OnClick listener in ShoppingListsFragment so that when the user clicks on the mTextViewListName it opens up an instance of ActiveListDetailsActivity.
Add the Firebase code in ActiveListsDetailsActivity that will set the appropriate title for the detail screen using setTitle and passing in the name of the current shopping list. You might want to save this shopping list as well. You can but theinvalidateOptionsMenu call inside of the same block of code. If the shopping list doesn't exist, close the activity usingfinish().
Wireframes
Hints and Tips
First, just write the Android code to open up the activity. This is pure Android java code; there is no Firebase code.
You should only be reading from the Firebase database. There's no writing involved.
The Firebase query will look very similar to the Firebase query you used to display information in theShoppingListsFragment.
If you need a refresher on how to read data from Firebase, go back to where you did that in version 0.1.
|
The 5 Write Methods
setValue( )
|
Write or replace data to a defined path, like messages/users/<username>
|
updateChildren( )
|
Update some of the keys for a defined path without replacing all of the data
|
push( )
|
Add to a list of data in your Firebase database. Every time you call push() Firebase generates a unique ID, like messages/users/<unique-user-id>/<username>
|
runTransaction( )
|
Use our transactions feature when working with complex data that could be corrupted by concurrent updates
|
Edit Shopping List Name
only list name and time stamplast will change
Using updateChildren
Using updateChildren
As mentioned you can use updateChildren to update the shopping list name. To do this you can either update a POJO for update via a hash map. In general it is better and recommended to stick to POJOs because it is easy to accidentally malform data when using hash maps. But when dealing with ServerValue.TIMESTAMP, you might find yourself needing to explicitly create a HashMap. When you have multiple "levels" of data in a hash map, you'll need to nest a hash map within a hash map. Here is how it would be done:
Firebase ref = new Firebase(Constants.FIREBASE_URL).child("movie1"); HashMap <String, Object> movieUpdatedProperties = new HashMap<>(); movieUpdatedProperties.put("movieName", "Eternal Sunshine of The Spotless Mind");
HashMap<String, Object> ratingsMap = new HashMap<>(); ratingsMap.put("MPAA", "R"); ratingsMap.put("India", "A"); ratingsMap.put("Germany", "12");
movieUpdatedProperties.put("ratings", ratingsMap); ref.updateChildren(movieUpdatedProperties);
becomes...
|
Exercise of update Children
V 0.2.03 Edit the List Name
Main Goal
Let the user edit the name of a shopping list on the shopping list details screen.
Specifications
When the user presses the white edit icon, a dialog should appear (I've already coded this for you).
Change the EditListNameDialogFragment so that when the user opens the dialog, it shows the current list name.
When the user presses the Edit Name button, if the name has changed and is not empty, write the new name to the Firebase Database ShoppingList object, using updateChildren.
At the same time, update the timestampLastChanged value to the current time on the server.
Steps
Add the following to Constants:
Add any values you need in EditListNameDialogFragment newInstance() from the shopping list to make this change. Once you put a value in the bundle, it available to you in onCreate
Extract any arguments you put in the bundle when the newInstance method created the dialog. You can store these in an instance variable so that are available to you.
You can use the helper method in the superclass I made EditListDialogFragment called helpSetDefaultValueEditText. This will allow you to set what text the user sees when the dialog opens.
Do the actual edit operation in the doListEdit() method.Remember, you need to update the timestampLastChanged for the shopping list.
Wireframes
Technical Notes
Using updateChildren
As mentioned you can use updateChildren to update the shopping list name. To do this you can either update a POJO for update via a hash map. In general it is better and recommended to stick to POJOs because it is easy to accidentally malform data when using hash maps. But when dealing with ServerValue.TIMESTAMP, you might find yourself needing to explicitly create a HashMap. When you have multiple "levels" of data in a hash map, you'll need to nest a hash map within a hash map. Here is how it would be done:
Firebase ref = new Firebase(Constants.FIREBASE_URL).child("movie1"); HashMap <String, Object> movieUpdatedProperties = new HashMap<>(); movieUpdatedProperties.put("movieName", "Eternal Sunshine of The Spotless Mind");
HashMap<String, Object> ratingsMap = new HashMap<>(); ratingsMap.put("MPAA", "R"); ratingsMap.put("India", "A"); ratingsMap.put("Germany", "12");
movieUpdatedProperties.put("ratings", ratingsMap); ref.updateChildren(movieUpdatedProperties);
becomes...
Learn about ServerValue.TIMESTAMP
The Java constant Firebase.ServerValue.TIMESTAMP, gives the exact time when the data reaches and is stored in the server. This is used for the timestampLastChanged variable. You should read up on its' usage in the first On Your Own activity from version 0.1.
Hints and Tips
You can check whether the name is valid (not empty and has changed) on the client side, before writing anything to Firebase.
EditListNameDialogFragment extends EditListDialogFragment which has a method calledhelpSetDefaultValueEditText. helpSetDefaultValueEditText takes a string and displays it when the user opens the dialog. You’ll want to pass in the original list name.
To get the original list name, you’ll want it available to you within the EditListDialogFragment - you can pass it in when you call newInstance.
|
Completion Callbacks
the data save or not?
Have Differenet List
how ?
because push can :
Add to a list of data in your Firebase database. Every time you call push() Firebase generates a unique ID, like messages/users/<unique-user-id>/<username>
What does push do?
it only gererated the key,show we need to use set to add the value
The code of implement the push
Firebase ref = new Firebase(Constants.FIREBASE_URL);
ref.child(“activeLists”).push().setValue(new ShopplisgList()).
//the ShopplisgList is a object that content a the list name an other property
|
EX Add a New Shopping List
V 0.2.05 Add a New Shopping List
Main Goal
When the user presses the green + button to add a new list, it should create an entirely new list and add it to a list of shopping lists in the Firebase database. These lists should keep track of when they were created.
Specifications
Use push() and setValueinstead of just setValue() in the ShoppingListFragment class to add a new shopping list.
Also, add the property timestampCreated to your object. This timestamp should be set once, when the list is made.
Steps
In Constants instead of using the location activeList, let's store the new lists under activeLists (plural). This will also keep the app from crashing since we're only updating the write portion.
Now that we have more than one list, in ShoppingList let's add an unchanging timestamp for when the list was created.
In AddListDialogFragment addShoppingList() you'll need to change the code in this method around to properly add a shopping list so that you may have more than one.
Data schema
When you're done the data schema should look something like this:
Technical Notes
How Push IDs are generated
If you're curious how push ids are generated, check out this informative Firebase blog post.
Hints and Tips
Code Snippets
Here is some generic code adding a Message POJO to a database, using push:
Firebase newRef = rootRef.push(); Message m = new Message("Lyla", "Hello World"); newPostRef.setValue(m);
|
read will have some problem
The 3 Ways to Add Read Listeners
addValueEventListener
addChildEventListener
addListenerForSingleValueEvent
addValueEventListener
it listener a node,if under the node,hsa any value changed(include the children),it resturn the whole node snapshot
addChildEventListener
addListenerForSingleValueEvent
almost equal to addValueEventListener,but only just make only one read
Conclusion of read and write
Event Guarantees in FireBase
1.Event and local state change
all chang do in yout app locally,will immediately fire event
eaample:
when A change to A1,will have a Event “A child node waschanged ready to fire, however there is no connectivity now,so can sed out.
when connectivity is reestablished,the event fire to the firebase database
2.Eventual consistency
3.event order
a single cient write 3 different in order,other client will receive the event in the same order
4.Vlue event trigger last
if listen for the same location
Debugging with Log Level Debug
public class ShoppingListApplication extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
/* Initialize Firebase */
Firebase.setAndroidContext(this);
Firebase.getDefaultConfig().setLogLevel(Logger.Level.DEBUG);
}
}
|
show the Log at debug level
05-04 21:28:14.188 3431-3431/com.udacity.firebase.shoppinglistplusplus I/AppCompatDelegate: The Activity's LayoutInflater already has a Factory installed so we can not install AppCompat's
05-04 21:28:14.267 3431-3453/com.udacity.firebase.shoppinglistplusplus W/EGL_emulation: eglSurfaceAttrib not implemented
05-04 21:28:14.267 3431-3453/com.udacity.firebase.shoppinglistplusplus W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0xa181e060, error=EGL_SUCCESS
05-04 21:28:20.320 3431-3457/com.udacity.firebase.shoppinglistplusplus D/RepoOperation: set: /activeLists/-KGvx6QlJsdnrbAZWp5H
05-04 21:28:20.320 3431-3457/com.udacity.firebase.shoppinglistplusplus D/DataOperation: set: /activeLists/-KGvx6QlJsdnrbAZWp5H {
listName=AKB
owner=Anonymous Owner
timestampCreated={
timestamp={.sv=timestamp}
}
timestampLastChanged={
timestamp={.sv=timestamp}
}
}
05-04 21:28:20.321 3431-3457/com.udacity.firebase.shoppinglistplusplus D/Connection: conn_1 - Sending data: {d={a=p, r=2, b={d={owner=Anonymous Owner, listName=AKB, timestampLastChanged={timestamp={.sv=timestamp}}, timestampCreated={timestamp={.sv=timestamp}}}, p=/activeLists/-KGvx6QlJsdnrbAZWp5H}}, t=d}
|
Firebase UI and Lists
has change,Firebase DB update the Firebase array,Firebase array notify dataset changed to the FirebaseLIst Adapter,FirebaseLIst Adapter control how to show the data in a list view
use FirebaseListAdapter
we need to overwite the populateView method
Important code
1.Create a layou file that use to show the iteam,R.layout.single_active_list
2. craete a adapter class extends FirebaseListAdapter<ShoppingList>
public class ActiveListAdapter extends FirebaseListAdapter<ShoppingList> {
/**
* Public constructor that initializes private instance variables when adapter is created
*/
public ActiveListAdapter(Activity activity, Class<ShoppingList> modelClass, int modelLayout,
Query ref) {
super(activity, modelClass, modelLayout, ref);
this.mActivity = activity;
}
/**
* Protected method that populates the view attached to the adapter (list_view_active_lists)
* with items inflated from single_active_list.xml
* populateView also handles data changes and updates the listView accordingly
*/
@Override
protected void populateView(View view, ShoppingList list) {
// TODO This is where you need to populate the single_active_list layout with
// the data in the current shopping list. It should be similar to what you
// were displaying in ShoppingListsFragment
TextView tvListName = (TextView) view.findViewById(R.id.text_view_list_name);
TextView tvCreatedbyName = (TextView) view.findViewById(R.id.text_view_created_by_user);
tvListName.setText(list.getListName());
tvCreatedbyName.setText(list.getOwner());
}
}
|
3.set the adapter to the List View
Firebase refListName = new Firebase(Constants.FIREBASE_URL).child(Constants.FIREBASE_LOCATION_ACTIVE_LISTS);
ActiveListAdapter adapter = new ActiveListAdapter(getActivity(), ShoppingList.class, R.layout.single_active_list, refListName);
mListView.setAdapter(adapter);
|
4. clean up when activity destory
@Override
protected void onDestroy() {
super.onDestroy();
adapter .cleanup();
}
|
EX Add a FirebaseListAdapter
V 0.2.07 Add a FirebaseListAdapter
Main Goal
Using the FirebaseUI library, add a list view containing all of the ShoppingLists in your Firebase database.
Specifications
Install the library Add the following library to your app's build.gradle file compile 'com.firebaseui:firebase-ui:0.2.2'
Setup the list view Delete the layout single_active_list included in the fragment_shopping_lists.xml layout as well as the TextView used in ShoppingListsFragment. This was just for displaying the data in version 0.1, but you're transitioning to a List View now. You can use the List View with the id R.id.list_view_active_lists. It should already be stored in themListView in the ShoppingListsFragment class.
Add the layout I have included the layout in your project already. It's the same one you were using to show a single list, and it's called R.layout.single_active_list.
Add the Firebase Reference You should make a Firebase reference that points to the root location where all of your lists are.
Make the Adapter Make a new FirebaseListAdapter. I’ve made a new class called ActiveListAdapter which you can copy over into the package com.udacity.firebase.shoppinglistplusplus.ui.activeLists; package. This will get you started.
Populate View Remember, you also need to override the populateView method. You should setR.id.text_view_list_name and R.id.text_view_created_by_user and fill them in with the appropriate value from your shopping list object.
Wireframes
|
but now,it can’t click,think about why?
we can set a setOnItemClickListener to the Lisview,than get the ShoppingList object directly at the Detailactivity.
However !!!!
the tabkle like this now,if we want to get the shopping list object that have name “56565”,we need to know it s pushID.
How to get the pushID when using FirebaseListAdapter and Listview?
get the pushID when using FirebaseListAdapter and Listview
how
above as a example:
if we use activeList/activeLists as a location,the FirebaseListAdapter will get A array,every iteam in this array,Has a key(-KGzejwRKDQ8uksgcwUo) and a value (a shopping List object)
we can see FirebaseListAdapter has a method,call getRef(int position),can get back the FireBase at different position in the array,than use get Key get the key
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(getContext(), "Key" + " " + mActiveListAdapter.getRef(position).getKey(), Toast.LENGTH_SHORT).show();
|
EX
V 0.2.09 Send Over the Push ID
Main Goal
The user should be able to select any shopping list in the list view and then be taken to the detail screen for the shopping list they selected.
Specifications
Using intent extras, refactor the code so that when you click on an item, the ActiveListDetailsActivity opens with the correct data for the selected shopping list.
You should be able to edit the shopping list name on the details screen in the same way you could when you had a single active list.
Wireframes
Hints and Tips
Don’t be shy about passing around the push id to anything that edits a ShoppingList. The push id is necessary to create a Firebase reference object for a single shopping list and you need this reference object to do any sort of write operation.
To actually get the push ID, look at the different methods FirebaseListAdapter provides. You cannot directly get the push ID from the FirebaseListAdapter, but you can get an object that contains the push ID.
Remember, the push ID is the key of the shopping list.
SKIP TO QUIZ
Quiz: Send Over The Push ID Spec
SOLUTION - V 0.2.10 Send Over the Push ID
Main Goal
The user should be able to select any shopping list in the list view and then be taken to the detail screen for the shopping list they selected.
|
Remove A Shopping List
we only can remove the Shopping List from the Firebase database ,than the array hold by FireBase adapterFirebaseListAdapter will automatically sync to the Firebase database.Moreover,we have no method to access the array hold by the FirebaseListAdapter.
we call removeValue
Firebase ref = new Firebase(Constants.FIREBASE_URL_ACTIVE_LISTS).child(mListID);
ref.removeValue();
|
the value of -KGzesnSA4lZoAaU7dsC will delete
thevalue of -KGzesnSA4lZoAaU7dsC become null,show will will not see the key -KGzesnSA4lZoAaU7dsC in the table too!!!
EX
V 0.2.11 Remove a Shopping List
Main Goal
Add the ability to delete the shopping list from the list detail screen.
Specifications
Update the app so that when you click Remove list menu option, and then press the OK button in the dialog, it deletes the list.
If the list is deleted, you should be moved back to the MainActivity. Note if you’ve been following along with my code steps, it should automatically do this.
Wireframes
Hints and Tips
The code you edit will be in RemoveListDialogFragment
What listener in the ActiveListDetailsActivity will be triggered when you delete the list? What will the value of the shopping list be when it’s deleted?
SKIP TO QUIZ
|
The iteam
create the object to represent to Iteam
where to add the List item
A
B
Question:
answer is:
ShoppingListsFragment B,it is becasue ShoppingListsFragment only need the Shopping list information ,use B will get little information sent from server to app.If it use A, the data that sent form server to app will more.
ActivelistDetailsActivity A,it is because it need the information the list and list iteam,if use B, need to add tow listener.
Overall,we should use B,it is becasue if the data is very big,the bad effect for send big data form FireBase database to app is bigger than add two listener,the listener is light.
Add Items to the List Spec
V 0.2.15 Add Items to the List Detail Screen
Main Goal
Any user can add items, which are associated with a specific shopping list, to the Firebase database. These items are displayed on the Shopping List Details screen.
Specifications
When pressing the plus button on the details screen, you should be able to add an item to the list in Firebase. (See Technical Notes below for information on how to correctly do this)
Every list of items will share a push id with the shopping list they are associated with. (See the Data Schema below)
You should use FirebaseListAdapter to show the items in the list. I’ve made a subclass of FirebaseListAdapter calledActiveListItemAdapter that you can copy to get started. It includes the commented out code for a dialog fragment that appears when you click the trashcan icon. You should use the layout I’ve provided you with as well, which isR.layout.single_active_list_item.
When you remove the list, you should also remove the list items. (See Technical Notes below for information on how to correctly do this)
Wireframes
Data Schema
When you're done the data schema should look something like this:
Technical Notes
Atomic Writes and Using ObjectMapper
For consistency, you might want to update multiple places in your Firebase database, all at the exact same momement. This is known as an atomic write, because all the locations in our database are updated at the same time and the write command is sent as one operation to the server. This is superior to calling setValue multiple times. This is because there is a small chance that something will happen when you're calling setValue multiple times (such as your phone losing internet connectivity) and that not all operations will make it to the database. This would cause data inconsistency.
Updating data in multiple location in a database automically can be done using the updateChildren method, as described here.updateChildren, though, currently doesn't support POJO's in the same way setValue does. Therefore, I have a work around that allows us to convert POJOs into Maps so that they can be used as part of a call to updateChildren. This uses Jackson'sObjectMapper class, which provides an easy way to convert a POJO style objects into Maps. Here is an example:
Message chatMessagePOJO = new Message("Lyla", "Hello World"); HashMap<String, Object> chatMessageMap = (HashMap<String, Object>) new ObjectMapper().convertValue(chatMessagePOJO, Map.class);
Once you've converted the data to a Map, it can be added to the HashMap passed to updateChildren. Note that if it's possible to do so without creating potential inconsistency issues, passing a POJO using setValue is always preferable to doing this conversion,
Passing Null to setValue and updateChildren
Note that passing null to setValue and updateChildren remove the value at that location. It is essentially the same as callingremoveValue.
Hints and Tips
SKIP TO QUIZ
|
Remove Event Listeners
why?if not remove,will make the phone warm,slow,memory lake.
list adapter need to be clean up
remove at onDestroy
mActiveListRefListener = mActiveListRef.addValueEventListener(new ValueEventListener() {
|
Firebase authenciation
can use above acount to login
or
use emaill and password to login
when login, a Token will create
The below is the Authentication
createUser is create a new account with emaill and password
Enable Email and Password Login Provider
Create a user with email and password
when success lohgin,onSuccess excute,but we should not log in the use here,we should have a sperate activity to do that.
if login has error,onError will execute.
the error list:
the code that create a account with Email and password
Create a progress a dialog
mAuthProgressDialog mAuthProgressDialog = new ProgressDialog(this);
mAuthProgressDialog.setTitle(getString(R.string.progress_dialog_loading));
mAuthProgressDialog.setMessage(getString(R.string.progress_dialog_authenticating_with_firebase));
mAuthProgressDialog.setCancelable(false);
//show it
mAuthProgressDialog.show();
// dismiss it
mAuthProgressDialog.dismiss();
|
Check the input erro at the client side
email:
boolean isEmailValid(CharSequence email) {
return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches();
}
|
user name:
password:
TextView set error
mEditTextUsernameCreate.setError("Name should not empty");
|
Creat the user
Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.createUser("bobtony@firebase.com", "correcthorsebatterystaple", new Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.createUser("bobtony@firebase.com", "correcthorsebatterystaple", new Firebase.ValueResultHandler<Map<String, Object>>() {
@Override
public void onSuccess(Map<String, Object> result) {
System.out.println("Successfully created user account with uid: " + result.get("uid"));
}
@Override
public void onError(FirebaseError firebaseError) {
// there was an error
}
});
|
EX
V 0.3.01 Create a Firebase User
Main Goal
Finish the Create Account screen by adding the functionality to create a new user in the Firebase credentials store using Firebase's email and password provider.
Specifications
When the user clicks the "Create Account" button, use the createUser code to make a new user in the Firebase system.
Show a progress dialog between when you try to create the user and when the server responds with onError or onSuccess.
Check that the password is at least 5 characters long and that the email is in the format of an email (see below for how).
The new user should have the email and password that the user entered.
If there is an error in creating the account because the email or password is not accepted or because the email is already taken, display a helpful error message
You should also display a more generic error message if onError is triggered by createUser.
Wireframes
Technical Notes
Make sure you Enable to Email and Password provider
If you haven't already, enable email and password login. Click here if you need help.
Use Google's Patterns to Match the email address
Check that the email matches Google's Patterns.EMAIL_ADDRESS. This should be a client side check that is done before any Firebase code.
setError
TextView's setError is a good way to visually show the user if something they typed in a EditText is wrong.
Hints and Tips
Error checking for the email and password should be a client side check that is done before any Firebase code.
The code you need to edit can be found in CreateAccountActivity.java.
Consider making a method checkPassword and checkEmail which takes in the password/email and returns true or false depending on whether it is acceptably written.
Code Snippets
Here is some generic user creation code:
Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com"); ref.createUser("bobtony@firebase.com", "correcthorsebatterystaple", new Firebase.ValueResultHandler<Map<String, Object>>() { @Override public void onSuccess(Map<String, Object> result) { System.out.println("Successfully created user account with uid: " + result.get("uid")); }
@Override public void onError(FirebaseError firebaseError) { // there was an error } });
|
Logging In
Overview
we nly need to do is call authWithPasseord() and get thr AuthData object,other is do by Firease
code in login
some useful method in AuthData
getProvider told whick method to login,google,facengithub?
In code :Logging In
Firebase ref = new Firebase(Constants.FIREBASE_URL);
ref.authWithPassword(email, password, new Firebase.AuthResultHandler() {
@Override
public void onAuthenticated(AuthData authData) {
mAuthProgressDialog.dismiss();
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
startActivity(intent);
}
@Override
public void onAuthenticationError(FirebaseError firebaseError) {
mAuthProgressDialog.dismiss();
Snackbar.make(activityloginLayout, firebaseError.getMessage(), Snackbar.LENGTH_SHORT).show();
}
});
|
EX:Log the user into Firebase using the Email and Password Provider.
V 0.3.03 Logging In
Main Goal
Log the user into Firebase using the Email and Password Provider.
Specifications
Log in the user in Firebase when they press Sign In on the LoginActivity screen.
Display an error message either on the associated EditText or as a toast (if there is no associated EditText) for the following situations:
There is no connection
The email is invalid
The user does not exist
The password is invalid
The password or email is empty (this should be checked client side)
When the user is sucessfully logged in, they should be taken to the MainActivity. If they press the back button, it should nottake them to the login page; we’ll implement logout later.
Wireframes
Hints and Tips
Code Snippets
Generic login code:
Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com"); ref.authWithPassword("bobtony@firebase.com", "correcthorsebatterystaple", new Firebase.AuthResultHandler() { @Override public void onAuthenticated(AuthData authData) { System.out.println("User ID: " + authData.getUid() + ", Provider: " + authData.getProvider()); }
@Override public void onAuthenticationError(FirebaseError firebaseError) { // there was an error } });
|
Log in with Google+
Configuring Google Login
Let's walk through how to set up Google login. To incorperate Google login, you'll do two things. First is to make a configuration file for your project (this involves making a "Google App" and passing along a Android Sigining Certificate). Then you will go into the Firebase backend and give it the Client ID for you new Google application.
Generate the google-services.json Configuration File
Follow the first half of the instructions on the Google Developer webpage to get a google-services configuration file. You will need to:
Ensure you have all the prerequisites listed.
Create a configuration file :
Create an app on Google.
Add an Android Signing Certificate SHA-1 so that you can use Google Sign-In.
Download the google-services.json configuration file.
Add the configuration file to your project.
After you are done adding the configuration file, you do NOT need to complete the other steps on the Google Developer webpage. You can move to the next section, "Add the Client ID to Firebase" now.
Add the Client ID to Firebase
Next, as described in the Firebase Google login documentation, head on over to the Login & Authsection in your App Dashboard. Enable Google authentication and then copy your Google application Client ID into the Firebase.
|
Goal:
codee:
Gradle File
classpath 'com.google.gms:google-services:1.5.0'
|
add the plugin to your app-level build.gradle:
apply plugin: 'com.google.gms.google-services'
|
Then in your app-level build.gradle file, declare Google Play Services as a dependency:
apply plugin: 'com.android.application'
...
dependencies {
compile 'com.google.android.gms:play-services:7.5.0'
}
|
Update the Manifest File
In your AndroidManifest.xml add the following permissions.
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
/**
* Represents Sign in screen and functionality of the app
*/
public class LoginActivity extends BaseActivity {
private static final String LOG_TAG = LoginActivity.class.getSimpleName();
/* A dialog that is presented until the Firebase authentication finished. */
private ProgressDialog mAuthProgressDialog;
/* References to the Firebase */
private Firebase mFirebaseRef;
private EditText mEditTextEmailInput, mEditTextPasswordInput;
/**
* Variables related to Google Login
*/
/* A flag indicating that a PendingIntent is in progress and prevents us from starting further intents. */
private boolean mGoogleIntentInProgress;
/* Request code used to invoke sign in user interactions for Google+ */
public static final int RC_GOOGLE_LOGIN = 1;
/* A Google account object that is populated if the user signs in with Google */
GoogleSignInAccount mGoogleAccount;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
/**
* Create Firebase references
*/
mFirebaseRef = new Firebase(Constants.FIREBASE_URL);
/**
* Link layout elements from XML and setup progress dialog
*/
initializeScreen();
/**
* Call signInPassword() when user taps "Done" keyboard action
*/
mEditTextPasswordInput.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
if (actionId == EditorInfo.IME_ACTION_DONE || keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
signInPassword();
}
return true;
}
});
}
@Override
protected void onResume() {
super.onResume();
}
@Override
public void onPause() {
super.onPause();
}
/**
* Override onCreateOptionsMenu to inflate nothing
*
* @param menu The menu with which nothing will happen
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
/**
* Sign in with Password provider when user clicks sign in button
*/
public void onSignInPressed(View view) {
signInPassword();
}
/**
* Open CreateAccountActivity when user taps on "Sign up" TextView
*/
public void onSignUpPressed(View view) {
Intent intent = new Intent(LoginActivity.this, CreateAccountActivity.class);
startActivity(intent);
}
/**
* Link layout elements from XML and setup the progress dialog
*/
public void initializeScreen() {
mEditTextEmailInput = (EditText) findViewById(R.id.edit_text_email);
mEditTextPasswordInput = (EditText) findViewById(R.id.edit_text_password);
LinearLayout linearLayoutLoginActivity = (LinearLayout) findViewById(R.id.linear_layout_login_activity);
initializeBackground(linearLayoutLoginActivity);
/* Setup the progress dialog that is displayed later when authenticating with Firebase */
mAuthProgressDialog = new ProgressDialog(this);
mAuthProgressDialog.setTitle(getString(R.string.progress_dialog_loading));
mAuthProgressDialog.setMessage(getString(R.string.progress_dialog_authenticating_with_firebase));
mAuthProgressDialog.setCancelable(false);
/* Setup Google Sign In */
setupGoogleSignIn();
}
/**
* Sign in with Password provider (used when user taps "Done" action on keyboard)
*/
public void signInPassword() {
String email = mEditTextEmailInput.getText().toString();
String password = mEditTextPasswordInput.getText().toString();
/**
* If email and password are not empty show progress dialog and try to authenticate
*/
if (email.equals("")) {
mEditTextEmailInput.setError(getString(R.string.error_cannot_be_empty));
return;
}
if (password.equals("")) {
mEditTextPasswordInput.setError(getString(R.string.error_cannot_be_empty));
return;
}
mAuthProgressDialog.show();
mFirebaseRef.authWithPassword(email, password, new MyAuthResultHandler(Constants.PASSWORD_PROVIDER));
}
/**
* Handle user authentication that was initiated with mFirebaseRef.authWithPassword
* or mFirebaseRef.authWithOAuthToken
*/
private class MyAuthResultHandler implements Firebase.AuthResultHandler {
private final String provider;
public MyAuthResultHandler(String provider) {
this.provider = provider;
}
/**
* On successful authentication call setAuthenticatedUser if it was not already
* called in
*/
@Override
public void onAuthenticated(AuthData authData) {
mAuthProgressDialog.dismiss();
Log.i(LOG_TAG, provider + " " + getString(R.string.log_message_auth_successful));
if (authData != null) {
/* Go to main activity */
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
}
}
@Override
public void onAuthenticationError(FirebaseError firebaseError) {
mAuthProgressDialog.dismiss();
/**
* Use utility method to check the network connection state
* Show "No network connection" if there is no connection
* Show Firebase specific error message otherwise
*/
switch (firebaseError.getCode()) {
case FirebaseError.INVALID_EMAIL:
case FirebaseError.USER_DOES_NOT_EXIST:
mEditTextEmailInput.setError(getString(R.string.error_message_email_issue));
break;
case FirebaseError.INVALID_PASSWORD:
mEditTextPasswordInput.setError(firebaseError.getMessage());
break;
case FirebaseError.NETWORK_ERROR:
showErrorToast(getString(R.string.error_message_failed_sign_in_no_network));
break;
default:
showErrorToast(firebaseError.toString());
}
}
}
/**
* Helper method that makes sure a user is created if the user
* logs in with Firebase's email/password provider.
*
* @param authData AuthData object returned from onAuthenticated
*/
private void setAuthenticatedUserPasswordProvider(AuthData authData) {
}
/**
* Helper method that makes sure a user is created if the user
* logs in with Firebase's Google login provider.
*
* @param authData AuthData object returned from onAuthenticated
*/
private void setAuthenticatedUserGoogle(AuthData authData) {
}
/**
* Show error toast to users
*/
private void showErrorToast(String message) {
Toast.makeText(LoginActivity.this, message, Toast.LENGTH_LONG).show();
}
/**
* Signs you into ShoppingList++ using the Google Login Provider
*
* @param token A Google OAuth access token returned from Google
*/
private void loginWithGoogle(String token) {
// TODO This method gets called once the "boiler plate" code below gets a token
// from google. Use this token and a specific Firebase method to login the user
// with google.
}
/**
* GOOGLE SIGN IN CODE
*
* This code is mostly boiler plate from
* https://developers.google.com/identity/sign-in/android/start-integrating
* and
* https://github.com/googlesamples/google-services/blob/master/android/signin/app/src/main/java/com/google/samples/quickstart/signin/SignInActivity.java
*
* The big picture steps are:
* 1. User clicks the sign in with Google button
* 2. An intent is started for sign in.
* - If the connection fails it is caught in the onConnectionFailed callback
* - If it finishes, onActivityResult is called with the correct request code.
* 3. If the sign in was successful, set the mGoogleAccount to the current account and
* then call get GoogleOAuthTokenAndLogin
* 4. getGoogleOAuthTokenAndLogin launches an AsyncTask to get an OAuth2 token from Google.
* 5. Once this token is retrieved it is available to you in the onPostExecute method of
* the AsyncTask. **This is the token required by Firebase**
*/
/* Sets up the Google Sign In Button : https://developers.google.com/android/reference/com/google/android/gms/common/SignInButton */
private void setupGoogleSignIn() {
SignInButton signInButton = (SignInButton)findViewById(R.id.login_with_google);
signInButton.setSize(SignInButton.SIZE_WIDE);
signInButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onSignInGooglePressed(v);
}
});
}
/**
* Sign in with Google plus when user clicks "Sign in with Google" textView (button)
*/
public void onSignInGooglePressed(View view) {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_GOOGLE_LOGIN);
mAuthProgressDialog.show();
}
@Override
public void onConnectionFailed(ConnectionResult result) {
/**
* An unresolvable error has occurred and Google APIs (including Sign-In) will not
* be available.
*/
mAuthProgressDialog.dismiss();
showErrorToast(result.toString());
}
/**
* This callback is triggered when any startActivityForResult finishes. The requestCode maps to
* the value passed into startActivityForResult.
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
/* Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...); */
if (requestCode == RC_GOOGLE_LOGIN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
handleSignInResult(result);
}
}
private void handleSignInResult(GoogleSignInResult result) {
Log.d(LOG_TAG, "handleSignInResult:" + result.isSuccess());
if (result.isSuccess()) {
/* Signed in successfully, get the OAuth token */
mGoogleAccount = result.getSignInAccount();
getGoogleOAuthTokenAndLogin();
} else {
if (result.getStatus().getStatusCode() == GoogleSignInStatusCodes.SIGN_IN_CANCELLED) {
showErrorToast("The sign in was cancelled. Make sure you're connected to the internet and try again.");
} else {
showErrorToast("Error handling the sign in: " + result.getStatus().getStatusMessage());
}
mAuthProgressDialog.dismiss();
}
}
/**
* Gets the GoogleAuthToken and logs in.
*/
private void getGoogleOAuthTokenAndLogin() {
/* Get OAuth token in Background */
AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
String mErrorMessage = null;
@Override
protected String doInBackground(Void... params) {
String token = null;
try {
String scope = String.format(getString(R.string.oauth2_format), new Scope(Scopes.PROFILE)) + " email";
token = GoogleAuthUtil.getToken(LoginActivity.this, mGoogleAccount.getEmail(), scope);
} catch (IOException transientEx) {
/* Network or server error */
Log.e(LOG_TAG, getString(R.string.google_error_auth_with_google) + transientEx);
mErrorMessage = getString(R.string.google_error_network_error) + transientEx.getMessage();
} catch (UserRecoverableAuthException e) {
Log.w(LOG_TAG, getString(R.string.google_error_recoverable_oauth_error) + e.toString());
/* We probably need to ask for permissions, so start the intent if there is none pending */
if (!mGoogleIntentInProgress) {
mGoogleIntentInProgress = true;
Intent recover = e.getIntent();
startActivityForResult(recover, RC_GOOGLE_LOGIN);
}
} catch (GoogleAuthException authEx) {
/* The call is not ever expected to succeed assuming you have already verified that
* Google Play services is installed. */
Log.e(LOG_TAG, " " + authEx.getMessage(), authEx);
mErrorMessage = getString(R.string.google_error_auth_with_google) + authEx.getMessage();
}
return token;
}
@Override
protected void onPostExecute(String token) {
mAuthProgressDialog.dismiss();
if (token != null) {
/* Successfully got OAuth token, now login with Google */
loginWithGoogle(token);
} else if (mErrorMessage != null) {
showErrorToast(mErrorMessage);
}
}
};
task.execute();
}
}
|
sigin code
Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.authWithOAuthToken("google", "<OAuth Token>", new Firebase.AuthResultHandler() {
@Override
public void onAuthenticated(AuthData authData) {
// the Google user is now authenticated with your Firebase app
}
@Override
public void onAuthenticationError(FirebaseError firebaseError) {
// there was an error
}
});
|
EX Logging In with Google
V 0.3.05 Logging In with Google
Main Goal
Log the user into Firebase using the Google OAuth Provider.
Specifications
If you haven’t already, enable Google login. You can check out the instructions here.
Make a configuration file for your project as described here.
Update your gradle file. (See Code Snippets)
Update our manifest file. (See Code Snippets)
Log in the user in Firebase when they press sign in on the LoginActivity page using the oAuth token returned by theGoogleApiClient.
If there is a network error or the user is denied because of a permission, display a helpful error message as a Toast to the user.
Wireframes
Hints and Tips
Code Snippets
Updates to Gradle File
Add the dependency to your project's top-level build.gradle:
classpath 'com.google.gms:google-services:1.5.0'
Then add the plugin to your app-level build.gradle:
apply plugin: 'com.google.gms.google-services'
Then in your app-level build.gradle file, declare Google Play Services as a dependency:
apply plugin: 'com.android.application' ...
dependencies { compile 'com.google.android.gms:play-services:7.5.0' }
Update the Manifest File
In your AndroidManifest.xml add the following permissions.
<uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.USE_CREDENTIALS" />
Code for Google sign in
Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com"); ref.authWithOAuthToken("google", "<OAuth Token>", new Firebase.AuthResultHandler() { @Override public void onAuthenticated(AuthData authData) { // the Google user is now authenticated with your Firebase app }
@Override public void onAuthenticationError(FirebaseError firebaseError) { // there was an error } });
Firebase Example Code for Google Login
|
After login ,how can we get the user data(the AuthData object)
server mathod can get the AuthData object
1.AuthResultHandler.onAuthenticated(AuthData authData) {
this method can get the AuthData as soon as lohin.
but some time ,we will move to other activity in the app,so get use some time
2.Listerners,addAuthStateListener(),like the normal listener in firebase
rmoveAuthStateListener() to remove
when change,will call again
3.getAuth()
Store user data
the AuthData not store the all information of the user
It must only give the information in left side!!
so,we need to save the other user data in the firebase data base
Code:
User.java
public class User {
// TODO Create a user POJO with name, email and time joined.
private String email;
private String name;
private HashMap<String,Object> timestampJoined;
public User() {
}
public User(String email, String name) {
this.email = email;
this.name = name;
this.timestampJoined=new HashMap<>();
timestampJoined.put(Constants.FIREBASE_PROPERTY_TIMESTAMP, ServerValue.TIMESTAMP);
}
public String getEmail() {
return email;
}
public String getName() {
return name;
}
public Object getTimestampJoined() {
return timestampJoined;
}
}
|
get the user UID
mFirebaseRef.createUser(mUserEmail, mPassword, new Firebase.ValueResultHandler<Map<String, Object>>() {
@Override
public void onSuccess(Map<String, Object> result) {
/* Dismiss the progress dialog */
mAuthProgressDialog.dismiss();
Log.i(LOG_TAG, getString(R.string.log_message_auth_successful));
// TODO Use your User POJO to create the user data if they don't already exist.
// You can call the createUserInFirebaseHelper helper method and put
// the code for creating the user there.
String uid = result.get("uid").toString();
// Toast.makeText(CreateAccountActivity.this,uid,Toast.LENGTH_SHORT).show();
createUserInFirebaseHelper(uid);
}
|
use the UID to save the user and prevent the same user
final Firebase ref = new Firebase(Constants.FIREBASE_URL_SUSER).child(uid);
ref.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() == null) {
User user = new User(mUserEmail, mUserName);
ref.setValue(user);
}
}
@Override
public void onCancelled(FirebaseError firebaseError) {
}
});
|
Explain,first read the UID location,if the value is null,that mean no this user exist in the Database,so ,we can create this user and add it into the database
EX use email and password login,and save the use data
V 0.3.07 User Data for the Email and Password Provider
Main Goal
When a user is created in Firebase via the Email and Password provider, also create a user in our own Firebase database.
Specifications
Add a POJO for users that contains the user name, email and the date they joined.
Create user objects whenever a new user signs up with an email and a password.
The code should not create a user if one already exists.
WireFrames and Data Schema
Hints and Tips
|
The problem of Google provider and Email/Password provider use thsame Email
we should consider they were the same user
User Data Google Provider and create user
EX User Data for the Google Provider
When the same user use google account(with same email) login,will create another new user account in FireBase(Have different UID),we don’t want this, so we can use Email,the Gmail.All the use to use Email as a ID,Not the UID
However, here has a problem. The key can not have periods (.) . we can use “, ” to replace “.”
public static String encodeEmail(String userEmail) {
return userEmail.replace(".", ",");
}
|
V 0.3.09 User Data for the Google Provider
Main Goal
When a user logs in with Google via Firebase, also create a user in our own Firebase database.
Specifications
When a user logs in with either Google or email/password, check if a user for the associated email already exists. If not, make a new user.
The key of the user data should be the "encoded" email of the user (See Technical Notes and Code Snippets).
WireFrames and Data Schema
Technical Notes
Associating Multiple Login Services
If you want to read up more on the options for associating multiple login services, check out this Stackoverflow post.
Encoding the Email
Firebase does not support having periods within their key names. Because of this, storing the email address as a key is a little tricky. What you can do is a simple replace that turns all "." into ",". I'm calling this encoding the email. You can copy a gist for a method that will do this below.
Hints and Tips
Code Snippets
encodeEmail Utility Method
public static String encodeEmail(String userEmail) { return userEmail.replace(".", ","); }
SKIP TO QUIZ
|
need check is the google account connected?see the soultion
Logout and Kick Off in the FireBase
whta is Kickoff?
a user can’t log in forever,set at here
above picture is 24 hours,than kick off
what will happen after kick off?
Log out code
Listen to the AuthState change
Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.addAuthStateListener(new Firebase.AuthStateListener() {
@Override
public void onAuthStateChanged(AuthData authData) {
if (authData != null) {
// user is logged in
} else {
// user is not logged in
}
}
});
|
rember to remove the listener
public void onDestroy() {
// TODO don't forget to remove the auth listener!
ref.removeAuthStateListener(authListener);
super.onDestroy();
}
|
the code that log out if the provider is Google+,Signs out the current signed-in user if any. It also clears the account previously selected by the user and a future sign in attempt will require the user pick an account again.
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
+ new ResultCallback<Status>() {
+ @Override
+ public void onResult(Status status) {
+ //nothing
+ }
+ });
+ }
|
EX Logout and Kick Off
V 0.3.13 Logging Out and Kicking Off
Main Goal
Provide a login button to log the user out and automatically log the user out if they haven't logged in for a month.
Specifications
Set the session length to one month.
Show the logout button in the menu bar for MainActivity
If the user logs out either on their own volition or are kicked off of the system, it should immediately take the user back to theLoginActivity screen.
There should be no lingering user data in SharedPreferences if the user is not logged in.
Wireframes
Hints and Tips
Use onAuthenticationStateChange to see when the user is logged out.
Use unauth to log out the user.
The code for the authentication state change listener should happen on any activity that is not the LoginActivity orCreateAccountActivity. Remember that all activities in our app inherit from a BaseActivity.
Code Snippets
Snippet for an AuthStateListener:
Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com"); ref.addAuthStateListener(new Firebase.AuthStateListener() { @Override public void onAuthStateChanged(AuthData authData) { if (authData != null) { // user is logged in } else { // user is not logged in } } });
|
List Owner Permissions
we can login now,so we can know who is the user,van control who can modified the List now.
ex
V 0.3.15 List Owner Permissions
Main Goal
Only the owner should be able to see the menu for removing the list and the button for editing the name.
Specifications
Wireframes
Technical Notes
Firebase Rules and Permissions
Right now we are only talking about half of the steps you need to fully create user permissions. Here, you are editing the client side of the app. In version 0.5 of the app you'll be implementing server-side permissions using Firebase's robust Security and Permissions rules. These permissions will allow you to do things like make a user who is not the owner unable to remove lists or rename the shopping list, on the server side. In any production app, you'll need to do both client side UI changes and server side permissions. I'll come back to this in version 0.5, but if you're curiosity is piqued, you can check out the official docs.
Hints and Tips
|
Check Off Items
V 0.3.19 Check Off Items
Main Goal
Allow users to check off on un-check items that have been purchased.
Specifications
Update a ShoppingListItem to include whether it's been bought yet and who bought it.
Change the "bought" status of an item when a user clicks on it.
The look of an item should change when it's bought. If it's bought it should have:
If the item is unbought, it should have:
Unlike other changes to shopping lists, don't worry about changing the "timestampLastChanged" property. User tests showed that this is the most common action, and to cut down on the amount of data transfer, we won't update the timestampLastChanged property every time a user buys something.
Wireframes
Hints and Tips
Code Snippets
A strike through can be achieved with the following code:
textViewItemName.setPaintFlags(textViewItemName.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
It can be removed with:
textViewItemName.setPaintFlags(textViewItemName.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
SKIP TO QUIZ
|
Shopping Mode
V 0.3.21 Shopping Mode
Main Goal
Integrate a "Shopping Mode" that allows a user to signal that they are currently in the store. Users can only buy or unbuy items when "shopping".
Specifications
Implement a method for users to toggle in and out of shopping mode by pressing a button.
Make sure, client side, that only users in shopping mode can buy or unbuy items on a list. As mentioned in the Technical Notes of the List Owner Permissions Spec, you'll add server-side permissions in version 0.5.
When the current user enters shopping mode, style the green shopping icon differently and change the state of the activity to shopping mode. (See Code Snippets)
If a list changes, the current user's list must be updated in real time.
Wireframes
Hints and Tips
You should have some method for keeping track of users shopping on a specific list. To tell whether the current user is shopping you can then check if they are on the list of shopping users.
You can add a listener for the current user and keep this current user in an instance variable. This will allow you to easily add the current user as a "shopper" on a shopping list.
As such, remember to clean up additional listeners in ActiveListDetailsActivity.
Code Snippets
The following code can be used to correctly color the shopping mode button.
Shopping Mode Off
mButtonShopping.setBackgroundColor(ContextCompat.getColor(ActiveListDetailsActivity.this, R.color.dark_grey));
Shopping Mode On
mButtonShopping.setBackgroundColor(ContextCompat.getColor(ActiveListDetailsActivity.this, R.color.primary_dark))
|
Who's at the Store
V 0.3.23 Who's at the Store
Main Goal
Display users who are currently shopping on a shopping list.
Specifications
Show the users currently shopping.
If there is just one person shopping, say "X is shopping". If the current user is shopping, replace with "You are shopping."
If only two users are shopping, say "X and Y are shopping". Again, replace "X" with "You" if the current user is one of the shoppers.
If more than two users are shopping, say "X and N others are shopping". Again, replace "X" with "You" if the current user is one of the shoppers.
Wireframes
Hints and Tips
SKIP TO QUIZ
|
Structure the data scheme in FireBase
(sort ,query,filter,and share)
Sorting in Firebase
We can order data in four ways: by child key, by key name, by value, or by priority
example
{
"lambeosaurus": {
"height" : 2.1,
"length" : 12.5,
"weight": 5000
},
"stegosaurus": {
"height" : 4,
"length" : 9,
"weight" : 2500
}
}
|
orderByChild(key)()
order nodes by a common child key by passing that key to orderByChild()
For example, to read all dinosaurs ordered by height
orderByKey()
order nodes by their keys using the orderByKey() method
Ordering by value
We can order nodes by the value of their child keys using the orderByValue() method. Let's say the dinosaurs are having a dino sports competition
{
"scores": {
"bruhathkayosaurus" : 55,
"lambeosaurus" : 21,
"linhenykus" : 80,
"pterodactyl" : 93,
"stegosaurus" : 5,
"triceratops" : 22
}
}
|
Ordering by priority
not suggest to use
order of different value
only can sort by a key at a time
EX
important:PushiD is create by the time,so when we sort the push ID,it is the same with sort by create time.
answer:
code:
Firebase activeListsRef = new Firebase(Constants.FIREBASE_URL_ACTIVE_LISTS);
Query query3 = activeListsRef.orderByKey();
mActiveListAdapter = new ActiveListAdapter(getActivity(), ShoppingList.class,
R.layout.single_active_list, query3, mEncodedEmail);
|
EX Sorting with orderBy
V 0.4.01 Sorting with orderBy
Main Goal
Add the ability to open up a settings activity and change the default sort order of the shopping lists on theShoppingListsFragment screen.
Specifications
Add the SettingsActivity.java if you haven’t already, the code is provided here.
Show the sorting option on the MainActivity screen. This should open the SettingActivity.
Order "By Owner Email" using orderByChild. Make sure to select the right child key.
Order "By List Name" using orderByChild. Make sure to select the right child key.
Order "By Publish Time" using orderByKey.
Wireframes
Technical Notes
Performance Note
As a general tip, if you already have the required data, it is better to re-order that data client-side on the Android phone. This saves a query to the server. You should always be on the lookout for ways to minimize how many times you communicate with the Firebase database.
That said, we’re not doing this in the beta version of ShoppingList++ for a few reasons:
The FirebaseUI is a relatively new library that currently doesn't support client-side re-sorting on the fly.
It’s good to be exposed to the different sorting functionalities available with Firebase, even if this won’t make it into the production version of ShoppingList++.
Hints and Tips
Make sure to add the SettingsActivity to the AndroidManifest.
Make sure you've edited the following locations:
menu_main.xml - This is the file that determines what is shown in the app bar in MainActivity. Here you can make the white sort button appear.
onOptionsItemSelected - This method in MainActivity is where you react to the button presses in the app bar.
arrays.xml - This contains two arrays, one that determines what sort options are shown on screen, the other is the associated "value" which is returned.
Once you know what the user selected, you'll probably want to store it in SharedPreferences.
Once you have the correct query, you’ll need to change the query which the FirebaseListAdapter is listening on. In what Lifecycle method should you do this? The user will go to the SettingsActivity and then back to the MainActivity, at which point their list should be udpated.
Although this method is not as efficient as you could be (see Performance Note), I’d suggest just remaking the adapter when the query changes.
Make sure you clean up your adapter!
-
-
-
-
SKIP TO QUIZ
|
Separate Bought Items
can sort the true and false
V 0.4.03 Separate the bought and unbought items
Main Goal
Seperate the bought and unbought items in real time when users buy and unbuy items.
Specifications
Wireframes
Hints and Tips
You only need to do this once, when the FirebaseListAdapter is made.
Think about which of the four methods makes sense to use in this case. What are you sorting by?
-
-
-
|
Share the list and set the list privacy
Nests are Bad in non SQL database
soultion is denormalizing the data
for example
the above picture is the fatabase of a chat room
if we want to get the name of the room (dev team) of all the room,we also need to download the messages of the room,this will be very big data
improved
message is save in a sperate table
Tips to structure the database
6. The space is checp,but the use thime is not(explain later)
Optimize for minimal data transfer and be aware of excessive request over the network
for example
we wnat ot show the user name
database like this
we need to & listener to read the data,1 listener at the locaion driends,to get all the email,each email need a listener, to get the name
if improved like this
only need one listener
2.Thinjk about the future
have 10000 user? iteam? normally not over than 100
3 use the activity as a guide
wil we need the information at the same time?if no,do denormlized
EX How to improve

Different relationship in a data base
1 to 1
1 to many
many to many
Many to Many in Firebase,has problem
Firebase provide quick sort and filterning method.
First problem
when we want to show the list that a user have,we need to search the owner is the thousand of List,than search shared with in the thousand of list again,it is the numer is too much,need tim
Second problem
we need to cimbine the two search result.
what can we improve?
For these type of Many to Many relationship,we can use redudency data to make it more efficient,
for example:
at the above database,if i want ot know all the groups that a user in,i need to download all the groups information,and found is the user in.,this is not a good way.
improved database:
in this database,the user save which group do they in. Although have redudency data(users and hroup save the same data),byt more efficiency.The space is checp,but the use thime is not
for update multiple location at the same time,we should use updateChildren
Range Queries
startAt(),endAt(),equalTo()
How to use?
example:
can use combined
Exercise:
Answer:
Query use in English
result:
explain:https://www.youtube.com/watch?v=OseBuMTXY8Y&feature=youtu.behttps://youtu.be/OseBuMTXY8Y:https://youtu.be/OseBuMTXY8Yhttps://youtu.be/OseBuMTXY8Y
EX:
Limit Queries
no need for the all answer
limitToFirst
limitToLast
where to use?
EX of Searching
V 0.4.13 Searching
Main Goal
Add an autocomplete search textbox when selecting friends emails on the AddFriendActivity.
Specifications
Make a search textbox on the AddFriendActivity. (To do this, all you need to do is change the visibility for the textbox inactivity_add_friend.xml layout to visible)
Write a query that searches for all emails that start with the letters entered in the search texbox.
Write the code in afterTextChanged that uses a FirebaseListAdapter and the list_view_friends_autocompleteListView to show a list of users whose emails start with what was entered in the textbox.
This list should be no more than 5 names long.
When the user selects a name or enters less than 2 letters, the list of names should disappear.
Wireframes
Technical Notes
Changing the Query
There is no easy way to change the underlying query for a FirebaseListAdapter. The easiest way to deal with this is to make a new adapter every time the query changes. Performance wise, it would make more sense to cache all users and filter client side. But in your situation, you can remake the adapter. We'll approach it this way for two reasons:
For the final production code, you'd want to revisit this part of the app.
Hints and Tips
Code Snippets
ref.orderByChild(“listName”).startAt("do").endAt("do~").limitToFirst(10);
|
Ofline access in FireBase
at default,the data that get before the phone offline,will cache locally,every thing we do to the data,will quennung,when connect again,the event send to the server.
see the example:
however,when the listener clean,the cache is cleaned too:
we can not clean up the cache when remove the listener.
two method can help us.
1.setPersistenceEnabled
Firebase.getDefaultConfig().setPersistenceEnabled(true);
|
prevent the data will cleanup when the listener is clean up
Firebase client automatically keeps a queue of all write operations that are performed while our application is offline
Bad side:
1.use more disk space
2.if offline ,and use a lot of addListernerForSingleValueEvent,it query to the local data,come online ,will not query again,will get the old data
2.keepSynced
can 預先get the data,although they do not have listener for
Firebase scoresRef = new Firebase("https://dinosaur-facts.firebaseio.com/scores");
scoresRef.keepSynced(true);
|
Bad side:
use more memory
EX
V 0.5.01 Add Simple Offline Functionality
Main Goal
The app should cache all user changes made offline.
Specifications
The app should cache all user changes made offline, even when the user navigates away from a screen.
This should function even if the user closes the app or restarts their phone.
You should not remove any listener cleanup code.
Technical Notes
Testing Offline
You can test if your solution works by putting the phone into airplane mode. Remember, if you're on a single screen and make changes, Firebase will automatically cache these changes without you needing to implement any code. What it will not do is keep data around when listeners are cleaned up. You should be cleaning up your listeners whenever you move away from an activity. Thus, if you don't change any code, you will start noticing data disappearing when you move around and back to different activies when offline. Data is also not cached between app restarts automatically, so you should test your code by restarting your app. If it still shows the changes you made while offline, on an app restart, you know that the data is cached locally.
Hints and Tips
|
Securing data(not yet)