Categories
discuss

Basic ConstraintLayout (Toolbar, fragment container, and bottom nav)

I’m adapting to Kotlin and ConstraintLayouts for Android. I’m trying to have a simple layout that has a toolbar and a bottom navigation view.

Here is my current xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimaryDark"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/app_name"
            android:textColor="@android:color/white"
            android:textSize="@dimen/toolbar_title_text_size"
            android:textStyle="bold" />

    </android.support.v7.widget.Toolbar>

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@color/colorAccent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/toolbar"
        app:layout_constraintBottom_toTopOf="@id/bottom_navigation_view"/>

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/bottom_navigation_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:menu="@menu/menu_main" />

</android.support.constraint.ConstraintLayout>

Unfortunately, I’m misunderstanding something and cannot seem to get the fragment container to fill the space between the toolbar and the bottom navigation.

Can someone steer me in the correct direction?

Answer

Height in your fragment container needs to be 0dp, which is the equivalent of “MATCH_CONSTRAINT”.

android:layout_height="0dp"

You can look it up here ConstraintLayout.

It should be

<FrameLayout
    android:id="@+id/fragment_container"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:background="@color/colorAccent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toBottomOf="@id/toolbar"
    app:layout_constraintBottom_toTopOf="@id/bottom_navigation_view"/>
Categories
discuss

Firebase query optimizable

I have a Firebase Database which looks like :

I have a node named Products

 Products
    |
    |--------prod1_id
    |         | 
    |         |--name : "prod1"
    |          --state: "free"
    |         
    |
    |---------prod2_id
              | 
              |--name : "prod2"
               --price: "not_free"

Then I have the node for users

Users
     |
     |--------user1_id
     |         | 
     |         |--name : "user1"
     |          --e-mail: "user1@email.com"
     |          
     |
     |---------user2_id
               | 
               |--name : "user2"
                --e-mail: "user2@email.com"

And on my application user can purchase, and only when he/she does, I create a new node called PurchasedItems where I store the User and Product

Purchased items
             |
             |--------user1_id
             |         | 
             |         |--prod1: "any_value"
             |          --prod2:  "any_value"
             |         
             |
             |---------user2_id
                       | 
                       |--prod1: "any_value"

The thing is that on my query for objects, I do this :

 products_ref= FirebaseDatabase.getInstance().getReference().child("products");

WHAT IS THE PROBLEM?

User that is logged in to the app, even if he has bought a product it will show the productNotFree layout because on products I have not any reference to what user has bought this item, but I have something similar on my “TryToPurchase” method because I have a query to the PurchasedProducts to see if user has this product or not to make the purchase or not.

On my onClick() method I have this to check if user has paid for it or not

root_ref.child("PurchasedProducts").child(currentuser).addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        if(dataSnapshot.hasChild(model.getProduct_id())){
            showToast("He has that product");
        }
        else{
            showToast("Purchasing");
            //Purchase for it

        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {

    }
});

So far I had this switch() statement to setImageResource but from the query to products

NOTE:layoutFree is for example a box that has not a lock on it, and layoutNotFree is the same box but with a lock

switch (model.getState()) {
        case "free":
            holder.card_image.setImageResource(layoutFree);
            break;
        case "not_free":
            holder.card_image.setImageResource(layoutNotFree));
            break;
        default:
            break;
    }

Now I’ve faced that if user purchase an item, he/she won’t be able to see the layoutFree even if he purchased it, he will see the layout with a lock even if he/she has paid for it.

What I’ve thought to do?

On same onBindViewHolder where I have the switch() statement I could make another query to Firebase asking if currentUser has this product and if he has that product I put the freeLayout otherwise the NotFreeLayout.

But I think it’s kinda dirty, so I put it here to see if there’s another way to make it efficient.

What I’d like to see?

Well, if I’m logged as a user that has paid for one product that has the state “not_free” I’d like to see the product with layout without lock item and also if I pay for an item I create a table purchasedItems and I do something like this :

root_ref.child("PurchasedProducts").child(currentuser).child(productId).setValue("paid");

And also I’d like to see the RecyclerView changes the layoutNotFree to layoutFree, is any way to do it instead of making a refresh of the Activity? Refresh of Activity means that I have to re-do the adapter, create the RecyclerView etc…

