Unable to refresh/update browsefragment using ArrayObjectAdaptor's clear() and addAll() - android-tv

I have a browsefragment thats displaying rows from a JSON file generated by PHP when a PHP page is called. I am trying to get the browsefragment to refresh the rows as the JSON data will be changing regularly.
Following the instructions on https://hackernoon.com/how-to-refresh-the-android-tv-browsefragment-6e4d2d3c6690, I added clear() and addAll() methods found in the ArrayOjectAdapter.
The main portion of my browseFragment is:
public class MainFragment extends BrowseSupportFragment
implements LoaderManager.LoaderCallbacks<LinkedHashMap<String, List<Video>>>{
private static final int BACKGROUND_UPDATE_DELAY = 300;
private static final String TAG = MainFragment.class.getSimpleName();
static final int GRID_ITEM_WIDTH = 300;
private static final int GRID_ITEM_HEIGHT = 200;
private final Handler mHandler = new Handler();
private ArrayObjectAdapter mRowsAdapter;
private Drawable mDefaultBackground;
private DisplayMetrics mMetrics;
private Runnable mBackgroundTask;
private Uri mBackgroundURI;
private BackgroundManager mBackgroundManager;
private CustomListRow mGridItemListRow;
private LoaderManager mLoaderManager;
private static final int CATEGORY_LOADER = 123;
ArrayList<Video> mItems = null;
private ArrayList<CustomListRow> mVideoListRowArray;
private static final int VIDEO_ITEM_LOADER_ID = 1;
private static PicassoBackgroundManager picassoBackgroundManager = null;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
prepareBackgroundManager();
setupUIElements();
loadRows();
setRows();
mLoaderManager = LoaderManager.getInstance(this);
mLoaderManager.initLoader(VIDEO_ITEM_LOADER_ID, null, this);
setupEventListeners();
prepareEntranceTransition();
picassoBackgroundManager = new PicassoBackgroundManager(getActivity());
picassoBackgroundManager.updateBackgroundWithDelay("http://twende.phidampalmgardens.com/images/bkground/background1.jpg");
updateRecommendations();
if(mVideoListRowArray != null) {
new Handler().postDelayed(new Runnable() {
public void run() {
//mLoaderManager.restartLoader(CATEGORY_LOADER, null, MainFragment.this);
mRowsAdapter.clear();
mRowsAdapter.addAll(0, mVideoListRowArray);
}
}, 2000);
}
}
Unfortunately, I still cannot get the rows to refresh/update without having to close and reopen the app

Try adding the mRowsAdapter.notifyDataSetChanged(); statement:
mRowsAdapter.clear();
mRowsAdapter.addAll(0, mVideoListRowArray);
mRowsAdapter.notifyDataSetChanged();

Related

How do I handle media metadata in separate class?

