Firebase Query not being updated - firebase

I want my firebase database link to be updated depending on what the user keys in inside the searchview but the link is not updated unless I open another activity and jump back to it.I have attacked my code in the bottom. So how do I refresh it automatically ?
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener()
{
#Override
public boolean onQueryTextSubmit(String query) {
query = sv.getQuery().toString();
Toast.makeText(MainMenu.this,query, Toast.LENGTH_SHORT).show();
makeItem();
return true;
}
#Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
public void makeItem ()
{
lv = findViewById(R.id.listView);
db = FirebaseDatabase.getInstance().getReferenceFromUrl("https://vsem-inventory.firebaseio.com/ItemList").orderByChild("ProductName").startAt(query).endAt(query+"\uf8ff");
FirebaseListOptions<ItemObject> options = new FirebaseListOptions.Builder<ItemObject>()
.setLayout(R.layout.content_main_menu_list)
.setQuery(db,ItemObject.class)
.build();
mAdapter = new FirebaseListAdapter<ItemObject>(options) {
#Override
protected void populateView(#NonNull View v, #NonNull ItemObject model, int position) {
final TextView tvAmount = v.findViewById(R.id.amount);
final TextView tvName = v.findViewById(R.id.name);
final TextView tvSerial = v.findViewById(R.id.serialNo);
final TextView tvSupplier = v.findViewById(R.id.supplierName);
final ImageView more = v.findViewById(R.id.more);
ImageView statusimg = v.findViewById(R.id.status);
Drawable paidIcon = v.getResources().getDrawable(R.drawable.succes);
Drawable lateIcon = v.getResources().getDrawable(R.drawable.late);
tvName.setText(model.getProductName());
tvSerial.setText(model.getSerialNo());
tvAmount.setText(model.getQuantity());
tvSupplier.setText(model.getModel());
final String Remarks = model.getRemarks();
final String cat = model.getCategory();
if(model.getQuantity().equals("0"))
statusimg.setImageDrawable(lateIcon);
else
statusimg.setImageDrawable(paidIcon);
more.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v) {
String serialNo = tvSerial.getText().toString();
String itemName = tvName.getText().toString();
String quan = tvAmount.getText().toString();
String supplier = tvSupplier.getText().toString();
showMenu(itemName,more,serialNo,quan,supplier,cat,Remarks);
}
});
}
};
lv.setAdapter(mAdapter);
}

The standard way is to call notifyDataSetChanged() after setting your adapter to your list view
Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.
mAdapter.notifyDataSetChanged();
Although I have seen some situations where only using this does not work and must be followed by these 2 commands.
lv.invalidateViews();
lv.scrollBy(0, 0);
And if all else comes to fail falling back on destroying and redrawing the list view might be your only viable option.
lv.destroyDrawingCache();
lv.setVisibility(ListView.INVISIBLE);
lv.setVisibility(ListView.VISIBLE);
EDIT : After looking at it a while more I just noticed you're missing listeners for your firebase. I assume you already have them somewhere as you already have the list but failing your refresh functions, what you can try is restarting the listeners whenever you're done with a query.
lv.setAdapter(mAdapter);
mAdapter.stopListening();
mAdapter.startListening();

Related

make a search in recylerview

