java 阳光AsyncTaskLoader
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 阳光AsyncTaskLoader相关的知识,希望对你有一定的参考价值。
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.sunshine;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.example.android.sunshine.data.SunshinePreferences;
import com.example.android.sunshine.utilities.NetworkUtils;
import com.example.android.sunshine.utilities.OpenWeatherJsonUtils;
import java.net.URL;
// COMPLETED (1) Implement the proper LoaderCallbacks interface and the methods of that interface
public class MainActivity extends AppCompatActivity implements
ForecastAdapter.ForecastAdapterOnClickHandler,
LoaderCallbacks<String[]> {
private static final String TAG = MainActivity.class.getSimpleName();
private RecyclerView mRecyclerView;
private ForecastAdapter mForecastAdapter;
private TextView mErrorMessageDisplay;
private ProgressBar mLoadingIndicator;
private static final int FORECAST_LOADER_ID = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_forecast);
/*
* Using findViewById, we get a reference to our RecyclerView from xml. This allows us to
* do things like set the adapter of the RecyclerView and toggle the visibility.
*/
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview_forecast);
/* This TextView is used to display errors and will be hidden if there are no errors */
mErrorMessageDisplay = (TextView) findViewById(R.id.tv_error_message_display);
/*
* LinearLayoutManager can support HORIZONTAL or VERTICAL orientations. The reverse layout
* parameter is useful mostly for HORIZONTAL layouts that should reverse for right to left
* languages.
*/
LinearLayoutManager layoutManager
= new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
/*
* Use this setting to improve performance if you know that changes in content do not
* change the child layout size in the RecyclerView
*/
mRecyclerView.setHasFixedSize(true);
/*
* The ForecastAdapter is responsible for linking our weather data with the Views that
* will end up displaying our weather data.
*/
mForecastAdapter = new ForecastAdapter(this);
/* Setting the adapter attaches it to the RecyclerView in our layout. */
mRecyclerView.setAdapter(mForecastAdapter);
/*
* The ProgressBar that will indicate to the user that we are loading data. It will be
* hidden when no data is loading.
*
* Please note: This so called "ProgressBar" isn't a bar by default. It is more of a
* circle. We didn't make the rules (or the names of Views), we just follow them.
*/
mLoadingIndicator = (ProgressBar) findViewById(R.id.pb_loading_indicator);
// COMPLETED (7) Remove the code for the AsyncTask and initialize the AsyncTaskLoader
/*
* This ID will uniquely identify the Loader. We can use it, for example, to get a handle
* on our Loader at a later point in time through the support LoaderManager.
*/
int loaderId = FORECAST_LOADER_ID;
/*
* From MainActivity, we have implemented the LoaderCallbacks interface with the type of
* String array. (implements LoaderCallbacks<String[]>) The variable callback is passed
* to the call to initLoader below. This means that whenever the loaderManager has
* something to notify us of, it will do so through this callback.
*/
LoaderCallbacks<String[]> callback = MainActivity.this;
/*
* The second parameter of the initLoader method below is a Bundle. Optionally, you can
* pass a Bundle to initLoader that you can then access from within the onCreateLoader
* callback. In our case, we don't actually use the Bundle, but it's here in case we wanted
* to.
*/
Bundle bundleForLoader = null;
/*
* Ensures a loader is initialized and active. If the loader doesn't already exist, one is
* created and (if the activity/fragment is currently started) starts the loader. Otherwise
* the last created loader is re-used.
*/
getSupportLoaderManager().initLoader(loaderId, bundleForLoader, callback);
}
// COMPLETED (2) Within onCreateLoader, return a new AsyncTaskLoader that looks a lot like the existing FetchWeatherTask.
/**
* Instantiate and return a new Loader for the given ID.
*
* @param id The ID whose loader is to be created.
* @param loaderArgs Any arguments supplied by the caller.
*
* @return Return a new Loader instance that is ready to start loading.
*/
@Override
public Loader<String[]> onCreateLoader(int id, final Bundle loaderArgs) {
return new AsyncTaskLoader<String[]>(this) {
/* This String array will hold and help cache our weather data */
String[] mWeatherData = null;
// COMPLETED (3) Cache the weather data in a member variable and deliver it in onStartLoading.
/**
* Subclasses of AsyncTaskLoader must implement this to take care of loading their data.
*/
@Override
protected void onStartLoading() {
if (mWeatherData != null) {
deliverResult(mWeatherData);
} else {
mLoadingIndicator.setVisibility(View.VISIBLE);
forceLoad();
}
}
/**
* This is the method of the AsyncTaskLoader that will load and parse the JSON data
* from OpenWeatherMap in the background.
*
* @return Weather data from OpenWeatherMap as an array of Strings.
* null if an error occurs
*/
@Override
public String[] loadInBackground() {
String locationQuery = SunshinePreferences
.getPreferredWeatherLocation(MainActivity.this);
URL weatherRequestUrl = NetworkUtils.buildUrl(locationQuery);
try {
String jsonWeatherResponse = NetworkUtils
.getResponseFromHttpUrl(weatherRequestUrl);
String[] simpleJsonWeatherData = OpenWeatherJsonUtils
.getSimpleWeatherStringsFromJson(MainActivity.this, jsonWeatherResponse);
return simpleJsonWeatherData;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Sends the result of the load to the registered listener.
*
* @param data The result of the load
*/
public void deliverResult(String[] data) {
mWeatherData = data;
super.deliverResult(data);
}
};
}
// COMPLETED (4) When the load is finished, show either the data or an error message if there is no data
/**
* Called when a previously created loader has finished its load.
*
* @param loader The Loader that has finished.
* @param data The data generated by the Loader.
*/
@Override
public void onLoadFinished(Loader<String[]> loader, String[] data) {
mLoadingIndicator.setVisibility(View.INVISIBLE);
mForecastAdapter.setWeatherData(data);
if (null == data) {
showErrorMessage();
} else {
showWeatherDataView();
}
}
/**
* Called when a previously created loader is being reset, and thus
* making its data unavailable. The application should at this point
* remove any references it has to the Loader's data.
*
* @param loader The Loader that is being reset.
*/
@Override
public void onLoaderReset(Loader<String[]> loader) {
/*
* We aren't using this method in our example application, but we are required to Override
* it to implement the LoaderCallbacks<String> interface
*/
}
/**
* This method is used when we are resetting data, so that at one point in time during a
* refresh of our data, you can see that there is no data showing.
*/
private void invalidateData() {
mForecastAdapter.setWeatherData(null);
}
/**
* This method uses the URI scheme for showing a location found on a map in conjunction with
* an implicit Intent. This super-handy intent is detailed in the "Common Intents" page of
* Android's developer site:
*
* @see "http://developer.android.com/guide/components/intents-common.html#Maps"
* <p>
* Protip: Hold Command on Mac or Control on Windows and click that link to automagically
* open the Common Intents page
*/
private void openLocationInMap() {
String addressString = "1600 Ampitheatre Parkway, CA";
Uri geoLocation = Uri.parse("geo:0,0?q=" + addressString);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(geoLocation);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
} else {
Log.d(TAG, "Couldn't call " + geoLocation.toString() + ", no receiving apps installed!");
}
}
/**
* This method is for responding to clicks from our list.
*
* @param weatherForDay String describing weather details for a particular day
*/
@Override
public void onClick(String weatherForDay) {
Context context = this;
Class destinationClass = DetailActivity.class;
Intent intentToStartDetailActivity = new Intent(context, destinationClass);
intentToStartDetailActivity.putExtra(Intent.EXTRA_TEXT, weatherForDay);
startActivity(intentToStartDetailActivity);
}
/**
* This method will make the View for the weather data visible and
* hide the error message.
* <p>
* Since it is okay to redundantly set the visibility of a View, we don't
* need to check whether each view is currently visible or invisible.
*/
private void showWeatherDataView() {
/* First, make sure the error is invisible */
mErrorMessageDisplay.setVisibility(View.INVISIBLE);
/* Then, make sure the weather data is visible */
mRecyclerView.setVisibility(View.VISIBLE);
}
/**
* This method will make the error message visible and hide the weather
* View.
* <p>
* Since it is okay to redundantly set the visibility of a View, we don't
* need to check whether each view is currently visible or invisible.
*/
private void showErrorMessage() {
/* First, hide the currently visible data */
mRecyclerView.setVisibility(View.INVISIBLE);
/* Then, show the error */
mErrorMessageDisplay.setVisibility(View.VISIBLE);
}
// COMPLETED (6) Remove any and all code from MainActivity that references FetchWeatherTask
@Override
public boolean onCreateOptionsMenu(Menu menu) {
/* Use AppCompatActivity's method getMenuInflater to get a handle on the menu inflater */
MenuInflater inflater = getMenuInflater();
/* Use the inflater's inflate method to inflate our menu layout to this menu */
inflater.inflate(R.menu.forecast, menu);
/* Return true so that the menu is displayed in the Toolbar */
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
// COMPLETED (5) Refactor the refresh functionality to work with our AsyncTaskLoader
if (id == R.id.action_refresh) {
invalidateData();
getSupportLoaderManager().restartLoader(FORECAST_LOADER_ID, null, this);
return true;
}
if (id == R.id.action_map) {
openLocationInMap();
return true;
}
return super.onOptionsItemSelected(item);
}
}
以上是关于java 阳光AsyncTaskLoader的主要内容,如果未能解决你的问题,请参考以下文章
在常规(支持)片段中使用 AsyncTaskLoader 更新适配器不更新 ListView