Android中LiveData+Room+Paging简单实现步骤

1.?添加依赖库

//for lifecycle and LiveData and ViewModel
implementation "android.arch.lifecycle:runtime:$archRuntimeVersion"
implementation "android.arch.lifecycle:extensions:$archExtensionVersion"
annotationProcessor "android.arch.lifecycle:compiler:$archVersion"

implementation "android.arch.persistence.room:runtime:$archVersion"
annotationProcessor "android.arch.persistence.room:compiler:$archVersion"

// Paging

2.?数据库实体类编写

@Entity()
public class Cheese {
    @PrimaryKey(autoGenerate = true)
    @NonNull
    public int id;

    public String name;

    public Cheese(String name) {
        this.name = name;
    }
}

3.?数据库dao接口编写

@Dao
public interface CheeseDao {
    @Query("SELECT * FROM cheese ORDER BY name COLLATE NOCASE ASC")
    DataSource.Factory<Integer, Cheese> allCheesesByName();

    @Insert
    void insertList(List<Cheese> cheeses);

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insert(Cheese cheese);

    @Delete
    void delete(Cheese cheese);
}

4.?数据库类编写

@Database(entities = {Cheese.class}, version = 1, exportSchema = false)
public abstract class CheeseDb extends RoomDatabase {
 
    public abstract CheeseDao cheeseDao();
 
    @VisibleForTesting
    public static final String DATABASE_NAME = "cheese.db";
 
    private static CheeseDb INSTANCE;
 
    public static CheeseDb getDatabase(final Context context) {
        if (INSTANCE == null) {
            synchronized (CheeseDb.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                            CheeseDb.class, DATABASE_NAME)
                            .fallbackToDestructiveMigration()
                            .addCallback(callback)
                            .build();
                }
            }
        }
        return INSTANCE;
    }
 
    private static RoomDatabase.Callback callback = new RoomDatabase.Callback() {
        @Override
        public void onOpen(@NonNull SupportSQLiteDatabase db) {
            super.onOpen(db);
            new PopulateDbAsync(INSTANCE).execute();
        }
    };
 
    private static class PopulateDbAsync extends AsyncTask<Void, Void, Void> {
 
        private final CheeseDao mDao;
 
        PopulateDbAsync(CheeseDb db) {
            mDao = db.cheeseDao();
        }
 
        @Override
        protected Void doInBackground(Void... voids) {
            ArrayList<Cheese> list = new ArrayList<>();
            // 假数据
            for (String name : data) {
                list.add(new Cheese(name));
            }
            mDao.insertList(list);
            return null;
        }
    }
 
    public static final String[] data = {"Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
            "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
            "Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
            "Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
            "Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
            "Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr", "Baby Swiss",
            "Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
            "Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
            "Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
            "Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
            "Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
            "Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
            "Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)",
            "Boeren Leidenkaas", "Bonchester", "Bosworth", "Bougon", "Boule Du Roves",
            "Boulette d'Avesnes", "Boursault", "Boursin", "Bouyssou", "Bra", "Braudostur",
            "Breakfast Cheese", "Brebis du Lavort", "Brebis du Lochois", "Brebis du Puyfaucon",
            "Bresse Bleu", "Brick", "Brie", "Brie de Meaux", "Brie de Melun", "Brillat-Savarin",
            "Brin", "Brin d' Amour", "Brin d'Amour", "Brinza (Burduf Brinza)",
            "Briquette de Brebis", "Briquette du Forez", "Broccio", "Broccio Demi-Affine",
            "Brousse du Rove", "Bruder Basil", "Brusselae Kaas (Fromage de Bruxelles)", "Bryndza",
            "Buchette d'Anjou", "Buffalo", "Burgos", "Butte", "Butterkase", "Button (Innes)",
            "Buxton Blue", "Cabecou", "Caboc"};
 
}

5. ViewModel类编写

public class CheeseViewModel extends AndroidViewModel {
 
    private final CheeseDao mCheeseDao;
    public final LiveData<PagedList<Cheese>> listLiveData;
 
    public CheeseViewModel(@NonNull Application application) {
        super(application);
        mCheeseDao = CheeseDb.getDatabase(application).cheeseDao();
 
        listLiveData = new LivePagedListBuilder<>(mCheeseDao.allCheesesByName(),
                new PagedList.Config.Builder()
                        .setPageSize(30)
                        .setEnablePlaceholders(true)
                        .build())
                .build();
 
    }
 
    public void insert(final String text) {
        Executors.newSingleThreadExecutor().execute(new Runnable() {
            @Override
            public void run() {
                mCheeseDao.insert(new Cheese(text));
            }
        });
    }
 
    public void remove(final Cheese cheese) {
 
        Executors.newSingleThreadExecutor().execute(new Runnable() {
            @Override
            public void run() {
                mCheeseDao.delete(cheese);
            }
        });
    }
 
}