Im making a mediaplayer using JavaFX Media classes. I made a SongModel class, that incapsulates all metadata from a file and creates Media and MediaPlayer instances.
It looks something like this:
private final StringProperty album =
new SimpleStringProperty(this, "album");
public String getAlbum(){ return album.get(); }
public void setAlbum(String value){ album.set(value); }
public StringProperty albumProperty() { return album; }
There are also artist, year, title, and albumCover fields that look just like that. Also, MediaPlayer property is exposed as a read-only:
public MediaPlayer getMediaPlayer(){ return mediaPlayer.get(); }
public ReadOnlyObjectProperty<MediaPlayer> mediaPlayerProperty(){
return mediaPlayer.getReadOnlyProperty();
}
I use a MapChangelistener to check if the field is available and then pass it to the handleMetadata method:
private void initializeMedia(String url){
try {
final Media media = new Media(url);
media.getMetadata().addListener(new MapChangeListener<String, Object>(){
#Override
public void onChanged(MapChangeListener.Change<? extends String, ? extends Object> ch) {
if(ch.wasAdded()){
handleMetadata(ch.getKey(), ch.getValueAdded());
}
}
});
mediaPlayer.setValue(new MediaPlayer(media));
mediaPlayer.get().setOnError(new Runnable() {
#Override
public void run() {
String errorMessage = mediaPlayer.get().getError().getMessage();
System.out.println("MediaPlayer error: "+errorMessage);
}
});
}catch(RuntimeException e){
System.out.println("Construction error: "+e);
}
}
private void handleMetadata(String key, Object value){
if(key.equals("album")){
setAlbum(value.toString());
} else if (key.equals("artist")){
setArtist(value.toString());
} if (key.equals("title")){
setTitle(value.toString());
} if (key.equals("year")){
setYear(value.toString());
} if (key.equals("image")){
setAlbumCover((Image)value);
}
}
Then I made an AbstractView class that provides access to SongModel:
public abstract class AbstractView {
protected final SongModel songModel;
protected final Node viewNode;
public AbstractView(SongModel songModel){
this.songModel = songModel;
this.viewNode = initView();
}
public Node getViewNode() {
return viewNode;
}
protected abstract Node initView();
}
But when I try to make a MetadataView class, I run into some problems.
Heres how it looks:
public class MetadataView extends AbstractView{
public Label artist;
public Label album;
public Label title;
public Label year;
public ImageView albumCover;
public MetadataView(SongModel songModel) {
super(songModel);
}
#Override
protected Node initView() {
artist = new Label();
artist.setId("artist");
album = new Label();
album.setId("album");
title = new Label();
title.setId("title");
year = new Label();
year.setId("year");
final Reflection reflection = new Reflection();
reflection.setFraction(0.2);
final URL url = getClass().getResource("resources/defaultAlbum.png");
Image image = new Image(url.toString());
albumCover = new ImageView(image);
albumCover.setFitWidth(240);
albumCover.setPreserveRatio(true);
albumCover.setSmooth(true);
albumCover.setEffect(reflection);
final GridPane gp = new GridPane();
gp.setPadding(new Insets(10));
gp.setHgap(20);
gp.add(albumCover, 0,0,1, GridPane.REMAINING);
gp.add(title, 1,0);
gp.add(artist, 1,1);
gp.add(album, 1,2);
gp.add(year, 1,3);
final ColumnConstraints c0 = new ColumnConstraints();
final ColumnConstraints c1 = new ColumnConstraints();
c1.setHgrow(Priority.ALWAYS);
gp.getColumnConstraints().addAll(c0,c1);
final RowConstraints r0 = new RowConstraints();
r0.setValignment(VPos.TOP);
gp.getRowConstraints().addAll(r0,r0,r0,r0);
return gp;
}
}
And heres how I call it in the start method:
metaDataView = new MetadataView(songModel);
The problem is that it displays only default metadata without taking it from the songmodel class. I tried running metadata view code together with data handling in one class and everything worked, but when i try to put them in separate classes - it doesnt. Music runs just fine, its just the data thats not displaying. Could anybody tell me what am I missing? How do i make it display metadata from a SongModel class? Ive spent a lot of time on that and dont want it to go to waste.
After a day of searching I have found an answer: binds. All I had to do was to bind label property of SongModel class to label property of MetadataView class:
title.textProperty().bind(songModel.titleProperty());
artist.textProperty().bind(songModel.artistProperty());
album.textProperty().bind(songModel.albumProperty());
year.textProperty().bind(songModel.yearProperty());
albumCover.imageProperty().bind(songModel.albumCoverProperty());

How to build JavaFX styleable objects properly, that can be GC