I want to make a search on recyclerview, but the data appears if the phone is turned off and then turned on again, why is that?
the example photo
the app
When i'm search the recylerview is blank
but when the phones turned off and then turn on again, the data is appear
here's the code in fragment class
//search
editText = view.findViewById(R.id.searchServant);
searchButton = view.findViewById(R.id.button2);
searchButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String s = editText.getText().toString();
firebaseSearch(s);
}
});
//RecylerviewDatabaseServant
recyclerViewdatabase = view.findViewById(R.id.recyclerViewServant);
mManager = new LinearLayoutManager(getContext());
recyclerViewdatabase.setLayoutManager(mManager);
FirebaseRecyclerOptions<Servant> options =
new FirebaseRecyclerOptions.Builder<Servant>().setQuery(FirebaseDatabase.getInstance().getReference().child("Servant")
, Servant.class)
.build();
servantAdapter = new ServantAdapter(options);
recyclerViewdatabase.setAdapter(servantAdapter);
//End
here the function firebase search
private void firebaseSearch(String s) {
FirebaseRecyclerOptions<Servant> options = new FirebaseRecyclerOptions.Builder<Servant>().setQuery(FirebaseDatabase.getInstance()
.getReference().child("Servant").orderByChild("name").startAt(s).endAt(s + "\uf8ff"), Servant.class).build();
servantAdapter = new ServantAdapter(options);
recyclerViewdatabase.setAdapter(servantAdapter);
}
Try add this line in You search query
private void firebaseSearch(String s) {
FirebaseRecyclerOptions<Servant> options = new FirebaseRecyclerOptions.Builder<Servant>().setQuery(FirebaseDatabase.getInstance()
.getReference().child("Servant").orderByChild("name").startAt(s).endAt(s + "\uf8ff"), Servant.class).build();
servantAdapter = new ServantAdapter(options);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager({**context**}));
recyclerViewdatabase.setAdapter(servantAdapter);
servantAdapter.startListening();
}

Retaining fragment state after receiving activity result

