I am trying to use realm database to display my api data. I want to display the company name, however the data is saids it is inserted in the log but cant seem to display the data on the UI. Here is the code..
Any help would be greatly appreciated with this problem. The variables are at the top and the problem is when it hits on success, ive written the code "write to DB", but it doesnt display the data but tells me the data has been inserted.
// Variables for the search input field and results TextViews.
private EditText mCompanyInput;
private TextView mTitleText;
private TextView mDescriptionText;
private TextView mOfficerText;
private TextView mTitleText1;
private TextView mDescriptionText1;
private OkHttpClient okHttpClient;
private static final String TAG = "MainActivity";
private Request request;
private String url = "https://api.companieshouse.gov.uk/search/companies?q=";
Button save;
TextView log;
Realm realm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCompanyInput = findViewById(R.id.companyInput);
log = findViewById(R.id.log);
mDescriptionText = findViewById(R.id.descriptionText);
mOfficerText = findViewById(R.id.officerText);
mTitleText1 = findViewById(R.id.titleText1);
mTitleText = findViewById(R.id.titleText);
mDescriptionText1 = findViewById(R.id.descriptionText1);
save = findViewById(R.id.searchButton);
realm = Realm.getDefaultInstance();
save.setOnClickListener(this);
}
public void onClick(View view){
okHttpClient = new OkHttpClient();
request = new Request.Builder().url(url).header("Authorization", "k6DNRbTp-AnQWn51JBz5VuPiTl8jv4_etdzoMyhf") .method("GET", null).build();
Log.d(TAG, "onClick:"+url);
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.i(TAG, e.getMessage());
}
#Override
public void onResponse(Call call, Response response) throws IOException {
Log.i(TAG,response.body().string());
Log.d(TAG, "onResponse:"+response.code());
}
});
writeToDB(mCompanyInput.getText().toString().trim(), (mDescriptionText.getText().toString().trim()));
showData();
}
public void showData(){
RealmResults<Company> guests = realm.where(Company.class).findAll();
// Use an iterator to invite all guests
String op="";
for (Company guest : guests) {
op+=guest.getName();
op+=guest.getAppointments();
}
log.setText(op);
}
public void writeToDB(final String mTitleText1, final String mDescriptionText1){
realm.executeTransactionAsync(new Realm.Transaction() {
#Override
public void execute(Realm bgRealm) {
Company user = new Company(mTitleText1, mDescriptionText1);
bgRealm.insert(user);
}
}, new Realm.Transaction.OnSuccess() {
#Override
public void onSuccess() {
writeToDB(mCompanyInput.getText().toString().trim(), (mOfficerText.getText().toString().trim()));
showData();
// Transaction was a success.
Log.v("Database", "Data Inserted");
}
}, new Realm.Transaction.OnError() {
#Override
public void onError(Throwable error) {
// Transaction failed and was automatically canceled.
Log.e("Database", error.getMessage());
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
realm.close();
}
Why are you calling writeToDB() from the onSuccess() method? This will cause recursion and keep writing the same data into the realm. It's correct to call showData() from onSuccess(), but there's not much point calling it directly from onClick().
I think your problem though is that you're trying to update the UI from a thread: it's called from an async transaction thread and not the main thread. See this answer (and there are others you can find easily once you know the problem: Updating UI / runOnUiThread / final variables: How to write lean code that does UI updating when called from another Thread.
Related
I developed an android application in which I want to get data from the database without refreshing the app. I tried different methods but no one works for me. I am using PHP for fetching data from the database into my android app. Below is my code which is for now only fetching data from a database but I have to refresh the app if I update data in the database to get the updated value in the app. I want realtime values from the database, like, if I update data in the database, I want the same update in the app but without refreshing it.
public class Profile extends AppCompatActivity implements View.OnClickListener {
private TextView textViewUsername,textViewHr,textViewBp;
private Button button;
private ProgressDialog progressDialog;
private SwipeRefreshLayout swipeRefreshLayout;
private ImageView imageViewWet, imageViewTempered;
String username;
private static int wet,tempered;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile2);
username = SharedPrefManager.getInstance(this).getUsername();
textViewUsername = (TextView) findViewById(R.id.pUsername);
textViewHr = (TextView) findViewById(R.id.heartRate);
textViewBp = (TextView) findViewById(R.id.bloodPressure);
swipeRefreshLayout = findViewById(R.id.swipeToRefresh);
imageViewTempered = (ImageView) findViewById(R.id.imageViewTempered);
imageViewWet =(ImageView) findViewById(R.id.imageViewWet);
button = (Button) findViewById(R.id.refresh);
wet = SharedPrefManager.getInstance(getApplicationContext()).getWetStatus();
tempered = SharedPrefManager.getInstance(getApplicationContext()).getTemperedStatus();
textViewUsername.setText(SharedPrefManager.getInstance(this).getUsername());
textViewHr.setText(String.valueOf(SharedPrefManager.getInstance(this).getHeartRate()));
textViewBp.setText(String.valueOf(SharedPrefManager.getInstance(this).getTemperature()));
if(wet==1){
imageViewWet.setImageResource(R.drawable.tick);
}
else{
imageViewWet.setImageResource(R.drawable.cross);
}
if(tempered == 1){
imageViewTempered.setImageResource(R.drawable.tick);
}
else{
imageViewTempered.setImageResource(R.drawable.cross);
}
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
data();
swipeRefreshLayout.setRefreshing(false);
}
});
button.setOnClickListener(this);
/*if(!SharedPrefManager.getInstance(this).isLoggedIn()){
finish();
startActivity(new Intent(this,ProfileActivity.class));
return;
}*/
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Please Wait...");
}
public void data(){
progressDialog.show();
StringRequest stringRequest = new StringRequest(Request.Method.POST, Constants.URL_DATA,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
progressDialog.dismiss();
try {
JSONObject obj = new JSONObject(response);
if(!obj.getBoolean("error")){
System.out.println("IN SHARED SET VALES");
SharedPrefManager.getInstance(getApplicationContext()).data(obj.getInt("Id"),obj.getString("Username"),obj.getInt("Heart_Rate"),obj.getInt("Temperature"),obj.getInt("Wet"),obj.getInt("Tempered"));
textViewUsername.setText(SharedPrefManager.getInstance(getApplicationContext()).getUsername());
textViewHr.setText(String.valueOf(SharedPrefManager.getInstance(getApplicationContext()).getHeartRate()));
textViewBp.setText(String.valueOf(SharedPrefManager.getInstance(getApplicationContext()).getTemperature()));
wet = SharedPrefManager.getInstance(getApplicationContext()).getWetStatus();
tempered = SharedPrefManager.getInstance(getApplicationContext()).getTemperedStatus();
if(wet==1){
imageViewWet.setImageResource(R.drawable.tick);
}
else{
imageViewWet.setImageResource(R.drawable.cross);
}
if(tempered == 1){
imageViewTempered.setImageResource(R.drawable.tick);
}
else{
imageViewTempered.setImageResource(R.drawable.cross);
}
}else{
Toast.makeText(getApplicationContext(),obj.getString("message"),Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
progressDialog.dismiss();
Toast.makeText(getApplicationContext(),error.getMessage(),Toast.LENGTH_LONG).show();
}
}
){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params = new HashMap<>();
params.put("Username",username);
return params;
}
};
RequestHandler.getInstance(this).addToRequestQueue(stringRequest);
}
#Override
public void onClick(View v) {
if(v == button){
data();
}
}
}
Below is the layout of my app. Basically I want to update Heart Rate and Temperature continuously without refreshing the app.
Please help me, how I can get data from the database into my app without refreshing the app?
Thanks in Advance
Try using reactive programming tools like RxJava or RxAndroid. Reactive Programming is basically event-based asynchronous programming.
Use time Outs to automatically refresh the content after few minutes .
Server Side app rendering and sockets could also be useful for such cases.
In my android app, I want to display the localized price, for an In-App purchase, on a button.
I've tried following a guide to set up the In-App Billing (https://medium.com/#patpatchpatrick/adding-the-google-play-billing-library-to-your-application-fbeb9ec03151) to set up the billing itself, and it seems to work on a test account.
Although .setSku and .setType is now deprecated, and .setSkuDetails is now to be used, which from documentation is great, as there's plenty of options. However i can't seem to get any access to the SkuDetails class..
For a couple of weeks I've tried implementing In-App Billing, and looked at various articles and guides, but can't seem to find my way about it. I feel like i've tried everything and doesn't know where to turn next.
public class InAppBilling extends AppCompatActivity implements
PurchasesUpdatedListener {
private static final String TAG = "InAppBilling";
//In APP Produkter
static final String ITEM_SKU_ADREMOVAL = "remove_ads_salary1";
private Button mButton;
private Button back_Button;
private String mAdRemovalPrice;
private SharedPreferences mSharedPreferences;
private BillingClient mBillingClient;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.inappbilling);
mBillingClient = BillingClient.newBuilder(InAppBilling.this).setListener(this).build();
mBillingClient.startConnection(new BillingClientStateListener() {
#Override
public void onBillingSetupFinished(int responseCode) {
if (responseCode == BillingClient.BillingResponse.OK){
List skuList = new ArrayList<>();
skuList.add(ITEM_SKU_ADREMOVAL);
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
mBillingClient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener() {
#Override
public void onSkuDetailsResponse(int responseCode, List<SkuDetails> skuDetailsList) {
//Processing the response if the code = OK, and skuDetailsList isn't = null(empty)
if (responseCode == BillingClient.BillingResponse.OK && skuDetailsList != null){
for (SkuDetails skuDetails : skuDetailsList){
String sku = skuDetails.getSku();
String price = skuDetails.getPrice();
if (ITEM_SKU_ADREMOVAL.equals(sku)){
mAdRemovalPrice = price;
}
}
}
}
});
}
}
#Override
public void onBillingServiceDisconnected() {
// IMPLEMENT RETRY POLICY - TRY TO RESTART ON NEXT REQUEST BY CALLING startConnection()
}
});
mButton = findViewById(R.id.buy_button);
mButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
//THIS skuDetails gives the error 'Cannot resolve symbol
.setSkuDetails(skuDetails)
// .setSku(ITEM_SKU_ADREMOVAL)
// .setType(BillingClient.SkuType.INAPP)
.build();
int responseCode = mBillingClient.launchBillingFlow(InAppBilling.this, flowParams);
}
});
back_Button = findViewById(R.id.back_button);
back_Button.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
//Returnere til det fragment man kom fra
InAppBilling.super.onBackPressed();
}
});
}
Well, I'd love to gain access over SkuDetails, so I can use it's method getPrice(), to show localized prices, for my in-app.
Right now, I can't use getPrice().
Make your activity to implement the listeners, then you will be able to access everything more easily.
I reformatted your code to implement all your listeners, and it may have some minor mistakes, but I hope you get the idea.
Notice that I've also implemented the View.OnClickListener which makes the code more clear, yet you will need to assign at module level a variable for the skuDetails being passed to the builder, which I didn't do. Let me know if you have any questions.
public class InAppBilling extends AppCompatActivity implements
PurchasesUpdatedListener, SkuDetailsResponseListener,
BillingClientStateListener, View.OnClickListener
{
private static final String TAG = "InAppBilling";
//In APP Produkter
static final String ITEM_SKU_ADREMOVAL = "remove_ads_salary1";
private Button mButton;
private Button back_Button;
private String mAdRemovalPrice;
private SharedPreferences mSharedPreferences;
private BillingClient mBillingClient;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.inappbilling);
mBillingClient = BillingClient.newBuilder(this).setListener(this).build();
mBillingClient.startConnection(this);
findViewById(R.id.buy_button).setOnClickListener(this);
findViewById(R.id.back_button).setOnClickListener(this);
}
#Override
public void onPurchasesUpdated(int responseCode, #Nullable List<Purchase> purchases)
{
}
#Override
public void onSkuDetailsResponse(int responseCode, List<SkuDetails> skuDetailsList)
{
if (responseCode == BillingClient.BillingResponse.OK && skuDetailsList != null)
{
for (SkuDetails skuDetails : skuDetailsList)
{
String sku = skuDetails.getSku();
String price = skuDetails.getPrice();
if (ITEM_SKU_ADREMOVAL.equals(sku))
{
mAdRemovalPrice = price;
}
}
}
}
#Override
public void onClick(View view)
{
if (view.getId() == R.id.back_button)
{
super.onBackPressed();
}
else if (view.getId() == R.id.buy_button)
{
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build();
int responseCode = mBillingClient.launchBillingFlow(this, flowParams);
}
}
#Override
public void onBillingSetupFinished(int responseCode)
{
if (responseCode == BillingClient.BillingResponse.OK)
{
List skuList = new ArrayList<>();
skuList.add(ITEM_SKU_ADREMOVAL);
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
mBillingClient.querySkuDetailsAsync(params.build(), this);
}
}
#Override
public void onBillingServiceDisconnected()
{
// IMPLEMENT RETRY POLICY - TRY TO RESTART ON NEXT REQUEST BY CALLING startConnection()
}
}
I'm working on a new project that implements MVVM. Can I use a viewmodel that is observed for two activities ? or should I make one viewmodel for each activity ?
public class FormViewModel extends AndroidViewModel {
/*
This is my only ViewModel in the project
*/
private UserRepository userRepository;
//linked fields in xml for lib Data Binding
public String name, lastName, address, age;
//variables observed in the views
public MutableLiveData<String> responseMessageInsertUpdate = new MutableLiveData<>();
public MutableLiveData<String> responseStartUserFormActivity = new MutableLiveData<>();
public MutableLiveData<String> responseMessageDelete = new MutableLiveData<>();
public FormViewModel(Application application) {
super(application);
userRepository = new UserRepository(application);
}
//get all users from database that implements RoomDataBase, it´s observed em MainActivity
//and update recyclerview when database receive any change
public LiveData<List<User>> getAllUsers() {
return userRepository.selectAllUsers();
}
/*
action of submit button defined (linked for lib Data Binding) in xml
makes change or user registration
*/
public void submitClick(User user) {
int idade = 0;
if (this.age != null) {
if (!this.age.isEmpty()) {
idade = Integer.parseInt(this.age);
}
}
if (user != null) {
user.setName(name);
user.setLastName(lastName);
user.setAddress(address);
user.setAge(idade);
} else {
user = new User(name, lastName, address, idade);
}
//validation logic
if (user.isFormValid()) {
if (user.getId() > 0) {
//update the user in the database
userRepository.updateUser(user);
//there is an observable of this MutableLiveData variable in UserFormActivity that shows this
//message in a toast for the User when received a value
responseMessageInsertUpdate.setValue("User data uploaded successfully.");
} else {
//insert the user on data base
userRepository.insertUser(user);
responseMessageInsertUpdate.setValue("User " + user.getName() + " stored successfully.");
}
} else {
responseMessageInsertUpdate.setValue("Please, correctly fill in all the fields of the form to confirm the registration.");
}
}
//action of btnNewForm linked for lib Data Binding in xml
public void newFormClick() {
/*
this MutableLiveData is observed for MainActivity and start a new UserFormActivity when receive
value when the btnNewForm is pressed
*/
responseStartUserFormActivity.setValue("startActivity");
}
//delete User from database
public void deleteUser(User user) {
if (user != null) {
userRepository.deleteUser(user);
/*
there is an observable of this MutableLiveData variable in MainActivity that shows this
message in a toast for the user when received a value (when an user is deleted from database)
*/
responseMessageDelete.setValue(user.getName() + " removed from list successfully.");
}
}
//this method is called on UserFormActivity to show more details of an existing user in activity fields
public void showDataUserInActivity(User user) {
//linked fields in xml for lib Data Binding that receive values from the object user
name = user.getName();
lastName = user.getLastName();
address = user.getAddress();
age = String.valueOf(user.getAge());
}
}
public class MainActivity extends AppCompatActivity {
/*
this activity shows all users in recyclerview
*/
private Context contexto = this;
private ActivityMainBinding binding;
private UserAdapter userAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
FormViewModel formViewModel = ViewModelProviders.of(this).get(FormViewModel.class);
binding.setViewModel(formViewModel);
createRecyclerView();
methodsViewModel();
}
//methods from ViewModel
private void methodsViewModel() {
//observer that update recyclerview when database receive any change
binding.getViewModel().getAllUsers().observe(this, new Observer<List<User>>() {
#Override
public void onChanged(#Nullable List<User> pessoas) {
userAdapter.addUserToList(pessoas);
}
});
//observer that starts a new UserFormActivity when btnNewForm is pressed
//receive value in the method newFormClick from ViewModel
binding.getViewModel().responseStartUserFormActivity.observe(this, new Observer<String>() {
#Override
public void onChanged(#Nullable String s) {
startUserFormActivity();
}
});
//observer that shows a message in a toast when the user is deleted from database
//receive value in the method deleteUser from ViewModel
binding.getViewModel().responseMessageDelete.observe(this, new Observer<String>() {
#Override
public void onChanged(#Nullable String message) {
Toast.makeText(contexto, message, Toast.LENGTH_SHORT).show();
}
});
}
private void createRecyclerView() {
RecyclerView rvUser = binding.rvPessoas;
rvUser.setLayoutManager(new LinearLayoutManager(contexto));
userAdapter = new UserAdapter(contexto, itemClick());
rvUser.setAdapter(userAdapter);
}
private void startUserFormActivity() {
Intent intent = new Intent(contexto, UserFormActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
contexto.startActivity(intent);
}
private void startUserFormActivity(User user) {
Intent intent = new Intent(contexto, UserFormActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("user", user);
contexto.startActivity(intent);
}
private UserAdapter.ItemClick itemClick() {
return new UserAdapter.ItemClick() {
#Override
public void simpleClick(View view, final int position) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(contexto);
String[] options = {"Update", "Delete"};
alertDialog.setItems(options, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
if (i == 0) {
//start a new UserFormActivity to change user attributes
startUserFormActivity(userAdapter.getUserFromList().get(position));
} else if (i == 1) {
//call the method deleteUser from ViewModel
binding.getViewModel().deleteUser(userAdapter.getUserFromList().get(position));
}
}
});
alertDialog.show();
}
};
}
}
public class UserFormActivity extends AppCompatActivity {
private Context context = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FormViewModel formViewModel = ViewModelProviders.of(this).get(FormViewModel.class);
final ActivityFormUserBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_form_user);
binding.setViewModel(formViewModel);
if (getIntent().getSerializableExtra("user") != null) {
User user = (User) getIntent().getSerializableExtra("user");
formViewModel.showDataUserInActivity(user);
//put user data in activity when action "update" is called in MainActivity
binding.setUser(user);
}
/*
Method from ViewModel
Observer that shows a message in a toast and close the activity when the user is storage or updated from database
receive value in the method submitClick from ViewModel
*/
formViewModel.responseMessageInsertUpdate.observe(this, new Observer<String>() {
#Override
public void onChanged(#Nullable String s) {
Toast.makeText(context, s, Toast.LENGTH_LONG).show();
if (s.contains("successfully")) {
finish();
}
}
});
}
}
Here is my ViewModel and my two activities for more details. As I said it's a ViewModel that is observed for two activities. This ViewModel calls a repository that updates, inserts and deletes user data as well as also updates e sends messages to the views.
It's completely OK to share a viewmodel among the views, in case if you're using the same data or it's a kind of centralised datastore.
Otherwise implement separate model for each view as it increases
code readability and hence efficiency.
Happy to provide personalised solution if you could post some of your
code snippets here. Happy coding
I'm testing Firebase by building an app that simply puts a message in the Database (authorisations are set to true for the test), it worked only once, and now nothing is pushed to the database. But as you can see I put logs everywhere to see where the problem is and surprisingly the onChildEventListener() seems to notice a change.
Here is the code for my main activity :
public class MainActivity extends AppCompatActivity {
public final static String TAG = "Main Activity";
public final int[] id = {0};
Button sendButton;
EditText messageEditText;
String message;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
id[0] = 0;
sendButton = findViewById(R.id.send_message);
messageEditText = findViewById(R.id.message_text);
final DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("test/geomessage/");
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
message = messageEditText.getText().toString();
Log.e(TAG, "Test 1");
GeoMessage currentGeomessage = new GeoMessage(id[0], message);
Log.e(TAG, "Test 2");
databaseReference.child("children").push().setValue(currentGeomessage).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.e(TAG, "Success !");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e(TAG, "FAIL");
}
}).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Log.e(TAG, "Complete");
}
});
Log.e(TAG, "Test 3");
}
});
databaseReference.child("children").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Log.e("101", "Child Added !");
id[0] = (int) dataSnapshot.getChildrenCount();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
Log.e("101", "Child CHanged !");
id[0] = (int) dataSnapshot.getChildrenCount();
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private static class GeoMessage {
int id;
String content;
public GeoMessage() {};
public GeoMessage(int id, String content) {
this.id = id;
this.content = content;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
}
Here are the logs when I click on the "Send" Button :
11-03 19:02:13.338 7440-7440/com.example.brumor.geofiretest E/Main Activity: Test 1
11-03 19:02:13.338 7440-7440/com.example.brumor.geofiretest E/Main Activity: Test 2
11-03 19:02:13.340 7440-7440/com.example.brumor.geofiretest E/Main Activity: Test 3
11-03 19:02:13.420 7440-7440/com.example.brumor.geofiretest E/101: Child Added !
The observed behavior occurs when the device does not have a connection to the Firebase servers. Calls to setValue() change the DB cache held locally in the client. This causes listeners for the changed location to fire. But the completion listeners for setValue() do not fire until the update to the Firebase server completes successfully or fails.
Check that your device has a network connection. You can detect the Firebase connection status using the example here.
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
message = messageEditText.getText().toString();
GeoMessage currentGeomessage = new GeoMessage(id[0], message);
databaseReference.child("children").push().setValue(currentGeomessage);
}
});
No need to use addonSuccessListener to store data. Also it is not even entering the method addonSuccessListener , so its skipping the whole method and then it prints the Log for you, but nothing is entering the database. Usually onSuccessListener is used for firebase storage, to see if the task is successful or not.
Also according to this page: https://firebase.google.com/docs/reference/admin/java/reference/com/google/firebase/tasks/Task
public abstract Task<T> addOnSuccessListener (OnSuccessListener<? super T> listener)
The above method is deprecated.
You have to use this now:
public abstract Task<T> addOnSuccessListener (Executor executor, OnSuccessListener<? super T> listener)
I am developing a an android app that uses service discovery over wifi direct,based on the provided google sample code, the problem is i can't get a fixed value of the advertised TXT record even though i'm using a final hashmap to store the value, the Hashmap is modified every time the onDnsSdTxtRecordAvailable callback is called, even though i'm using a final hashmap declared globally to store the first value, it gets replaced by null. here is the code i'm using. thanks
private WifiP2pManager manager;
private final IntentFilter intentFilter = new IntentFilter();
private Channel channel;
private BroadcastReceiver receiver = null;
private WifiP2pDnsSdServiceRequest serviceRequest;
private TextView statusTxtView;
private TextView services;
private Button register;
private Button broadcast;
private LocationManager locationManager;
final HashMap<String, String> buddies = new HashMap<String, String>();
private TextView locationTxt;
public String value1;
private Button loc;
private final String name = new String();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
statusTxtView = (TextView) findViewById(R.id.status);
services = (TextView) findViewById(R.id.services);
register = (Button) findViewById(R.id.discover);
broadcast = (Button) findViewById(R.id.bd);
locationTxt = (TextView)findViewById(R.id.location);
loc = (Button)findViewById(R.id.loc);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter
.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter
.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(this, getMainLooper(), null);
startRegistrationAndDiscovery();
register.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startRegistrationAndDiscovery();
}
});
broadcast.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
discoverService();
}
});
loc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
doIt();
}
});
}
#Override
public void onResume() {
super.onResume();
receiver = new MyReceiver(manager, channel, this);
registerReceiver(receiver, intentFilter);
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
public void appendStatus(String status) {
String current = statusTxtView.getText().toString();
statusTxtView.setText(current + "\n" + status);
}
//service discvery handllng methods
private void startRegistrationAndDiscovery() {
Map<String, String> record = new HashMap<String, String>();
record.put(TXTRECORD_PROP_AVAILABLE, "visible");
WifiP2pDnsSdServiceInfo service = WifiP2pDnsSdServiceInfo.newInstance(
SERVICE_INSTANCE, SERVICE_REG_TYPE, record);
manager.addLocalService(channel, service, new ActionListener() {
#Override
public void onSuccess() {
appendStatus("Added Local Service");
}
#Override
public void onFailure(int error) {
appendStatus("Failed to add a service");
}
});
discoverService();
}
private void discoverService() {
/*
* Register listeners for DNS-SD services. These are callbacks invoked
* by the system when a service is actually discovered.
*/
manager.setDnsSdResponseListeners(channel,
new DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName,
String registrationType, WifiP2pDevice srcDevice) {
// A service has been discovered. Is this our app?
if (instanceName.equalsIgnoreCase(SERVICE_INSTANCE)) {
// update the UI and add the item the discovered
// device.
/* WiFiP2pService service = new WiFiP2pService();
service.device = srcDevice;
service.instanceName = instanceName;
service.serviceRegistrationType = registrationType;*/
//put data to textview here
services.setText(srcDevice.status+" Instance name " + instanceName + " type " + registrationType);
Log.d(TAG, "onBonjourServiceAvailable "
+ instanceName);
Http_client http_client = new Http_client(SERVICE_INSTANCE);
appendStatus("data sent to server successfully");
}
}
}, new DnsSdTxtRecordListener() {
/**
* A new TXT record is available. Pick up the advertised
* buddy name.
*/
#Override
public void onDnsSdTxtRecordAvailable(String fullDomainName, Map<String, String> record,WifiP2pDevice device) {
Log.d(TAG, device.deviceName + " is " + record.get(TXTRECORD_PROP_AVAILABLE));
buddies.put("mm",record.get(TXTRECORD_PROP_AVAILABLE));
Toast.makeText(getBaseContext(),record.get(TXTRECORD_PROP_AVAILABLE),Toast.LENGTH_LONG).show();
//
}
});
// After attaching listeners, create a service request and initiate
// discovery.
serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel, serviceRequest,
new ActionListener() {
#Override
public void onSuccess() {
appendStatus("Added service discovery request");
}
#Override
public void onFailure(int arg0) {
appendStatus("Failed adding service discovery request");
}
});
manager.discoverServices(channel, new ActionListener() {
#Override
public void onSuccess() {
appendStatus("Service discovery initiated");
}
#Override
public void onFailure(int arg0) {
appendStatus("Service discovery failed");
}
});
}
public void doIt(){
buddies.put("mm","value1");
Toast.makeText(getBaseContext(),buddies.get("mm"),Toast.LENGTH_LONG).show();
buddies.put("mm","value2");
Toast.makeText(getBaseContext(),buddies.get("mm"),Toast.LENGTH_LONG).show();
}
A final variable will not help you, as I have commented. Based on your question, what you need to do is to always check if the value is set in your hashmap, before saving the new returned variable. Something like
if (!buddies.containKey("mm"))
buddies.put("mm", .....)