Android view not updating on main thread - android

I have an array of data model items in the application class. My first activity has a broadcast receiver that alters the values of items in the list (via push if you are curious).
I have two kinds of visual representation for a model item and I want to be able to update the view whenever I get a push, regardless of where I am in the application.
My solution was that every model item has an interface reference to their view classes, so when I update the model, the model tells the interfaces to update the views.
My problem is that the views do not update, and I have verified, the code is running on the main thread.
public interface IWidget {
void setValue(int value);
}
public class MyView implements IWidget {
#Override
void setValue(int value){
}
}
public class Model{
int value;
IWidget iWidget;
public void setWidget(IWidget iWidget){
this.iWidget = iWidget;
}
public void setValue(int value){
this.value = value;
iWidget.setValue(value);
}
}

I was generating a view twice on 2 fragments of view pager, so I was not looking at the right one. The instance that was updating was the last one (not on the fragment I was initially looking on).

Related

Object List on RecyclerView

I'm having a little big problem on Android Studio. A have an object "Sport" that can have multiple lessons. So inside this object there is a list.
public class Sport implements Serializable {
private String cid;
private String cname;
String csportpic;
long ccreatedat;
List<Lesson> lessons;
public Sport() {
}
The object has gets and sets for each element. So the data coming from Firebase in well placed.
In a recycleview I want to display the lessons data and also some variable of the object sport(cname, cid), so I'm passing to the recycleview constructor the object Sport.
Do you have any ideia how to perform a loop through lesson List in a recyclerview? Can it be done inside onBindViewHolder?
Sorry, got it working.
For some reason the first loop was not working correctly. Perhaps the Object was not well written, or the query to the database.
public void onBindViewHolder(#NonNull final CoachVH holder, final int position)
{
for (Lesson lesson:sportlesson.get(position).getLessons())
{
holder.classid.setText(String.valueOf(new SimpleDateFormat("dd-MM-yyyy HH:mm").format(lesson.getLessonTime())));
holder.classname.setText(sportlesson.get(position).getCname());
holder.classaddress.setText(String.valueOf(lesson.getLessonAddress()));
holder.classprice.setText(String.valueOf(lesson.getLessonPrice()));
}
}

Listening for button click and linking fragment with view model

Im trying to learn view models and implement them in my app. I have been following a tutorial on getting me started but, I have a couple questions.
How do i listen for a button click? Since all the business logic is suppose to be stored in the view model would I put an OnClick listener there? Or would i put it with my onChange method in the activity that launches the fragment?
How to tell the fragment to use the view model?
Update was looking at this guys tutorial Location of click event in MVVM architecture . Isn't the whole point of mvvm to eliminate the need of interfaces?
Update 2: Found where you can use data binding to shove OnClick listener into button here: Handle onClick event with Databinding and MVVM and Using DataBinding library for binding events
Live data observe code from activity launching fragment
//private BattleRhythmViewModel battleModel;
battleModel = ViewModelProviders.of(this).get(BattleRhythmViewModel.class);
battleModel.getEvents().observe(this, new Observer<ArrayList<Event>>() {
#Override
public void onChanged(#Nullable ArrayList<Event> events) {
// Add newly created events to array/recycler view
// Another one for pushing new platform/content to database
}
});
}
View model for fragment
public class BattleRhythmViewModel extends ViewModel {
private MutableLiveData<ArrayList<Event>> battleRhythmEvents;
private MutableLiveData<ArrayList<TableData>> battleRhythmExtra;
public LiveData<ArrayList<Event>> getEvents()
{
return battleRhythmEvents;
}
public LiveData<ArrayList<TableData>> getExtras()
{
return battleRhythmExtra;
}
}

Passing searching data to Searchable Activity

I have a main activity which has 2 fragments. The main activity has a SearchView in the action bar. Both the fragments have a list of large number of strings, List<String>.
The flow is:
User enters Fragment I --> Selects a string (lets say Selection1) --> Based on Selection1 a list of strings is populated in the second fragment --> Here the user selects a second String ---> Processing based on these two strings.
Now since both the fragments contain a large number of strings, the user enters a query in the SearchView, which filters the list and reduces it to a smaller list displayed in the SearchableActivity.
Now the problem is how does the SearchableActivity get access to these two List<String> to filter them based on the query and display a reduced list to the user.
Currently what I have done is overridden onSearchRequested and pass the data as
#Override
public boolean onSearchRequested()
{
Bundle appData = new Bundle();
appData.putString(FRAGMENT_ID, "Fragment_A");
appData.putStringArrayList(SEARCH_LIST, searchList);
startSearch(null, false, appData, false);
return true;
}
Is there a better way or standard way by which this problem can be handled i.e. an implementation that allows data to be based from my MainActivity to SearchableActivity?
Edit: Adding code. Showing how data is set in the Fragment. onDataReceived is called from the HttpManager which receives the data.
#Override
public void onDataReceived(String type,final Object object)
{
switch(type)
{
case PopItConstants.UPDATE_LIST:
getActivity().runOnUiThread(new Runnable() {
#Override
public void run()
{
updateCinemaList((List<String>) object);
}
});
break;
}
}
public void updateDataList(List<String> data)
{
this.dataList = data;
spinner.setVisibility(View.GONE);
mAdapter.updateList(dataList);
}
I just answered a similar question a few minutes ago, at how can I send a List into another activity in Android Studio
I encourage you to rethink your pattern of simply passing data around among Activities and Fragments. Consider creating one or more data models (non-Android classes) for your application, and making these models available to the Android classes (Activities, Fragments, etc.) that need them.
Remove all of the data storage and manipulation code from your Activities and Fragments, and put it into the model(s).
Okay... So this is how I did it.
Basically, the data received in the two fragments was not simply List<String> but they were models viz. Cinema and Region which contained details other than names including location, rating etc.
So, firstly, I made an interface ISearchable
public Interface ISearchable
{
// This contains the Search Text. An ISearchable item is included
// in search results if query is contained in the String returned by this method
public String getSearchText();
//This is meant to return the String that must be displayed if this item is in search results
public String getDisplayText();
//This is meant to handle onClick of this searchableItem
public void handleOnClick();
}
Both the Cinema and Region models implemented ISearchable.
After this, I used a singleton class DataManager in which I maintained a List<ISearchable> currentSearchList.
public class DataManager
{
.....<singleton implementation>....
List<ISearchable> currentSearchList;
public void setSearchList(List<ISearchable> searchList)
{
this.currentSearchList = searchList;
}
public List<ISearchable> getSearchList()
{
return this.currentSearchList;
}
}
So whenever a fragment (either Fragment_A or Fragment_B) is loaded, it updates this currentSearchList, so that when the SearchableActivity performs search all it has to do is DataManager.getInstance().getSearchList() and then use this list for filtering out a list of matching items.
This is how I handled the problem of having Lists in Activity other than the SearchableActivity using which search needs to be performed.
I understand this might not be the best solution, so, I look forward to suggestions and criticisms, and using that to be arrive at a better solution.

How to restart activity with data of previous or next position of a ListView

I'm building a book reader app and currently having some issues on how to move to next or previous chapter.
The fragment that is in charge of showing a list of chapter (basically a ListView). I capture the item with onItemClick:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Intent intent = new Intent(getActivity().getApplicationContext(),ReaderActivity.class);
intent.putExtra("name",adapter.getItem(i).getName());
intent.putExtra("url",adapter.getItem(i).getUrl());
startActivity(intent);
}
});
It will start the ReaderActivity and display the content of the book. Now the ReaderActivity has 2 buttons for moving to next/previous chapter. How can I get the data (the name and url) from the ListView?
At the moment I'm thinking of two methods:
Calling finish() on ReaderActivity and override the onDestroy() method to call a method to get the next/previous data in the fragment that holds the ListView.
Passing the whole ArrayList of chapters to ReaderActivity so it can retrieve the item it wants (probably not a good solution since there are too many chapters).
Is there a better way?
There are way to many ways to get the best one.
Some of them:
Use your Application.java to share in-memory data (data stores) from any place. Example:
public final Application extends android.app.Application {
private List<Chapter> chapters;
public void setChapters(List<Chapter> chapters) {
this.chapters = chapters != null ? chapters : Collections.<Chapter>epmtyList();
}
public List<Chapter> get Chapters() {
return chapters;
}
}
// from any place which has context (or is context)
List<Chapter> chapters = ((Application) getContext().getApplicationContext()).getChapters();
Make your list a static member with a public static getter and then reference is from your ReaderActivity
public final ApplicationActivity extends Activity {
private static List<Chapter> chapters;
....
public static List<Chapter> getChapters() {
return chapters;
}
Store the list in shared preferences so any activity can reference it
Include the list of chapters in your intent extras and pass it to your ReaderActivity
I think your ReaderActivity needs to deal with the whole book rather a single chapter. Which means approach (4) is most likely a good candidate.
I would put the list data in the Application class (or another singleton), and then the ReaderActivity would be able to query it for the next chapter. Actually then it could just get the details of the next chapter and update its contents accordingly, without needing to create a new activity at all.

Detailed view of list row

In my project have to populate the list view from local database.I have implemented it.When I click the row in list item I need to show all the details in list row in next activity.I implemented custom list adapter.I not yet started to code for detailed list row.How can I pass all details in single row to another activity.Can anyone help me?
You can set the information in tags of textviews of your custom list and pass them through intents.
one thing that you can do is just pass the id (PK) of the item . Then on next activity you can fetch it again from database.
another options is that you can create a class with all the data you want to forward as class'members and serialize the object and send it along with the intent.
here is a example
public class ActivityExtra implements Parcelable {
public Integer a=0;
public String b="";
private GameActivityExtra(Parcel in) {
this.a = in.readInt();
this.b = in.readString();
}
public GameActivityExtra() {
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(a);
dest.writeString(b);
}
public static final Parcelable.Creator<GameActivityExtra> CREATOR = new Parcelable.Creator<GameActivityExtra>() {
public GameActivityExtra createFromParcel(Parcel in) {
return new GameActivityExtra(in);
}
public GameActivityExtra[] newArray(int size) {
return new GameActivityExtra[size];
}
};
}
now create instance of this class in your activity . and use intent.putextra(...) to put it . and get the same object while receiving it.
Use #nitesh goel answer to make your object class parcelabe.
Then onitemclick use
intent.putExtra("object", object);
to send your object to other activity.
And in corresponding activity use
intent.getParcelableExtra("object");
to get your object. then you can get everything of that object.

Categories

Resources