I hope I’ve explained it correctly and step by step to avoid confusion, if I did something wrong on question feel free to edit it or question it to me and I’ll edit.

Answer

In this example, all products table children is saved in one ArrayList with only one request to Firebase Database.

According to your database schema.

First, Define a Arraylist of Products.class to hold all products details

 ArrayList<Products> productsArrayList = new ArrayList<>();

Second, define the Products.class in new class

public class Products {

    public String  id;
    public String  name;
    public String state;

    public Products() {
    }

    public Products(String name, String state) {
        this.name = name;
        this.state = state;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getState() {
        return state;
    }


    public void setId(String id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setState(String state) {
        this.state = state;
    }

}

I only add id(Necessary for position search), name, state You can add other values to Products.class

Third, make the Firebase query to get all products children

DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Products");
        ref.addListenerForSingleValueEvent(
                new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {


                        // for loop will be executed for each children
                        for(DataSnapshot userSnapshot : dataSnapshot.getChildren()){

                            // put snapShot in Products.class ...... only children added
                            // in This case Children Will be price, quantity
                            Products products = userSnapshot.getValue(Products.class);

                            // set id manually to tha same instance of the class
                            products.setId(userSnapshot.getKey());

                            // add the Post class to ArrayList
                            productsArrayList.add(products);
                        }

                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {
                        //handle databaseError
                    }
                });

Now after products details are saved in productsArrayList you can use them anywhere.

A helper method to search in ArrayList<Products> and get specific position

 public int getArrayListProductsPosition(String id){

        for(int i = 0; i < productsArrayList.size() ; i++){

            // if the passed id equals some id in arrayList return arrayList position
            if(Objects.equals(productsArrayList.get(i).getId(), id)){
                return i;
            }

        }

        return 0;
    }

Fourth, Now anywhere the class if you need to access specific product details, to update UI for example;

    // pass the id of the product you want to get details about
    // I suppose this id will probably be retrived from another database tabel
    int position = getArrayListProductsPosition(id);

    //update your UI TextView quantity for example;
    String name = productsArrayList.get(position).getName()
    textQuantitiy.setText(name);

    // or update you UI ImageView for example;

For more efficiency

in the search method (getArrayListProductsPosition), save products id's in database as numbers and change in Products.class. String id to Long id because String-String comparison is slower than Long-Long comparison

if Products table is to be changed (not static) use the productsArrayList once and immediately after retrieve query (you don’t want the data to be old)

Categories
discuss

Java 8 LocalDateTime – How to keep .000 milliseconds in String conversion

I have a timestamp that I receive via a String in the following format:

2016-10-17T12:42:04.000

I am converting it to a LocalDateTime to add some days to it (then back to a String) via the following line:

String _120daysLater = LocalDateTime.parse("2016-10-17T12:42:04.000",
    DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")).minusDays(120).toString());

However, I noticed that the response it gives back drops the .000 milliseconds.

I’m not sure the cleanest way to ensure that the exact pattern is preserved. For now I’m just adding a single millisecond, and there’s probably a way to incorporate the old SimpleDateFormat into it, but I was hoping there’s an even better way.

Answer

LocalDateTime::toString omits parts if zero:

The format used will be the shortest that outputs the full value of the time where the omitted parts are implied to be zero.

Use LocalDateTime::format instead of relying on toString().

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
LocalDateTime _120daysLater = LocalDateTime.parse("2016-10-17T12:42:04.000", formatter).minusDays(120);

// This just uses default formatting logic in toString. Don't rely on it if you want a specific format.
System.out.println(_120daysLater.toString());

// Use a format to use an explicitly defined output format
System.out.println(_120daysLater.format(formatter));
Categories
discuss

How can i change constraint programmatically

I need some help with ConstraintLayout.

I have 3 Buttons vertically aligned. Button1 and Button3 are visible, Button2 is invisible. When I click on Button1, Button2 should be visible.

<Button
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="8dp"
    android:onClick="on_expand"
    android:text="Button"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/textView" />

<Button
    android:id="@+id/button2"
    android:layout_width="wrap_content"
    android:layout_height="0dp"
    android:layout_marginTop="8dp"
    android:text="Button"
    android:visibility="invisible"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/button1" />

<Button
    android:id="@+id/button3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="8dp"
    android:text="Button"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@id/button1" />

How can I set

app:layout_constraintTop_toBottomOf="@id/button2"

on Button3

I have found this

Button b1 = (Button)findViewById(R.id.button1);
Button b2 = (Button) findViewById(R.id.button2);
Button b3 = (Button) findViewById(R.id.button3);    

ConstraintSet constraintSet = new ConstraintSet();
        constraintSet.connect("What must i set here????");
        constraintSet.clone(mConstraintLayout);
        constraintSet.applyTo(mConstraintLayout);

Answer

First add:

android:id="@+id/constraint_layout"

to your ConstraintLayout, then change:

android:onClick="on_expand"

in:

android:onClick="onExpand"

to respect lowerCamelCase methods naming convention.

Finally this should be your code:

public class MainActivity extends AppCompatActivity {

private ConstraintLayout mConstraintLayout;
private Button mButton;
private ConstraintSet mConstraintSet = new ConstraintSet();

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mConstraintLayout = findViewById(R.id.constraint_layout);
    mButton = findViewById(R.id.button2);
}

public void onExpand(View view) {
    // If the button is already visible then you don't need to apply any constraints
    if (mButton.getVisibility() == View.VISIBLE) {
        return;
    }
    /* Otherwise:
    - Make the button2 visible;
    - Insert the actual constraints in the ConstraintSet
    - Define a new constraint between button3 and button2 (TopToBottomOf)
    - Apply it to the ConstraintLayout */
    mButton.setVisibility(View.VISIBLE);
    mConstraintSet.clone(mConstraintLayout);
    mConstraintSet.connect(R.id.button3, ConstraintSet.TOP, 
                           R.id.button2, ConstraintSet.BOTTOM);
    mConstraintSet.applyTo(mConstraintLayout);
    }
}
Categories
discuss

Unsatisfied Dependency Exception in Springboot junit test

I am using spring-boot 1.5.9. I have created a simple spring-boot application which has the following directory structure.

enter image description here

LibraryService.java autowires the repository interface and has a method to save a book to the library.

LibraryService.java

@Service
public class LibraryService  {
  private static final Logger logger = LoggerFactory.getLogger(LibraryService.class);       

  @Autowired
  BookRepository bookRepository;

  public void save(Book book){
    bookRepository.save(book);  
  } 

  public long count(){
    return bookRepository.count();
  }
}

Below is the BookRepository interface

public interface BookRepository extends MongoRepository<Book, String> { }

When I autowire the LibraryService in the test class I find it is not injecting properly and I get the unsatisfied dependency exception. Following is the LibraryServiceTest class

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@DataMongoTest
public class LibraryServiceTest {

@Autowired
LibraryService libraryService;

@Test
public void testSave(){
Book aBook = new Book("Harry Potter" , "J. K. Rowling");
libraryService.save(aBook); 
assertEquals(1, libraryService.count());;
 }  
}

I tried the @MockBean instead of @Autowired in the test class and had no exception but the repository instance was evaluated to null which resulted the test to fail. What is the correct way to inject the dependency when using junit?

EDIT

Following is the stack trace:

2017-12-31 09:48:00.112 ERROR 57648 --- [           main] 
o.s.test.context.TestContextManager      : Caught exception while allowing 
TestExecutionListener
[org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@32464a14] to prepare test instance [com.example.demo.service.LibraryServiceTest@56193c7d]

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.example.demo.service.LibraryServiceTest': Unsatisfied dependency expressed through field 'libraryService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.service.LibraryService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:386) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118) ~[spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) ~[spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:44) ~[spring-boot-test-autoconfigure-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230) ~[spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12]
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) [.cp/:na]
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.service.LibraryService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
... 29 common frames omitted

Answer

From the documentation:

Annotation that can be used in combination with @RunWith(SpringRunner.class) for a typical MongoDB test. Can be used when a test focuses only on MongoDB components.

Using this annotation will disable full auto-configuration and instead apply only configuration relevant to MongoDB tests.

So, this will exclude your service from the spring context (and it should be annotated with @RunWith(SpringRunner.class) anyway).

Use that to test your Mongo repositories. To test your services, mock the repository (which is why DI is useful in the first place), and test the business logic inside the service on the mocked repository.

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..