6.?分页设配器类编写ViewHolder?和 Adapter

public class CheeseViewHolder extends RecyclerView.ViewHolder {
 
    private TextView tvName;
    public Cheese cheese;
 
    public CheeseViewHolder(@NonNull View itemView) {
        super(itemView);
        tvName = itemView.findViewById(R.id.name);
    }
 
    public void bindTo(Cheese cheese) {
        this.cheese = cheese;
        tvName.setText(cheese.name);
    }
}
 
 
public class CheeseAdapter extends PagedListAdapter<Cheese, CheeseViewHolder> {
 
    private static DiffUtil.ItemCallback<Cheese> ITEM_CALLBACK = new DiffUtil.ItemCallback<Cheese>() {
        @Override
        public boolean areItemsTheSame(@NonNull Cheese oldItem, @NonNull Cheese newItem) {
            return oldItem.id == newItem.id;
        }
 
        @Override
        public boolean areContentsTheSame(@NonNull Cheese oldItem, @NonNull Cheese newItem) {
            return oldItem.name.equals(newItem.name);
        }
    };
 
    public CheeseAdapter() {
        super(ITEM_CALLBACK);
    }
 
    @NonNull
    @Override
    public CheeseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.cheese_item, parent, false);
        return new CheeseViewHolder(view);
    }
 
    @Override
    public void onBindViewHolder(@NonNull CheeseViewHolder holder, int position) {
        holder.bindTo(getItem(position));
    }
}

7.? Activity?及页面布局编写

public class MainActivity extends AppCompatActivity {
 
    private CheeseViewModel viewModel;
    private CheeseAdapter adapter;
    private RecyclerView recyclerView;
    private Button btnAdd;
    private EditText etText;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        recyclerView = findViewById(R.id.cheeseList);
        btnAdd = findViewById(R.id.addButton);
        etText = findViewById(R.id.inputText);
 
        viewModel = ViewModelProviders.of(this).get(CheeseViewModel.class);
        adapter = new CheeseAdapter();
 
        recyclerView.setAdapter(adapter);
 
        viewModel.listLiveData.observe(this, new Observer<PagedList<Cheese>>() {
            @Override
            public void onChanged(@Nullable PagedList<Cheese> cheeses) {
                adapter.submitList(cheeses);
            }
        });
 
        initListener();
 
        initSwipeToDelete();
        
    }
 
    private void initSwipeToDelete() {
 
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
            @Override
            public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
                return makeMovementFlags(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
            }
 
            @Override
            public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder viewHolder1) {
                return false;
            }
 
            @Override
            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
                if (viewHolder instanceof CheeseViewHolder) {
                    CheeseViewHolder holder = (CheeseViewHolder) viewHolder;
                    viewModel.remove(holder.cheese);
                }
            }
        });
 
        itemTouchHelper.attachToRecyclerView(recyclerView);
    }
 
    private void initListener() {
        btnAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                addCheese();
            }
        });
 
        etText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (actionId == EditorInfo.IME_ACTION_DONE) {
                    addCheese();
                    return true;
                }
                return false;
            }
        });
 
        etText.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER) {
                    addCheese();
                    return true;
                }
                return false;
            }
        });
    }
 
    private void addCheese() {
        String cheese = etText.getText().toString().trim();
        if (!TextUtils.isEmpty(cheese)) {
            viewModel.insert(cheese);
            etText.setText("");
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical">
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
 
        <EditText
            android:id="@+id/inputText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="@string/add_cheese"
            android:imeOptions="actionDone"
            android:inputType="text"
            android:maxLines="1" />
 
        <Button
            android:id="@+id/addButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="0"
            android:text="@string/add" />
    </LinearLayout>
 
    <android.support.v7.widget.RecyclerView
        android:id="@+id/cheeseList"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutManager="LinearLayoutManager" />
</LinearLayout>

管理线程执行工具类

public class AppExecutors {

    private final Executor mDiskIO;

    private final Executor mNetworkIO;

    private final Executor mMainThread;

    private AppExecutors(Executor diskIO, Executor networkIO, Executor mainThread) {
        this.mDiskIO = diskIO;
        this.mNetworkIO = networkIO;
        this.mMainThread = mainThread;
    }

    public AppExecutors() {
        this(Executors.newSingleThreadExecutor(), Executors.newFixedThreadPool(3),
                new MainThreadExecutor());
    }

    public Executor diskIO() {
        return mDiskIO;
    }

    public Executor networkIO() {
        return mNetworkIO;
    }

    public Executor mainThread() {
        return mMainThread;
    }

    private static class MainThreadExecutor implements Executor {
        private Handler mainThreadHandler = new Handler(Looper.getMainLooper());

        @Override
        public void execute(@NonNull Runnable command) {
            mainThreadHandler.post(command);
        }
    }
}
Android中LiveData+Room+Paging简单实现步骤
滚动到顶部