How can I reference an adapter within onCreateOptionsMenu, when the adapter is created inside OnPostExecute?
Within onCreateOptionsMenu I have two methods:
onQueryTextChange
onQueryTextSubmit
In each I use adapter.getFilter().filter(newText);.
What's the issue:
My adapter can not be assigned and used with getFilter() due to the structure of my code.
Because my my adapter is created within:
Class LoadInbox extends AsyncTask Protected String doInBackground OnPostExecute -> Created here
How can I reference my adapter within onPostExecute to work within onCreateOptionsMenu
Related
I'm creating an android application that contains one main activity and three fragments. There is a side navigation bar and depend on the selected menu item, it will replace the fragment loaded into the main screen.
In one of those fragments, I'm loading data from a REST API and once the data received, it will update the fragment UI. I'm using ok-http to send REST API calls. So in the onResponse() method, I have to call getActivity().runOnUiThread() to update the UI elements with received data and show Toast notifications for errors.
I already read that there is a chance to return null while calling getActivity() method within a fragment due to detach the fragment from the activity. I'm also aware that it's not a good idea to create a reference to the activity in onAttach() method and use it later like below, since it will prevent GC to clean that activity object after detaching from the fragment.
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
mActivity = (Activity)context;
}
Therefore I'm currently doing null check before calling getActivity() method as shown below which is recommended in most of the SO answers.
if (getActivity() != null) {
getActivity().runOnUiThread(() -> {
//Update UI
}
);
}
But according to the above code block, It's obvious that if there is no activity attached to the fragment (when getActivity() returns null), the UI will not be updated.
It's okay to not executing the UI updates if the fragment is not on the screen anymore. So my question is, is there any possibility of showing the fragment UI to the user while getActivity() returning null?
Here is my scenario: In my application i have a Main activity, two fragments and a service that runs in background. I attach the fragments to my main activity using this piece of code:
Fragment f1;
f1=new loginfragment();
FragmentTransaction ft=getFragmentManager().beginTransaction();
ft.add(R.id.frame,f1);
ft.commit();
Which is working fine. one of these fragments contains a listview which is attached to an adapter.(i have verified that adapter is correctly attached to the listview and entries can be added to listview without any problems.
In order to be able to inflate a layout inside the listview adapter(which extends BaseAdapter) i created a constructor to feed Context to it.
background service checks a page periodically and sends the results to one of these fragments using an interface that the fragment implements(sending broadcasts didn't work for me).interface is defined like this:
interface resultInterface{
void receive(String s,Context con);
}
fragment implements the interface like this:
#Override
public void receive(String s,Context con){
String elements[]=s.split("<br>");
if(elements.length>1) {
if(elements[0].equals("REQUEST")) {
init_notification("REQUEST",detect(elements[1],elements[2]));// a function that shows a notification
item i = new item(elements[1], elements[2]);
orders.add(i);
adapter = new listview_adapter(orders,c);
list.setAdapter(adapter);}
}
}
orders is an Arraylist and c is the context that is being passed to the listview adapter. service calls this interface method like this:
resultInterface resultinterface=new servefragment();
resulstinterface.receive(s,this);
upon receiving data (which results in calling the interface method) the fragment method is supposed to split the data and add entries to the listview.(i have verified that data is being correctly passed to the interface method.
BUT, the view that is being shown as listview entries is not correct( look corrupted somehow). Here is how it is supposed to look(using dummy data):Like this but here is how they are actually added(1 item is received from server which is correct but the layout is not): Like this
If you need more information just comment and i'll add them
My guess is that the Context object your service is passing to you has a different theme than you're expecting. This can cause text colors, button colors, etc to all change.
In order to be able to inflate a layout inside the listview adapter(which extends BaseAdapter) i created a constructor to feed Context to it.
Unless you need the Context instance somewhere other than inside getView(), you don't have to pass a Context via a constructor. Here's the full signature of the getView() method:
public View getView(int position, View convertView, ViewGroup parent)
The parent argument is guaranteed to be non-null, and all View instances have a getContext() method, so you can always retrieve a Context by writing parent.getContext(). Additionally, this will be your Activity (as opposed to something like your Application), which has the added benefit of having the correct theme.
So delete all of the code that passes the Context into your adapter and just use parent.getContext() instead, and I bet the problem goes away.
In my activity inside onStart() I bind into my custom service and create an instance of the service then I can call my service's public methods. Inside onStop() then I do unbindservice(myservice).
How can I do the same inside my listview adapter that extends BaseAdapter?
(There are public methods and variables I need to access inside onClickListener of my list items.)
If you succeed binding service with the activity then its simple to implement.
Just pass the service instance to the adapter either in constructor or via method. Then use the service instance on the adapter's OnClick mehtod.
MyService s;
...
// Binding is done s is service instance then
MyAdapter adapter = new MyAdapter(activityInstance, s, your data)
You might have access to the service instance s inside the adapter.
I have an adapter class and calling startActivityForResult() and getting the result in my Activity where I am using the adapter.
I want to change the image view background on getting the result.And the change should effect only the particular position of the RecyclerView.
startActivityForResult() inside the adapter class:
pass the context to your adapter class and do this:
((Activity)context).startActivityForResult(...);
As far as updating the RecyclerView, you can get the position inside the onBindViewHolder() and just update the class object from the List or ArrayListfor the image and call notifyDataSetChanged() after that.
P.S. this is the best I can do to explain to you without any code.
Edit : to get the TextView from the adapter class inside the Activity class:
View viewItem = recycleView.getLayoutManager().findViewByPosition(position);
TextView textView = viewItem.findViewById(R.id.textView);
textView.setTextColor(getResources().getColor(R.color.yourColor));
I have a listview NoteList which contains a method doListRefresh() to select list contents from the sqlite note table, populates a cursor (which populates my array adapter), then calls adapter.notifyDataSetChanged(); to refresh the list. Upon (add, edit, deletes etc)
Inside my custom Array adapter i populate several elements on each row including a delete button. Inside the array adapter i have the delete button onClick handler etc. I need to call NoteList.doListRefresh() from within my Array adapter and i do this by using a setter inside my array adapter which is called from NoteList something like adapter.setNoteListObj(this);. This is working but i'm not sure its the best way?
I wanted to ask if this is "best practice" for doing something like this?
Thank you for any advice
Here is some of the sample code:
Within NoteList:
onCreate(Bundle savedInstanceState) {
thisObject = this;
}
// set custom ArrayAdapter to the data
adapter = new NoteArrayAdapter(activity, R.layout.channel_note_list_item, noteList);
adapter.setNoteList(thisObject);
...
within Adapter:
private NoteList callingNoteListObj;
...
// setter
protected void setNoteList(NoteList _callingNoteListObj) {
this.callingNoteListObj = _callingNoteListObj;
}
...
// within delete onclick handler (after delete)
// refresh local database
callingNoteListObj.doListRefresh();
I don't see why not. All you are doing is passing a reference to the instance (a "pointer" for those who have done more than Java). Personally, I'd pass this into the constructor for your adapter and store the reference locally. In fact, you probably already do if you pass in this as a Context object in order to construct an ArrayAdapter. Since its your custom adapter for your custom NoteList, you could very well just cast context (or this.getContext()) to NoteList and call it without needing to use a setter.