美文网首页
Android Architecture Components

Android Architecture Components

作者: insomniatt | 来源:发表于2017-06-30 15:03 被阅读599次

    1.BasicSample - Shows how to persist data using a SQLite database and Room. Also uses ViewModels and LiveData.

    此 sample 需求非常简单, 使用 list 展示(持久化)数据库中的数据, 点击每个 item 可以进入到详情页(展示详情信息)

    1.1MainActivity.java -- main_activity.xml

    作为一个 fragment 的载体, 仅仅包括一个 fragment: 1.2ProductListFragment.java
    还有个 public method 展示ProductFragment.java(一会再来看)

    1.2ProductListFragment.java -- list_fragment.xml

    此界面中有2个 view, 一个是加载完成前的 loading 提示view, 一个是加载完成后的 recyclerView

    1.2ProductListFragment 中使用了android.databinding 进行 fragment, xml 和数据的绑定
    onCreateView() 中 init:

    private ListFragmentBinding mBinding;
    mBinding = DataBindingUtil.inflate(inflater, R.layout.list_fragment, container, false);
    

    在 list_fragment.xml 中,
    --1.使用<data> 标签,声明 var
    --2.使用 app:visibleGone="@{isLoading}" 对 view 进行动态控制

    <layout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <data>
            <variable
                name="isLoading"
                type="boolean" />
        </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/cardview_light_background"
            android:orientation="vertical">
    
            <TextView
                android:id="@+id/loading_tv"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="center_vertical|center_horizontal"
                android:text="@string/loading_products"
                android:textAlignment="center"
                app:visibleGone="@{isLoading}"
                />
    
            <android.support.v7.widget.RecyclerView
                android:id="@+id/products_list"
                android:contentDescription="@string/cd_products_list"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layoutManager="LinearLayoutManager"
                app:visibleGone="@{!isLoading}"/>
    
        </LinearLayout>
    </layout>
    

    --3.${visibleGone} 关键字在 BindingAdapters.java 中被自定义, 然后 showHide() 方法对 view 进行动态控制

    public class BindingAdapters {
        @BindingAdapter("visibleGone")
        public static void showHide(View view, boolean show) {
            view.setVisibility(show ? View.VISIBLE : View.GONE);
        }
    }
    

    --4. 而 showHide() 是在ListFragmentBinding.java 中被调用, 是自动生成的

    
    public class ListFragmentBinding extends android.databinding.ViewDataBinding  {
    ...
     com.example.android.persistence.ui.BindingAdapters.showHide(this.loadingTv, isLoading);
     com.example.android.persistence.ui.BindingAdapters.showHide(this.productsList, IsLoading1);
    ...
    }
    

    --5.适配器 ProductAdapter.java 对数据和 fragment 进行关联

     mProductAdapter = new ProductAdapter(mProductClickCallback);
    

    --6.获取数据
    在onActivityCreated() 中, 获取数据:

     final ProductListViewModel viewModel = ViewModelProviders.of(this).get(ProductListViewModel.class);
        
     // Update the list when the data changes        
     viewModel.getProducts().observe(this, new Observer<List<ProductEntity>>() {
                @Override
                public void onChanged(@Nullable List<ProductEntity> myProducts) {
                    if (myProducts != null) {
                        mBinding.setIsLoading(false);
                        mProductAdapter.setProductList(myProducts);
                    } else {
                        mBinding.setIsLoading(true);
                    }
                }
            });
    

    这段代码使用了新的方式获取数据库中的数据:ViewModelProviders.of(this).get(ProductListViewModel.class);
    --7.ProductListViewModel.java
    ViewModelProviders为arch 中的方法;
    此处我们需要实现如下: 在 apply() 中有 loadAllProducts()的方法, 此方法实现在 Dao 中

    public class ProductListViewModel extends AndroidViewModel {
    
        private static final MutableLiveData ABSENT = new MutableLiveData();
        {
            //noinspection unchecked
            ABSENT.setValue(null);
        }
    
        private final LiveData<List<ProductEntity>> mObservableProducts;
    
        public ProductListViewModel(Application application) {
            super(application);
    
            final DatabaseCreator databaseCreator = DatabaseCreator.getInstance(this.getApplication());
    
            LiveData<Boolean> databaseCreated = databaseCreator.isDatabaseCreated();
            mObservableProducts = Transformations.switchMap(databaseCreated,
                    new Function<Boolean, LiveData<List<ProductEntity>>>() {
                @Override
                public LiveData<List<ProductEntity>> apply(Boolean isDbCreated) {
                    if (!Boolean.TRUE.equals(isDbCreated)) { // Not needed here, but watch out for null
                        //noinspection unchecked
                        return ABSENT;
                    } else {
                        //noinspection ConstantConditions
                        return databaseCreator.getDatabase().productDao().loadAllProducts();
                    }
                }
            });
    
            databaseCreator.createDb(this.getApplication());
        }
    
        /**
         * Expose the LiveData Products query so the UI can observe it.
         */
        public LiveData<List<ProductEntity>> getProducts() {
            return mObservableProducts;
        }
    }
    

    --8.ProductEntity.java
    @Entity 是 新的包 arch.room 中的
    此类是Product 的实体类:
    @Entity(tableName = "products"): 表名为"products"
    @PrimaryKey private int id; : primary key 为 id

    @Entity(tableName = "products")
    public class ProductEntity implements Product {
        @PrimaryKey
        private int id;
        private String name;
        private String description;
        private int price;
    
        @Override
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        @Override
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String getDescription() {
            return description;
        }
    
        public void setDescription(String description) {
            this.description = description;
        }
    
        @Override
        public int getPrice() {
            return price;
        }
    
        public void setPrice(int price) {
            this.price = price;
        }
    
        public ProductEntity() {
        }
    
        public ProductEntity(Product product) {
            this.id = product.getId();
            this.name = product.getName();
            this.description = product.getDescription();
            this.price = product.getPrice();
        }
    }
    

    --9.ProductDao.java
    @Dao 是新的包 arch.room 中的
    形如 retrofit2的接口请求, 实现起来的方式和retrofit 很像

    @Dao
    public interface ProductDao {
        @Query("SELECT * FROM products") 
        LiveData<List<ProductEntity>> loadAllProducts();
    
        @Insert(onConflict = OnConflictStrategy.REPLACE)
        void insertAll(List<ProductEntity> products);
    
        @Query("select * from products where id = :productId")
        LiveData<ProductEntity> loadProduct(int productId);
    
        @Query("select * from products where id = :productId")
        ProductEntity loadProductSync(int productId);
    }
    

    --10.上一张图简单理解下 View ViewModel model 的关系

    final-architecture.png

    2.GithubBrowserSample - An advanced sample that uses the Architecture components, Dagger and the Github API. Requires Android Studio 3.0 canary 1

    --1.MainActivity.java
    implements LifecycleRegistryOwner

        @Override
        public LifecycleRegistry getLifecycle() {
            return lifecycleRegistry;
        }
    

    implements HasSupportFragmentInjector

     @Override
        public DispatchingAndroidInjector<Fragment> supportFragmentInjector() {
            return dispatchingAndroidInjector;
        }
    

    通过注入NavigationController 控制 fragment

    @Inject
        NavigationController navigationController;
        @Inject
        public NavigationController(MainActivity mainActivity) {
            this.containerId = R.id.container;
            this.fragmentManager = mainActivity.getSupportFragmentManager();
        }
    
        public void navigateToSearch() {
            SearchFragment searchFragment = new SearchFragment();
            fragmentManager.beginTransaction()
                    .replace(containerId, searchFragment)
                    .commitAllowingStateLoss();
        }
    

    --2.SearchFragment.java
    dataBinding

     <data>
            <import type="com.android.example.github.vo.Repo"/>
            <import type="java.util.List"/>
            <import type="com.android.example.github.vo.Status"/>
            <import type="com.android.example.github.vo.Resource"/>
            <variable name="resultCount" type="int"/>
            <variable name="query" type="String"/>
            <variable name="loadingMore" type="boolean"/>
            <variable name="searchResource" type="Resource"/>
            <variable name="callback" type="com.android.example.github.ui.common.RetryCallback"/>
        </data>
    
    SearchFragmentBinding dataBinding = DataBindingUtil
                    .inflate(inflater, R.layout.search_fragment, container, false,
                            dataBindingComponent);
    

    extends LifecycleFragment

    功能1:searching function:

        private void doSearch(View v) {
            //get query key word
            String query = binding.get().input.getText().toString();
            // Dismiss keyboard
            dismissKeyboard(v.getWindowToken());
            binding.get().setQuery(query);
            searchViewModel.setQuery(query);
        }
    

    --3.SearchViewModel.java
    extends ViewModel
    功能1:refresh()

        void refresh() {
            if (query.getValue() != null) {
                query.setValue(query.getValue());
            }
        }
    

    功能2:loadNextPage()

        void loadNextPage() {
            String value = query.getValue();
            if (value == null || value.trim().length() == 0) {
                return;
            }
            nextPageHandler.queryNextPage(value);
        }
    

    --4.DAO @Dao
    RepoDao.java
    UserDao.java
    --5.Entity @Entity
    RepoEntity.java
    UserEntity.java
    RepoSearchResultEntity.java
    ContributorEntity.java
    --6.GithubService.java

        @GET("users/{login}")
        LiveData<ApiResponse<User>> getUser(@Path("login") String login);
    
        @GET("users/{login}/repos")
        LiveData<ApiResponse<List<Repo>>> getRepos(@Path("login") String login);
    
        @GET("repos/{owner}/{name}")
        LiveData<ApiResponse<Repo>> getRepo(@Path("owner") String owner, @Path("name") String name);
    
        @GET("repos/{owner}/{name}/contributors")
        LiveData<ApiResponse<List<Contributor>>> getContributors(@Path("owner") String owner, @Path("name") String name);
    
        @GET("search/repositories")
        LiveData<ApiResponse<RepoSearchResponse>> searchRepos(@Query("q") String query);
    
        @GET("search/repositories")
        Call<RepoSearchResponse> searchRepos(@Query("q") String query, @Query("page") int page);
    

    --7.repository
    RepoRepository.java

    GithubDb db;
    //操作数据库
    RepoDao repoDao;
    //网络操作
    GithubService githubService;
    AppExecutors appExecutors;
    

    UserRepository.java

    //操作数据库
    UserDao userDao;
    //网络操作
    GithubService githubService;
    AppExecutors appExecutors;
    

    --8.AppComponent.java

    @Singleton
    @Component(modules = {
            AndroidInjectionModule.class,
            AppModule.class,
            MainActivityModule.class
    })
    public interface AppComponent {
        @Component.Builder
        interface Builder {
            @BindsInstance Builder application(Application application);
            AppComponent build();
        }
        void inject(GithubApp githubApp);
    }
    

    --9.AppModule.java

    @Module(includes = ViewModelModule.class)
    
     @Singleton @Provides
        GithubService provideGithubService() {
            return new Retrofit.Builder()
                    .baseUrl("https://api.github.com/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(new LiveDataCallAdapterFactory())
                    .build()
                    .create(GithubService.class);
        }
    
        @Singleton @Provides
        GithubDb provideDb(Application app) {
            return Room.databaseBuilder(app, GithubDb.class,"github.db").build();
        }
    
        @Singleton @Provides
        UserDao provideUserDao(GithubDb db) {
            return db.userDao();
        }
    
        @Singleton @Provides
        RepoDao provideRepoDao(GithubDb db) {
            return db.repoDao();
        }
    

    --10.MainActivityModule.java

    @ContributesAndroidInjector(modules = FragmentBuildersModule.class)
        abstract MainActivity contributeMainActivity();
    
    
    

    --11.FragmentBuildersModule.java

        @ContributesAndroidInjector
        abstract RepoFragment contributeRepoFragment();
    
        @ContributesAndroidInjector
        abstract UserFragment contributeUserFragment();
    
        @ContributesAndroidInjector
        abstract SearchFragment contributeSearchFragment();
    

    相关文章

      网友评论

          本文标题:Android Architecture Components

          本文链接:https://www.haomeiwen.com/subject/ddwucxtx.html