I have created a custom UI component TextInputPro that renders an EditText. I also have a native module that I can send events like focus() to.
My files are
|-- TextInputProPackage.java <--- packages all together
|-- TextInputProManager.java <--- creates a view (EditText)
|-- TextInputProModule.java <--- gets events from JS
How can TextInputProModule.java communicate with the View created by TextInputProManager.java?
TextInputProPackage.java:
public class TextInputProPackage implements ReactPackage {
#Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
// MODULE CREATED HERE
return Arrays.<NativeModule>asList(
new TextInputProModule(reactContext)
);
}
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
//VIEW CREATED HERE
return Arrays.<ViewManager>asList(
new TextInputProManager()
);
}
}
TextInputProManager.java:
public class TextInputProManager extends SimpleViewManager<EditText> {
public static final String REACT_CLASS = "TextInputPro";
public EditText editText;
#Override
public String getName() {
return REACT_CLASS;
}
#Override
public EditText createViewInstance(ThemedReactContext context){
editText = new EditText(context);
editText.setText("hello world");
return editText;
}
}
TextInputProModule.java:
public class TextInputProModule extends ReactContextBaseJavaModule {
public static final String REACT_CLASS = "TextInputPro";
private static ReactApplicationContext reactContext = null;
public TextInputProModule(ReactApplicationContext context) {
super(context);
reactContext = context;
}
#Override
public String getName() {
return REACT_CLASS;
}
#ReactMethod
public void focus () {
// WHERE ARE YOU EDITTEXT?
}
}
In my head, I have to make a global variable in Package.java and pass it down to both constructors, but I couldn't make that work
Related
I am building a custom component in Java and trying to display that in React Native but the component is not appearing. I've been looking through forums and documentation for solutions but can't find a solution. I am not sure if it's an issue on the native side or the React Native side. Any help or advice on improvement is highly appreciated.
Bottom Sheet View
public class BottomSheetView extends NestedScrollView {
private BottomSheetBehavior bSheetBehavior;
public BottomSheetView(Context context) {
super(context);
init();
}
private void init() {
inflate(getContext(), R.layout.bottom_sheet, this);
CoordinatorLayout coordinaterLayout = findViewById(R.id.coordinate_layout);
View bottomSheet = coordinaterLayout.findViewById(R.id.bottom_sheet_component);
bSheetBehavior = BottomSheetBehavior.from(bottomSheet);
bSheetBehavior.setHideable(false);
bSheetBehavior.setPeekHeight((int) PixelUtil.toPixelFromDIP(200));
}
#Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
}
}
Bottom Sheet Manager
public class BottomSheetManager extends ViewGroupManager<BottomSheetView> {
public static final String REACT_CLASS = "BottomSheet";
private BottomSheetView bottomSheet;
#Override
public String getName() {
return REACT_CLASS;
}
#Override
protected BottomSheetView createViewInstance(ThemedReactContext reactContext) {
return new BottomSheetView(reactContext);
}
}
Bottom Sheet Package
public class BottomSheetPackage implements ReactPackage {
private Activity mActivity = null;
BottomSheetPackage(Activity activity) {
mActivity = activity;
}
public BottomSheetPackage() {
}
#Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = Collections.emptyList();
return modules;
}
#Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(new BottomSheetManager());
}
}
React Native
class BottomSheet extends Component {
render() {
return (<BottomSheet style={{height: 200}}/>);
}
}
Android add Paging Library as part of Architecture Component for using the pagination of the resource. I use this example for do it. I write these codes but in my DataSource.Factory I can't return my received DataSource from network. let's see my codes:
PostDataSource:
public class PostDataSource extends PageKeyedDataSource {
private final APIUtils api = RetrofitHelper.getInstance().create(APIUtils.class);
private final String TOKEN = TokenUtil.getCachedAuthToken();
private int page = 1;
private GeneralWebResult<ArrayList<Post>> postList;
#Override
public void loadInitial(#NonNull LoadInitialParams params, #NonNull LoadInitialCallback callback) {
api.getMainPosts("all",10,"new",page,TOKEN).enqueue(new Callback<GeneralWebResult<ArrayList<Post>>>() {
#Override
public void onResponse(Call<GeneralWebResult<ArrayList<Post>>> call, Response<GeneralWebResult<ArrayList<Post>>> response) {
postList = response.body();
callback.onResult(/*return ArrayList<Post> */postList.getResult(),null, ++ page);
Log.e("RESULT",response.code()+" ");
}
#Override
public void onFailure(Call<GeneralWebResult<ArrayList<Post>>> call, Throwable t) {
Log.e("ERROR",t.getLocalizedMessage());
}
});
}
#Override
public void loadBefore(#NonNull LoadParams params, #NonNull LoadCallback callback) {
}
#Override
public void loadAfter(#NonNull LoadParams params, #NonNull LoadCallback callback) {
ArrayList<Post> postList = new ArrayList<>();
api.getMainPosts("all",10,"new",page,TOKEN).enqueue(new Callback<GeneralWebResult<ArrayList<Post>>>() {
#Override
public void onResponse(Call<GeneralWebResult<ArrayList<Post>>> call, Response<GeneralWebResult<ArrayList<Post>>> response) {
postList.addAll(response.body().getResult());
callback.onResult(postList,null);
Log.e("RESULT",response.code()+" ");
}
#Override
public void onFailure(Call<GeneralWebResult<ArrayList<Post>>> call, Throwable t) {
Log.e("ERROR",t.getLocalizedMessage());
}
});
}
}
PostDataSourceFactory:
public class PostDataSourceFactory extends DataSource.Factory {
private PostDataSource dataSource;
#Override
public DataSource create() {
return new PostDataSource();
}
}
PostViewModel:
public class PostViewModel extends ViewModel {
public LiveData<PagedList<Post>> liveDataSource;
public PostViewModel() {
Executor executor = Executors.newFixedThreadPool(5);
PostDataSourceFactory factory = new PostDataSourceFactory(executor);
PagedList.Config config = new PagedList.Config.Builder().setEnablePlaceholders(false)
.setInitialLoadSizeHint(10).setPageSize(10).setPrefetchDistance(4).build();
liveDataSource = (new LivePagedListBuilder(factory,config)).setFetchExecutor(executor).build();
//Log.e("LIVE DATA SOURCE", liveDataSource.getValue().get(0).getContent());
}
}
PostAdapter:
public class PostAdapter extends PagedListAdapter<Post, PostAdapter.Holder> {
private PagedList<Post> items;
public void setItems(PagedList<Post> items) {
this.items = items;
}
public class Holder extends RecyclerView.ViewHolder{
TextView content;
Holder(View itemView) {
super(itemView);
content = itemView.findViewById(R.id.item_post_test_content);
}
void bindTo(Post post){
content.setText(post.getContent());
}
}
PostAdapter() {
super(Post.DiffCAllback);
}
#NonNull
#Override
public PostAdapter.Holder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new Holder(LayoutInflater.from(parent.getContext()).inflate(R.layout.post_test_item,parent,false));
}
#Override
public void onBindViewHolder(#NonNull PostAdapter.Holder holder, int position) {
holder.bindTo(getItem(position));
}
}
MainActivity:
list = findViewById(R.id.home_list);
list.setLayoutManager(new LinearLayoutManager(this));
PostViewModel viewModel = ViewModelProviders.of(this).get(PostViewModel.class);
PostAdapter adapter = new PostAdapter();
viewModel.liveDataSource.observe(this,items ->{
Log.e("ITEMS SIZE",items.size()+" ");
adapter.setItems(items);
} );
list.setAdapter(adapter);
Where is my mistake? why PostDataSourceFactory return null on create()?
Use a MutableLiveData object to wrap your data source
MutableLiveData is used for notifying your UI when observing any data
When using LivePagedListBuilder it is advisable to use a MutableLiveData as a wrapper for data source
See PagingWithNetworkSample
You also need to update your data source PagedKeyDataSource
public class PostDataSourceFactory extends DataSource.Factory<Integer, Post> {
public MutableLiveData<PostDataSource> datasourceLiveData = new MutableLiveData<>();
public PostDataSourceFactory(
}
#Override
public DataSource<Integer, Post> create() {
PostDataSource dataSource = new PostDataSource();
datasourceLiveData.postValue(dataSource);
return dataSource;
}
}
When the method(Bill) is called the widgets that I initialized with Butterknife is returning null(noPrev and recyclerList).
In other classes like activities, I used the same method(Binding the widget with BUtterknife) and It is working well but when I tried binding my widgets inside the fragment, it always returning null.
........................................................................
public class Home extends Fragment implements BridgeInterface.BillsResponse{
#BindView(R.id.rvBillList)
RecyclerView recyclerList;
#BindView(R.id.tvNoPreviousBill)
TextView noPrev;
public List<Bill> list_of_bill = new ArrayList<>();
private BillRecyclerAdapter adapter;
private Handler h;
private Runnable r;
private View v;
public Home() {
// Required empty public constructor
}
public static Home getInstance() {
Home home = new Home();
return home;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.fragment_home, container, false);
ButterKnife.bind(Home.this,v);
if(list_of_bill.size()==0){
noPrev.setVisibility(View.VISIBLE);
recyclerList.setVisibility(View.GONE);
} else{
noPrev.setVisibility(View.GONE);
recyclerList.setVisibility(View.VISIBLE);
}
return v;
}
#Override
public void onResume() {
super.onResume();
h = new Handler();
r = () -> {
BridgeInterface.GetBIlls getBIlls =
new BillsRequest(getContext());
getBIlls.request();
h.postDelayed(r,5000);
};
r.run();
}
#Override
public void Bill(List<Bill> bills) {
list_of_bill = bills;
initRecycler();
}
public void initRecycler() {
noPrev.setVisibility(View.GONE);
recyclerList.setVisibility(View.VISIBLE);
adapter = new BillRecyclerAdapter(list_of_bill);
recyclerList.setAdapter(adapter);
recyclerList.setLayoutManager(new LinearLayoutManager(getContext()));
}
}
Here's the Interface Class
public interface BridgeInterface {
interface BillsResponse{
void Bill(List<Bill> bills);
}
interface GetBIlls{
void request();
}
}
BillRequest Class;:::
public class BillsRequest implements BridgeInterface.GetBIlls {
private Context context;
private final String url = "http://"+
AppSingleton.getInstance().getIP_ADDRESS()
+"/waterdistrict/bills.php";
private Gson gson;
public BillsRequest(Context context ) {
this.context = context;
}
#Override
public void request() {
StringRequest request = new StringRequest(Request.Method.GET, url,
response -> {
gson = new GsonBuilder().create();
List<BillResponse> bill_response =
Arrays.asList(gson.fromJson(response,
BillResponse.class));
Log.d("Check", "Levl 2");
Home.getInstance().Bill(bill_response.get(0).getBills());
}, error -> {
Log.d("Error", error.toString());
});
RequestQueue queue = Volley.newRequestQueue(context);
queue.add(request);
}
}
I have multiple ViewHolders that work as separated views inside a vertical RecyclerView. I'm practicing with the new Architecture Components ViewModel.
Inside my ViewModel I have a couple of MutableLiveData lists that i want to observe, but how can I call
ViewModelProviders.of((AppCompatActivity)getActivity()).get(FilterViewModel.class)
and
mFilterViewModel.getCountries().observe(this, new Observer<ArrayList<TagModel>>() {
#Override
public void onChanged(#Nullable ArrayList<TagModel> tagModels) {
}
});
without leaking the activity or save the activity inside the adapter?
my ViewModel
public class FilterViewModel extends ViewModel {
private final MutableLiveData<ArrayList<TagModel>> mCountries;
private final MutableLiveData<ArrayList<TagModel>> mSelectedCountryProvinceList;
private final MutableLiveData<ArrayList<TagModel>> mDistanceList;
public FilterViewModel(){
mCountries = new MutableLiveData<>();
mSelectedCountryProvinceList = new MutableLiveData<>();
mDistanceList = new MutableLiveData<>();
TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
#Override
public void update(TagSearchList object) {
mCountries.setValue(object.getCountries());
}
#Override
public void update(int id, TagSearchList object) {
if (id == 5){
TagStore.getInstance().unSubcribe(this);
update(object);
}
}
#Override
public void error(String error) {
}
}).get(5,"parent");
TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
#Override
public void update(TagSearchList object) {
mSelectedCountryProvinceList.setValue(object.toList());
}
#Override
public void update(int id, TagSearchList object) {
if (id == 6){
TagStore.getInstance().unSubcribe(this);
update(object);
}
}
#Override
public void error(String error) {
}
}).get(6,"parent");
TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
#Override
public void update(TagSearchList object) {
mDistanceList.setValue(object.toList());
}
#Override
public void update(int id, TagSearchList object) {
if (id == 51){
TagStore.getInstance().unSubcribe(this);
update(object);
}
}
#Override
public void error(String error) {
}
}).get(51,"parent");
}
public void selectCountry(final TagModel country){
TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
#Override
public void update(TagSearchList object) {
mSelectedCountryProvinceList.setValue(object.toList());
}
#Override
public void update(int id, TagSearchList object) {
if (id == country.getId()){
TagStore.getInstance().unSubcribe(this);
update(object);
}
}
#Override
public void error(String error) {
}
}).get(country.getId(),"parent");
}
public LiveData<ArrayList<TagModel>> getCountries(){
return mCountries;
}
public LiveData<ArrayList<TagModel>> getDistances(){
return mDistanceList;
}
public LiveData<ArrayList<TagModel>> getProvinces(){
return mSelectedCountryProvinceList;
}
I am using Room Persistence library. Below is my code for recyclerview adapter using MVVM.
You can see CartViewModel and I have initialized it into the constructor. The constructor gets the context from the activity, and I have cast it into FragmentActivity.
private CartViewModel cartViewModel;
public CartListAdapter(Context context, List<CartModel> cartModels) {
this.context = context;
this.cartModels = cartModels;
cartViewModel = ViewModelProviders.of((FragmentActivity) context).get(CartViewModel.class);
}
Here is my full adapter class. I hope it will help.
public class CartListAdapter extends RecyclerView.Adapter<CartListAdapter.CartListViewHolder> {
private static final String TAG = "CartListAdapter";
private Context context;
private List<CartModel> cartModels;
private Double totalQuantity = 0.0;
private CartViewModel cartViewModel;
public CartListAdapter(Context context, List<CartModel> cartModels) {
this.context = context;
this.cartModels = cartModels;
cartViewModel = ViewModelProviders.of((FragmentActivity) context).get(CartViewModel.class);
}
#NonNull
#Override
public CartListViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new CartListViewHolder(LayoutInflater.from(context).inflate(R.layout.list_all_cart_item,parent,false));
}
#Override
public void onBindViewHolder(#NonNull CartListViewHolder holder, int position) {
CartModel cartModel = cartModels.get(position);
Glide.with(context)
.load(cartModel.getPPICLocate())
.into(holder.cartItemImage);
holder.tvCartProductName.setText(cartModel.getProductName());
holder.tvCartProductCategory.setText(cartModel.getPCategorySubID());
holder.tvCartProductPrice.setText(cartModel.getPPriceSales());
holder.etCartProductQuantity.setText(cartModel.getPQuantity());
holder.btnCartPQtIncrease.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
totalQuantity = Double.valueOf(holder.etCartProductQuantity.getText().toString());
totalQuantity = totalQuantity+1;
cartModel.setPQuantity(totalQuantity.toString());
updateCart(cartModel);
}
});
holder.btnCartPQtDecrease.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
totalQuantity = Double.valueOf(holder.etCartProductQuantity.getText().toString());
totalQuantity = totalQuantity-1;
cartModel.setPQuantity(totalQuantity.toString());
updateCart(cartModel);
}
});
}
#Override
public int getItemCount() {
return cartModels.size();
}
public class CartListViewHolder extends RecyclerView.ViewHolder{
private ImageView cartItemImage;
private TextView tvCartProductName,tvCartProductCategory,tvCartProductPrice,
etCartProductQuantity,tvCartProductPrevPrice;
private ImageButton btnCartPQtIncrease,btnCartPQtDecrease;
public CartListViewHolder(#NonNull View itemView) {
super(itemView);
cartItemImage= itemView.findViewById(R.id.cartItemImage);
tvCartProductName= itemView.findViewById(R.id.tvCartProductName);
tvCartProductCategory= itemView.findViewById(R.id.tvCartProductCategory);
tvCartProductPrice= itemView.findViewById(R.id.tvCartProductPrice);
etCartProductQuantity= itemView.findViewById(R.id.etCartProductQuantity);
tvCartProductPrevPrice= itemView.findViewById(R.id.tvCartProductPrevPrice);
btnCartPQtIncrease= itemView.findViewById(R.id.btnCartPQtIncrease);
btnCartPQtDecrease= itemView.findViewById(R.id.btnCartPQtDecrease);
}
}
public void addItems(List<CartModel> cartModels) {
this.cartModels = cartModels;
notifyDataSetChanged();
}
private void updateCart(CartModel cartModel){
String tqt = String.valueOf(cartModel.getPQuantity());
Log.d(TAG, "updateQuantity: "+tqt);
/*cartRepository.updateCartRepo(cartModel);*/
cartViewModel.updateCartItemVM(cartModel);
}
}
You could create an OnClickListener interface instead, then implement the onClick method (defined in your interface) in your fragment or activity where you have access to your view model.
My solution to this issue is;
create a new variable(ViewModel) for the layout (fragment or activity layout)
in your activity or fragment get the instance of your viewModel with ViewModelProviders
hold the data which fills your recyclerView in MutableLiveData and observe it and fill the adapter of recyclerView with the value you observed
here you mut be careful not to create adapter instance in observe method.
if you create it in observe method, it will make leaks
I'm setting up my first Vaadin application with Vaadin 7.5.6 and the official Vaadin Spring 1.0.0. I want to use the MVP pattern but I'm asking myself how the components work together. Because I'm new to MVP i don't want to use any Addons, so i tried to set it up by myself.
So if I'm right, the LoginViewPresenter will give me the view over presenterInstance.getView(). This is already working fine, but how should i access to the presenter over the view? When i want to do a logic operation for my view i should do it in the presenter class. But how to call a presenter method from a view Buttonclicklistener?
My second question is if I have the UIScope annotation over my presenter class, when does Spring instantiate a new object from this class? I thougt as long as the UI exists. But after generating a random string in the constructor I'm printing out the content of the randomString variable (in the UI.class init() method) but there is always a new value.
Regards
LoginViewPresenter.java
#SpringComponent
#UIScope
public class LoginViewPresenter implements Serializable
{
private static final long serialVersionUID = 6286518141570430211L;
#Autowired
private LoginView view;
public final String randomString;
public LoginViewPresenter()
{
randomString = Utils.generateRandomString(8);
}
#PostConstruct
public void init()
{
}
public LoginView getView()
{
return view;
}
public void setView(LoginView view)
{
this.view = view;
}
}
LoginView.java
#SuppressWarnings("serial")
#UIScope
#SpringView(name = LoginView.NAME)
public class LoginView extends VerticalLayout implements View
{
public static final String NAME = "LoginView";
#PostConstruct
private void init()
{
}
#Override
public void enter(ViewChangeEvent event)
{
}
}
Your view should'nt be aware of the presenter. It should fire events, and your presenter can listen to them.
Here is how I do it:
LoginView.java
#SuppressWarnings("serial")
#UIScope
#SpringView(name = LoginView.NAME)
public class LoginView extends VerticalLayout implements View {
public static final String NAME = "LoginView";
#Autowired
private transient Collection<LoginViewListener> loginViewListeners;
#PostConstruct
private void init() {
...
Button b = new Button("click me");
b.addClickListener(e -> loginViewListeners.forEach(l -> l.eventFired()));
addComponent(b);
...
loginViewListeners.forEach(listener -> listener.viewInitialized(this));
}
#Override
public void enter(ViewChangeEvent event)
{
}
public interface LoginViewListener {
void viewInitialized(LoginView view);
void eventFired();
}
}
LoginViewPresenter.java
#SpringComponent
#UIScope
public class LoginViewPresenter implements LoginViewListener, Serializable {
private static final long serialVersionUID = 6286518141570430211L;
private LoginView view;
public final String randomString;
public LoginViewPresenter() {
randomString = Utils.generateRandomString(8);
}
#PostConstruct
public void init() {
}
public LoginView getView() {
return view;
}
public void setView(LoginView view) {
this.view = view;
}
#Override
public void viewInitialized(LoginView v) {
setView(v);
}
#Override
void eventFired() {
...
}
}
Does your randomString still have always a new value with this design?