我正在研究一个查询github API的应用程序以获取用户列表,而我正在遵循推荐的android 体系结构组件指南。从网络中获取数据后,我将使用Room DB将其存储在本地,然后使用在LiveData对象上观察到的ViewModel将其显示在UI上(这很好)。但是,我希望有一个按钮,当且仅当存在网络连接时,单击该按钮将触发刷新操作并执行网络请求以从API获取新数据。问题是,当我单击该按钮时,将触发两个网络调用,一个来自refreshUserData(),另一个来自已存在的LiveData(在onCreate()期间触发)。我应如何最好地处理这种情况,以使刷新按钮仅执行一个网络请求,而不执行两个网络请求。这是我的存储库类:
public class UserRepository { private final UserDao mUserDao; private LiveData> mAllUsers; private LiveData
mUser; private final GithubUserService githubUserService; private final AppExecutors appExecutors; private final Application application; private static String LOG_TAG = UserRepository.class.getSimpleName(); private RateLimiter repoListRateLimit = new RateLimiter<>(1, TimeUnit.MINUTES); public UserRepository(Application application, GithubUserService githubUserService, AppExecutors appExecutors) { this.application = application; UserRoomDatabase db = UserRoomDatabase.getDatabase(application); mUserDao = db.userDao(); this.githubUserService = githubUserService; this.appExecutors = appExecutors; } public LiveData getUser(int userId) { LiveData user = mUserDao.loadUser(userId); Log.d(LOG_TAG, "retrieved user from database successful"); return user; } public LiveData >> getAllUsers() { //ResultType, RequestType /** * List is the [ResultType] * GithubUser is the [RequestType] */ return new NetworkBoundResource , GithubUser>(appExecutors) { @Override protected void saveCallResult(@NonNull GithubUser item) { Log.d(LOG_TAG, "call to insert results to db"); mUserDao.insertUsers(item.getItems()); } @Override protected boolean shouldFetch(@Nullable List
data) { Log.d(LOG_TAG, "null?" + (data == null)); Log.d(LOG_TAG, "empty? " + (data.isEmpty())); Log.d(LOG_TAG, "rate? " + (repoListRateLimit.shouldFetch("owner"))); Log.d(LOG_TAG, "should fetch? " + (data.isEmpty() || repoListRateLimit.shouldFetch("owner"))); return data.isEmpty() || data == null; } @NonNull @Override protected LiveData > loadFromDb() { Log.d(LOG_TAG, " call to load from db"); return mUserDao.getAllUsers(); } @NonNull @Override protected LiveData
> createCall() { Log.d(LOG_TAG, "creating a call to network"); return githubUserService.getGithubUsers("language:java location:port-harcourt"); } @Override protected GithubUser processResponse(ApiResponse response) { return super.processResponse(response); } }.asLiveData(); } public LiveData >> refreshUserData() { //ResultType, RequestType /** * List is the [ResultType] * GithubUser is the [RequestType] */ return new NetworkBoundResource , GithubUser>(appExecutors) { @Override protected void saveCallResult(@NonNull GithubUser item) { Log.d(LOG_TAG, "call to insert results to db"); mUserDao.insertUsers(item.getItems()); } @Override protected boolean shouldFetch(@Nullable List
data) { Log.d(LOG_TAG, "refreshUserData"); return true; } @NonNull @Override protected LiveData > loadFromDb() { Log.d(LOG_TAG, "refreshUserData"); Log.d(LOG_TAG, " call to load from db"); return mUserDao.getAllUsers(); } @NonNull @Override protected LiveData
> createCall() { Log.d(LOG_TAG, "refreshUserData"); Log.d(LOG_TAG, "creating a call to network"); return githubUserService.getGithubUsers("language:java location:port-harcourt"); } @Override protected GithubUser processResponse(ApiResponse response) { return super.processResponse(response); } }.asLiveData(); } public Application getApplication() { return application; } }
我的ViewModel类是:
public class UserProfileViewModel extends AndroidViewModel { private UserRepository mRepository; public UserProfileViewModel(UserRepository mRepository) { super(mRepository.getApplication()); this.mRepository = mRepository; } public LiveData>> getmAllUsers() { return mRepository.getAllUsers(); } public LiveData >> refreshUserData() { return mRepository.refreshUserData(); } public LiveData getUser(int userId) { return mRepository.getUser(userId); } }
我的MainActivity类:
public class MainActivity extends AppCompatActivity implements GithubAdapter.ListItemClickListener { private RecyclerView mRecyclerView; private UserProfileViewModel mUserViewModel; public static final String USER_ID = "userId"; private ConnectivityManager cm; private boolean isConnected; private UserRepository mRepository; private GithubUserService mGithubUserService; private NetworkInfo activeNetwork; private Picasso mPicasso; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); mGithubUserService = GithubApplication.get(MainActivity.this).getGithubUserService(); mPicasso = GithubApplication.get(MainActivity.this).getPicasso(); mRepository = new UserRepository(getApplication(), mGithubUserService, new AppExecutors()); // the factory and its dependencies instead should be injected with DI framework like Dagger ViewModelFactory factory = new ViewModelFactory(mRepository); mUserViewModel = ViewModelProviders.of(this, factory).get(UserProfileViewModel.class); // initViews(); mRecyclerView = findViewById(R.id.users_recycler); final GithubAdapter mAdapter = new GithubAdapter(this, this, mPicasso); mRecyclerView.setAdapter(mAdapter); mRecyclerView.setHasFixedSize(true); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); cm = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE); getUsers(mAdapter); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //check if there is a network connection // if there is a network connection the LoaderManager is called but // displays a message if there's no network connection activeNetwork = cm.getActiveNetworkInfo(); isCOnnected= activeNetwork != null && activeNetwork.isConnectedOrConnecting(); if (isConnected) { mUserViewModel.refreshUserData().observe(MainActivity.this, new Observer>>() { @Override public void onChanged(@Nullable Resource > listResource) { // Toast.makeText(MainActivity.this, "second" + listResource.status, Toast.LENGTH_LONG).show(); Snackbar.make(view, "refresh:" + listResource.status, Snackbar.LENGTH_LONG) .setAction("Action", null).show(); mAdapter.setUsers(listResource.data); } }); } else { Snackbar.make(view, "no connection", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } } }); } private void getUsers(GithubAdapter mAdapter) { mUserViewModel.getmAllUsers().observe(this, new Observer
>>() { @Override public void onChanged(@Nullable Resource > listResource) { Toast.makeText(MainActivity.this, "" + listResource.status, Toast.LENGTH_LONG).show(); mAdapter.setUsers(listResource.data); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } @Override public void onListItemClick(int userId) { Intent detailIntent = new Intent(MainActivity.this, DetailActivity.class); detailIntent.putExtra(USER_ID, userId); startActivity(detailIntent); } }
您可以在此处找到完整的代码