I decided to refactor my application because of hugh memory leaks in the old version. For visualization objects, I decide to not more using fxml, but Styleable interface.
So I created a class Sim Photo like this :
public class SimPhoto extends Control {
private static final String DEFAULT_CLASS_NAME = "sim-photo";
private static final Double DEFAULT_STROKE_WIDTH = 0.0;
#Getter
#Setter
private static String DEFAULT_PHOTO = "";
private StyleableStringProperty imgPath;
private StyleableIntegerProperty arcHeight;
private StyleableIntegerProperty arcWidth;
private DoubleProperty strokeWidth;
private ObjectProperty<Paint> stroke;
private ObjectProperty<Paint> fill;
public SimPhoto() {
initialize();
}
public SimPhoto(#NamedArg("imgPath") String imgPath) {
this();
this.imgPathProperty().set(imgPath);
}
//Example of init properties
public final StyleableIntegerProperty arcHeightProperty() {
if (arcHeight == null) {
arcHeight = new SimpleStyleableIntegerProperty(
StyleableProperties.ARC_WIDTH,
SimPhoto.this,
"arcWidth",
0
);
}
return arcHeight;
}
public final StringProperty imgPathProperty() {
if(imgPath == null) {
imgPath = new SimpleStyleableStringProperty(
StyleableProperties.IMG_PATH,
SimPhoto.this,
"imgPath",
"");
}
return imgPath;
}
(...)
}
In my skin class, I use binding of properties from Control Class
public class SimPhotoSkin extends SkinBase<SimPhoto> {
#Getter
private Rectangle photoFond = new Rectangle();
private Rectangle photoView = new Rectangle();
private boolean invalidate = false;
private InvalidationListener invalidListener = this::invalidated;
private ChangeListener<String> pathListener = this::pathChanged;
public SimPhotoSkin(SimPhoto control) {
super(control);
initVisualization();
initListeners();
}
private void initVisualization() {
getChildren().addAll(photoFond, photoView);
if (getSkinnable().imgPathProperty() != null) {
setNewFond(getSkinnable().getImgPath());
}
}
private void initListeners() {
photoFond.widthProperty().bind(getSkinnable().widthProperty().subtract(5));
photoFond.heightProperty().bind(getSkinnable().heightProperty().subtract(5));
photoView.widthProperty().bind(photoFond.widthProperty().subtract(photoFond.strokeWidthProperty()));
photoView.heightProperty().bind(photoFond.heightProperty().subtract(photoFond.strokeWidthProperty()));
photoView.arcWidthProperty().bind(getSkinnable().arcWidthProperty());
photoView.arcHeightProperty().bind(getSkinnable().arcHeightProperty());
photoFond.arcWidthProperty().bind(getSkinnable().arcWidthProperty());
photoFond.arcHeightProperty().bind(getSkinnable().arcHeightProperty());
photoFond.fillProperty().bind(getSkinnable().fillProperty());
photoFond.strokeProperty().bind(getSkinnable().strokeProperty());
photoFond.strokeWidthProperty().bind(getSkinnable().strokeWidthProperty());
getSkinnable().imgPathProperty().addListener(pathListener);
}
private void pathChanged(ObservableValue<? extends String> observable, String oldValue, String newValue) {
(...)
}
private void setNewFond(String path) {
(...)
}
private void invalidated(Observable observable) {
invalidate = true;
}
}
I know that object cannot been GC while exist a reference to it. So I have a big problem, because event these objects are no more used, thay cannot be GC , and in my application ,when I need creating more than 300 objects at time is a big problem.
I tried to create method clean(), that will be unbind all bidnings and listeners, but it's not realy helpful. Problem still persist.
I'm thinking about any workaround like a Manager, that will store all objects in queue and while calling will return one objects disponibles or create new one.
But this is the last possibility, if I dont find any solution for my problem, and I would like avoid this.

java.lang.NumberFormatException: Invalid int: "130 PHP"

I dont know how to solve this problem
i cant find my error in codes
pls help me solve it :( thanks!
private void loadListFood() {
cart = new Database(this).getCarts();
adapter = new CartAdapter(cart,this);
recyclerView.setAdapter(adapter);
int total = 0;
for(Order order:cart)
total+=(Integer.parseInt(order.getPrice()))*(Integer.parseInt(order.getQuantity()));
Locale locale = new Locale("en", "US");
NumberFormat fmt = NumberFormat.getCurrencyInstance(locale);
txtTotalPrice.setText(fmt.format(total));
}
i am being redirected to
total+=(Integer.parseInt(order.getPrice()))*(Integer.parseInt(order.getQuantity()));
here is my adapter codes
public class CartAdapter extends RecyclerView.Adapter<CartViewHolder>{
private List<Order> listData = new ArrayList<>();
private Context context;
public CartAdapter(List<Order> cart, Cart cart1)
{
}
#Override
public CartViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View itemView = inflater.inflate(R.layout.cartlayout,parent,false);
return new CartViewHolder(itemView);
}
#Override
public void onBindViewHolder(CartViewHolder holder, int position) {
TextDrawable drawable = TextDrawable.builder()
.buildRound(""+listData.get(position).getQuantity(), Color.RED);
holder.img_cart_count.setImageDrawable(drawable);
int price = (Integer.parseInt(listData.get(position).getPrice()))*(Integer.parseInt(listData.get(position).getQuantity()));
holder.txt_price.setText(price);
holder.txt_cart_name.setText(listData.get(position).getProductName());
}
#Override
public int getItemCount() {
return listData.size();
}
}
From JavaDoc: The method Integer.parseInt(String s) throws a NumberFormatException
if the string does not contain a parsable integer.
That means, method order.getPrice() or order.getQuantity() returns "130 PHP" which is not a valid Integer.
Your real problem might be: Why the method returns a String and not Integer because you have to parse your String now. Pretty error prone and bad practice.
If your GUI element (or whatever) does not fit with Integer, at least remove your "PHP" out of the input field and you might be able to parse your String without manipulate it with some String helper methods.
class CartViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
, View.OnCreateContextMenuListener {
public TextView txt_cart_name,txt_price;
public ImageView img_cart_count;
private ItemClickListener itemClickListener;
public void setTxt_cart_name(TextView txt_cart_name) {
this.txt_cart_name = txt_cart_name;
}
public CartViewHolder(View itemView) {
super(itemView);
txt_cart_name = (TextView)itemView.findViewById(R.id.cart_item_name);
txt_price = (TextView)itemView.findViewById(R.id.cart_item_Price);
img_cart_count = (ImageView)itemView.findViewById(R.id.cart_item_count);
itemView.setOnCreateContextMenuListener(this);
}
#Override
public void onClick(View view) {
}
#Override
public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
contextMenu.setHeaderTitle("Selecione uma Ação");
contextMenu.add(0,0,getAdapterPosition(),Common.DELETE);
}
}
public class CartAdapter extends RecyclerView.Adapter<CartViewHolder> {
private List<Order> listData = new ArrayList<>();
private Context context;
public CartAdapter(List<Order> listData, Context context) {
this.listData = listData;
this.context = context;
}
#Override
public CartViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View itemView = inflater.inflate(R.layout.cart_layout,parent,false);
return new CartViewHolder(itemView);
}
#Override
public void onBindViewHolder(CartViewHolder holder, int position) {
TextDrawable drawable = TextDrawable.builder()
.buildRound(""+listData.get(position).getQuantity(), Color.BLUE);
holder.img_cart_count.setImageDrawable(drawable);
Locale locale = new Locale("pt","BR");
NumberFormat fmt = NumberFormat.getCurrencyInstance(locale);
int price = (Integer.parseInt(listData.get(position).getPrice()))*(Integer.parseInt(listData.get(position).getQuantity()));
holder.txt_price.setText(fmt.format(price));
holder.txt_cart_name.setText(listData.get(position).getProductName());
}
#Override
public int getItemCount() {
return listData.size();
}
}