I have an Activity A that consists of Fragment A. Inside Fragment A, I start Activity B with startActivityForResult(). When I receive the result from Activity B, all views values in Fragment A that had already been set before return to their default values. How to retain the all views values in Fragment A?
Below is the implementation:
public class MainFragment extends Fragment {
public MainFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listView = (ListView) getActivity().findViewById(R.id.xlistview);
xItemArrayList = new ArrayList<XItem>();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id){
case R.id.menu_item_add:
initialiseList();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void initialiseList(){
xListAdapter = new xListAdapter(getContext(), R.layout.item_list, xItemArrayList);
xListAdapter.setxListListener(new xListListener() {
#Override
public void onClickStart(View view) {
openAutocompleteActivity(Constant.VIEW_START);
}
});
xListView.setAdapter(xListAdapter);
}
private void openAutocompleteActivity(int selectedView) {
this.selectedView = selectedView;
try {
// The autocomplete activity requires Google Play Services to be available. The intent
// builder checks this and throws an exception if it is not the case.
Intent intent = new PlaceAutocomplete.IntentBuilder(PlaceAutocomplete.MODE_FULLSCREEN).build(getActivity());
startActivityForResult(intent, Constant.REQUEST_CODE_AUTOCOMPLETE);
} catch (GooglePlayServicesRepairableException e) {
// Indicates that Google Play Services is either not installed or not up to date. Prompt the user to correct the issue.
GoogleApiAvailability.getInstance().getErrorDialog(getActivity(), e.getConnectionStatusCode(), 0 ).show();
} catch (GooglePlayServicesNotAvailableException e) {
// Indicates that Google Play Services is not available and the problem is not easily resolvable.
String message = "Google Play Services is not available: " + GoogleApiAvailability.getInstance().getErrorString(e.errorCode);
Log.e(Constant.TAG_ERROR, message);
Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Check that the result was from the autocomplete widget.
if (requestCode == Constant.REQUEST_CODE_AUTOCOMPLETE) {
if (resultCode == Constant.RESULT_OK) {
// Get the user's selected place from the Intent.
Place place = PlaceAutocomplete.getPlace(getActivity(), data);
if (selectedView == Constant.VIEW_START){
start = place;
((TextView)xListView.getChildAt(0).findViewById(R.id.textview_start)).setText(start.getName());
}else if (selectedView == Constant.VIEW_LAST){
last = place;
((TextView)xListView.getChildAt(0).findViewById(R.id.textview_last)).setText(last.getName());
}
} else if (resultCode == PlaceAutocomplete.RESULT_ERROR) {
Status status = PlaceAutocomplete.getStatus(getActivity(), data);
Log.e(Constant.TAG_ERROR, "Error: Status = " + status.toString());
} else if (resultCode == Constant.RESULT_CANCELED) {
// Indicates that the activity closed before a selection was made. For example if
// the user pressed the back button.
}
}
}
There are two views in R.layout.item_list, R.id.textview_start and R.id.textview_last. On select each of the view, Activity B will start and on finish Activity B, the result will be displayed on the view itself. However, every time Activity B starts and finishes, previous values of the two views disappear and return to default. I have tried SavedInstanceState, but it does not work. It seems when Activity B returns to Activity A (with Fragment A in it), system goes to OnResume() of Fragment A without going to onCreatedView() of Fragment A.
You can use 2 method:
1st: use sharedpreferences to store the data. Now this data is accessible next time also the app is used. So after displaying the old data, just reset the data in sharepreferences to blank.
2nd: use bundle to transfer data to the activity and then just retrieve the same back.
Use a bundle to transfer data from one activity to another activity
Bundle bundle = new Bundle();
bundle.putString("KEY_NAME", "Abrakadabra");
Intent i = new Intent(this, MyActivityName.class);
i.putExtras(bundle);
startActivity(i) <-- new activity started
Then in the receiving activity: Put this code in the onCreate method
Bundle bundle = getIntent().getExtras();
String stringdata = bundle.getString("KEY_NAME");
To pass data from activity to fragment: Put this code anywhere
Bundle bundle = new Bundle();
bundle.putString("KEY_NAME", "Abrakadabra");
MyFragment myfragment = new MyFragment();
myfragment.setArguments(bundle);
Then in the onCreateView method of the fragment add this code
Bundle args = getArguments();
String stringdata = args.getString("KEY_NAME");
Since Fragment A is waiting for Activity B's result, Activity A (where Fragment A is) will go to pause state. When Activity B returns results, Fragment A will resumes without going through onActivityCreated(). Thus, saving instance state will not work. Currently, the only solution I can think of is as below.
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Check that the result was from the autocomplete widget.
if (requestCode == Constant.REQUEST_CODE_AUTOCOMPLETE) {
if (resultCode == Constant.RESULT_OK) {
// Get the user's selected place from the Intent.
Place place = PlaceAutocomplete.getPlace(getActivity(), data);
if (selectedView == Constant.VIEW_START){
start = place;
}else if (selectedView == Constant.VIEW_LAST){
last = place;
}
} else if (resultCode == PlaceAutocomplete.RESULT_ERROR) {
Status status = PlaceAutocomplete.getStatus(getActivity(), data);
Log.e(Constant.TAG_ERROR, "Error: Status = " + status.toString());
} else if (resultCode == Constant.RESULT_CANCELED) {
// Indicates that the activity closed before a selection was made. For example if
// the user pressed the back button.
}
}
if(start!=null)((TextView)xListView.getChildAt(0).findViewById(R.id.textview_start)).setText(start.getName());
if(last!=null)((TextView)xListView.getChildAt(0).findViewById(R.id.textview_last)).setText(last.getName());
}
All the views values are re-set in onActivityResult(). When Activity A/Fragment A goes into pause state, it retains global variables values. Thus, for this implementation to work, start and last must be declared as global variables in Fragment A. Please suggest a better solution, if any.

Updating Red5 SharedObject closing stream

I'm trying to create a voice conference room with all users can speak and use the mic. But as an Admin, I should have the privilege to mute any user. So, I add to the user an attribute for the mic which will be check in client side and enable/disable user's mic accordingly. The server side code looks like:
String identifier;
String userID;
private int _gId = 1;
private Map<String,Object> newUser;
#Override
public boolean appConnect(IConnection conn, Object[] params) {
identifier = (String)params[1];
userID = (String)params[0];
int _globalUserId = _gId++;
conn.getClient().setAttribute("id", _globalUserId);
newUser = new HashMap<String,Object>();
newUser.put("identifier", (String)params[0]);
newUser.put("mic", 1); //mic value to be checked in client side
return true;
}
#Override
public boolean roomJoin(IClient client, IScope scope) {
ISharedObject so = getSharedObject(scope, "users_so");
so.setAttribute(userID,newUser);
return true;
}
#SuppressWarnings("unchecked")
public void muteUser(String userID){
IScope scope = Red5.getConnectionLocal().getScope();
ISharedObject so = getSharedObject(scope, "users_so");
Map<String,Object> user= new HashMap<String,Object>();
user = (Map<String, Object>) so.getAttribute(userID);
if(user != null){
user.put("mic", 0);
so.beginUpdate();
boolean removed = so.removeAttribute(userID);
boolean updated = so.setAttribute(userID,user);
so.endUpdate();
log.info("Mic: " + user.get("mic"));
log.info("Removed: " + removed);
log.info("Updated: " + updated);
}
}
The problem arises when I try to call the muteUser method. Red5 says that the stream is closed. I think this happens when I remove the attribute of the user and added it again but I couldn't find another way to update the sharedObject's mic value.
Does any one have a better idea to update a sharedObject without losing stream?
The SO that you're requesting doesn't work like a user map that it would appear you think it does in your example. I would suggest storing a map in the SO and then do a get / add to the map; the map in this case being shared, so you'd have to make it thread-safe; I'd use a ConcurrentMap there like so:
ISharedObject so = getSharedObject(scope, "users_so");
if (so == null) {
// make sure your so exists
}
so.beginUpdate();
ConcurrentMap<String, Object> users = (ConcurrentMap<String, Object>) so.getAttribute("users");
if (users == null) {
users = new ConcurrentHashMap<String, Object>();
so.setAttribute("users" users);
}
Object user = users.get(userID);
user.put("mic", 0);
so.endUpdate();

why sometime i get the cursor null or count equal to zero

My apliction works fine ,it updates my spinner but sometime when I start my activity cursor becomes null and spinner list will be blank ,why?.It seems like my cursor is null or its count is zero. Though it works fine most of the time so there is no chance of cursor being null or emplty.very strange behavior
public class MainActivity extends Activity {
String[] data = { MediaStore.Video.Media.DATA };
ArrayList<String> path;
Spinner path_spinner;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.MainActivity);
path= new ArrayList<String>();
path_spinner = (Spinner) findViewById(R.id.folder_spinner);
Cursor cursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,data, null, null, null);
if(cursor != null && cursor.getCount() > 0)
{
cursor.moveToFirst();
do {
path.add(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA))
} while (cursor.moveToNext());
}
ArrayAdapter<String> path_adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, path);
path_spinner.setAdapter(path_adapter);
}
}
Update
if any uri is accessd at this time it gives
ContentValues values = new ContentValues(4);
values.put(MediaStore.Audio.Media.TITLE,"audio" + audiofile.getName());
values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/3gpp");
values.put(MediaStore.Audio.Media.DATA, audiofile.getAbsolutePath());
ContentResolver contentResolver = getContentResolver();
Uri base = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Uri newUri = contentResolver.insert(base, values);
07-24 15:52:22.300: E/AndroidRuntime(2583): Caused by: java.lang.UnsupportedOperationException: Unknown URI: content://media/external/audio/media
it was all working fine before the cursor problem .It seems like content provider is not accesible at the moment. why?