How to access objects from event listener in javafx

I have an object Contract and it contains Summary and Observable List of another object ContractDetails inside it.
Now, I am using ContractDetails to populate in tableview from Contract object.
I have a save button, which on clicking needs to save Contract along with ContractDetails. I am able to access ContractDetails since they are in tableview.
How do I access Contract properties in eventlistener of save button.
The related code is given below
public class Contract {
private String tradeDate;
private String contractNote;
.....
.....
private String brokerId;
private ObservableList<ContractDetails> contractdetails = FXCollections.observableArrayList();
public Contract() {
}
public Contract(String tradeDate, String contractNote, ....., String brokerId,ObservableList<ContractDetails> contractdetails) {
this.tradeDate = tradeDate;
this.contractNote = contractNote;
....
....
this.contractdetails=contractdetails;
}
public String getTradeDate() {
return tradeDate;
}
public void setTradeDate(String tradeDate) {
this.tradeDate = tradeDate;
}
public String getContractNote() {
return contractNote;
}
public void setContractNote(String contractNote) {
this.contractNote = contractNote;
}
....
....
public ObservableList<ContractDetails> getContractdetails() {
return contractdetails;
}
public void setContractdetails(ObservableList<ContractDetails> contractdetails) {
this.contractdetails = contractdetails;
}
}
public class ContractDetails {
private String orderNo;
private String contractType;
private String symbol;
private String buysell;
private Integer quantity;
private Double buysellprice;
private Double netcontractValue;
public ContractDetails() {
}
public ContractDetails(String orderNo, String contractType, String symbol, String buysell, Integer quantity, Double buysellprice, Double netcontractValue) {
this.orderNo = orderNo;
this.symbol = symbol;
this.buysell = buysell;
this.quantity = quantity;
this.buysellprice = buysellprice;
this.netcontractValue = netcontractValue;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
....
....
public Double getNetcontractValue() {
return netcontractValue;
}
public void setNetcontractValue(Double netcontractValue) {
this.netcontractValue = netcontractValue;
}
}
In the controller
==================
public class ContractViewController implements Initializable {
#FXML
private TableView<ContractDetails> tblcontractfx;
#FXML
private TableColumn<ContractDetails, String> contractTypefx;
#FXML
private TableColumn<ContractDetails, String> symbolfx;
....
....
#FXML
private Button savefx;
#FXML
private TextField txtclientcodefx;
#FXML
private TextField txttradedtfx;
private void fetchContracts(TableView tableView, Contract contract)
{ txttradedtfx.setText(contract.getTradeDate());
txtclientcodefx.setText(contract.getClientCode());
symbolfx.setCellValueFactory(new PropertyValueFactory<ContractDetails, String>("symbol"));
contractTypefx.setCellValueFactory(new PropertyValueFactory<ContractDetails, String>("contractType"));
tableView.setItems((ObservableList) contract.getContractdetails());
#FXML
private void saveClicked(ActionEvent event) { DBConnection DBcon = new DBConnection();
//Now I am getting the contract details from tableview tblcontractfx
ObservableList<ContractDetails> contractdetails = tblcontractfx.getItems();
//How do I get the summary values from contract. I am able to get those which are in text fields like txttradedtfx and txtclientcodefx.However contractNote which I am not using, I still need to retrieve it to populate into database.
String clientCode=txtclientcodefx.getText();
Thanks
Just store the contract in a local variable.
Contract contract;
private void fetchContracts(TableView tableView, Contract contract)
{
this.contract = contract;
...
}
private void saveClicked(ActionEvent event) {
// here you have full access to the contract variable
String contractNote = contract.getContractNote();
}
As an alternative, if you insist on combining it all in a single table, you could put the Contract into the table via setUserData and retrieve it via getUserData.
By the way, I still don't get your code. Why is there a tableView parameter when you have full access to TableView<ContractDetails> tblcontractfx

GXT 3 Can't fill Grid

I want to load data from a remote server in the grid. The following code:
final RepServiceAsync service = GWT.create(RepService.class);
final RepProperties props = GWT.create(RepProperties.class);
RpcProxy<PagingLoadConfig, PagingLoadResult<ReportsList>> proxy = new RpcProxy<PagingLoadConfig, PagingLoadResult<ReportsList>>() {
#SuppressWarnings("unchecked")
#Override
public void load(PagingLoadConfig loadConfig, AsyncCallback callback) {
service.getReports(callback);
}
};
ListStore<ReportsList> store = new ListStore<ReportsList>(props.key());
final PagingLoader<PagingLoadConfig, PagingLoadResult<ReportsList>> loader = new PagingLoader<PagingLoadConfig, PagingLoadResult<ReportsList>>(
proxy);
loader.setRemoteSort(true);
loader.addLoadHandler(new LoadResultListStoreBinding<PagingLoadConfig, ReportsList, PagingLoadResult<ReportsList>>(
store));
final PagingToolBar toolBar = new PagingToolBar(50);
toolBar.getElement().getStyle().setProperty("borderBottom", "none");
toolBar.bind(loader);
ColumnConfig<ReportsList, String> nameCol = new ColumnConfig<ReportsList, String>(
props.name(), 150, "Name");
ColumnConfig<ReportsList, String> pathCol = new ColumnConfig<ReportsList, String>(
props.path_name(), 150, "Path");
List<ColumnConfig<ReportsList, ?>> l = new ArrayList<ColumnConfig<ReportsList, ?>>();
l.add(nameCol);
l.add(pathCol);
ColumnModel<ReportsList> cm = new ColumnModel<ReportsList>(l);
Grid<ReportsList> grid = new Grid<ReportsList>(store, cm) {
#Override
protected void onAfterFirstAttach() {
super.onAfterFirstAttach();
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override
public void execute() {
loader.load();
}
});
}
};
grid.getView().setForceFit(true);
grid.setLoadMask(true);
grid.setLoader(loader);
RepProperties:
public interface RepProperties extends PropertyAccess<ReportsList> {
#Path("id")
ModelKeyProvider<ReportsList> key();
ValueProvider<ReportsList, String> name();
ValueProvider<ReportsList, String> path_name();
}
ReportsList code:
public class ReportsList implements Serializable {
private static final long serialVersionUID = 1L;
int id;
String name;
String path_name;
public ReportsList() {
}
public ReportsList(int id, String name, String path_name) {
super();
this.id = id;
this.name = name;
this.path_name = path_name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPath_name() {
return path_name;
}
public void setPath_name(String path_name) {
this.path_name = path_name;
}
}
GWT Servlet Impl:
public class RepServiceImpl extends RemoteServiceServlet implements RepService {
private static final long serialVersionUID = 1L;
#EJB
private ReportEjb repManager;
#Override
public List<Report> getReports() {
List<Report> reports = null;
reports = repManager.getReports();
return reports ;
}
}
The code is executed without error, the query to the database is performed ( EJB-call ), but the Grid is not populated.
In what could be the problem?
In my experience this usually means that there is an exception while trying to put data into the grid itself. Try attaching a LoadExceptionHandler to your loader and see what it gives you
e.g.
public class DebugLoadHandler implements LoadExceptioniHandler<ListLoadConfig> {
#Override
public void onLoadException(LoadExceptionEvent<ListLoadConfig> event) {
Window.alert("Load Exception" + event.getException().getMessage());
}
}

Resources