Accessing OutArgument value of Receive implementation child activity within custom WF4 activity

Using VS2012/.NET 4.5 I am creating a custom activity which implements a Receive child activity (as an implementation child). The parameters are in the example below fixed to just one: OutValue of type Guid.
I really would love to access the value of incoming parameter value in ReceiveDone, because I need to work with it and transform it before returning it from the activity. Please ignore that I am currently using a Guid, it still fails to access the value with and InvalidOperationException:
An Activity can only get the location of arguments which it owns. Activity 'TestActivity' is trying to get the location of argument 'OutValue' which is owned by activity 'Wait for
workflow start request [Internal for TestActivity]'
I have tried everything I could think of, but am stupefied. There must be a way to do this very simple thing?
public class TestActivity : NativeActivity<Guid>
{
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
var content = ReceiveParametersContent.Create(new Dictionary<string, OutArgument>()
{
// How to access the runtime value of this inside TestActivity?
{"OutValue", new OutArgument<Guid>()}
});
startReceiver = new Receive()
{
DisplayName = string.Format("Wait for workflow start request [Internal for {0}]", this.DisplayName),
CanCreateInstance = true,
ServiceContractName = XName.Get("IStartService", Namespace),
OperationName = "Start",
Content = content
};
foreach (KeyValuePair<string, OutArgument> keyValuePair in content.Parameters)
{
metadata.AddImportedChild(keyValuePair.Value.Expression);
}
metadata.AddImplementationChild(startReceiver);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(startReceiver, ReceiveDone);
}
private void ReceiveDone(NativeActivityContext context, ActivityInstance completedInstance)
{
var receive = completedInstance.Activity as Receive;
ReceiveParametersContent content = receive.Content as ReceiveParametersContent;
try
{
// This causes InvalidOperationException.
// An Activity can only get the location of arguments which it owns.
// Activity 'TestActivity' is trying to get the location of argument 'OutValue'
// which is owned by activity 'Wait for workflow start request [Internal for TestActivity]'
var parmValue = content.Parameters["OutValue"].Get(context);
}
catch (Exception)
{ }
}
private Receive startReceiver;
private const string Namespace = "http://company.namespace";
}
Use internal variables to pass values between internal activities.
Although not directly related to your code, see the example below which should give you the idea:
public sealed class CustomNativeActivity : NativeActivity<int>
{
private Variable<int> internalVar;
private Assign<int> internalAssign;
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
base.CacheMetadata(metadata);
internalVar = new Variable<int>("intInternalVar", 10);
metadata.AddImplementationVariable(internalVar);
internalAssign = new Assign<int>
{
To = internalVar,
Value = 12345
};
metadata.AddImplementationChild(internalAssign);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(internalAssign, (activityContext, instance) =>
{
// Use internalVar value, which was seted by previous activity
var value = internalVar.Get(activityContext);
Result.Set(activityContext, value);
});
}
}
Calling the above activity:
WorkflowInvoker.Invoke<int>(new CustomNativeActivity());
Will output:
12345
Edit:
In your case your OutArgument will be the internalVar
new OutArgument<int>(internalVar);
You need to use OutArgument and them to variables. See the code example with the documentation.
I may have tried everything I thought of, but I am stubborn and refuse to give up, so I kept on thinking ;)
I here have changed my example to use a Data class as a parameter instead (it does not change anything in itself, but I needed that in my real world example).
This code below is now a working example on how to access the incoming data. The use of an implementation Variable is the key:
runtimeVariable = new Variable<Data>();
metadata.AddImplementationVariable(runtimeVariable);
And the OutArgument:
new OutArgument<Data>(runtimeVariable)
I can then access the value with:
// Here dataValue will get the incoming value.
var dataValue = runtimeVariable.Get(context);
I haven't seen an example elsewhere, which does exactly this. Hope it will be of use to any one but me.
The code:
[DataContract]
public class Data
{
[DataMember]
Guid Property1 { get; set; }
[DataMember]
int Property2 { get; set; }
}
public class TestActivity : NativeActivity<Guid>
{
public ReceiveContent Content { get; set; }
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
runtimeVariable = new Variable<Data>();
metadata.AddImplementationVariable(runtimeVariable);
Content = ReceiveParametersContent.Create(new Dictionary<string, OutArgument>()
{
{"OutValue", new OutArgument<Data> (runtimeVariable)}
});
startReceiver = new Receive()
{
DisplayName = string.Format("Wait for workflow start request [Internal for {0}]", this.DisplayName),
CanCreateInstance = true,
ServiceContractName = XName.Get("IStartService", Namespace),
OperationName = "Start",
Content = Content
};
metadata.AddImplementationChild(startReceiver);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(startReceiver, ReceiveDone);
}
private void ReceiveDone(NativeActivityContext context, ActivityInstance completedInstance)
{
// Here dataValue will get the incoming value.
var dataValue = runtimeVariable.Get(context);
}
private Receive startReceiver;
private Variable<Data> runtimeVariable;
private const string Namespace = "http://company.namespace";
}

Resources