I'm trying to initialize my views with some details grabbed from my JSON Api.
I have a tablayout with multiple tabs(fragments) and in each fragment, I have placed an AsyncTask at the end of OnViewCreated ...
This works usually, but sometimes it errors out and says it cannot find elements of the view (NullPointerException)
I also notice that sometimes my AsyncTasks lag behind, swiping through the tabs sometimes gets ahead of the AsyncTasks and the tab content doesn't load for a couple of seconds after I've swiped over to them.
Is there a more correct way to do this?
Here's the code I'm working with right now (Same across each fragment of the tabview):
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mSwipeRefreshLayout = (SwipeRefreshLayout) getView().findViewById(R.id.swipe_refresh);
mSwipeRefreshLayout.setOnRefreshListener(this);
// Construct the data source
mSwipeRefreshLayout.setRefreshing(true);
mLoadTask = new LoadTask(this);
mLoadTask.execute((Void) null);
}
And here is an example of a load task:
public class LoadTask extends AsyncTask<Void, Void, Boolean> {
private String mResponse;
private Fragment mFrag;
public LoadTask(Fragment frag){
mFrag = frag;
}
#Override
protected Boolean doInBackground(Void... params) {
// Calls to functions for making an API request here
// Uses HttpUrlConnection
// Response is stored in mResponse
int responseCode = fullResponse.getStatus();
mResponse = fullResponse.getMessage();
Log.w("Response", mResponse);
if(responseCode == 200)
return true;
else
return false;
}
#Override
protected void onPostExecute(final Boolean success) {
mLoadTask = null;
if (success) {
// Initialize adapter and set it to the recyclerview
// Or call initializeView function which sets the view
// elements according the details of the response
} else {
// Error handling code
}
mSwipeRefreshLayout.setRefreshing(false);
}
#Override
protected void onCancelled() {
mLoadTask = null;
}
}
Related
I have the following piece of code which retrieve some weather data from the openweathermap api. The AsyncTask class is used for that purpose.
public class ForecastFragment extends Fragment {
String imageUrl;
ListView listView;
List<WeatherForecastData> WeatherForecastDataList;
String IMG_URL = "http://api.openweathermap.org/img/w/";
Fragment fragment;
public ForecastFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//Inflate xml view and convert it to a View object
View rootView = inflater.inflate(R.layout.fragment_forecast, container, false);
//Initialise ListView.
listView = (ListView) rootView.findViewById(R.id.listView);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String temp = WeatherForecastDataList.get(position).getWeatherTemperature();
Toast.makeText(getActivity(), temp + "° C"+" Have a nice day", Toast.LENGTH_SHORT).show();
}
});
return rootView;
}
//Now we are ready for further processing
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
if (savedInstanceState == null) {
if(isOnline()) {
requestData("http://api.openweathermap.org/data/2.5/forecast/daily?lat=50.09&lon=14.42&cnt=9&&units=metric&mode=json");
}else{
Toast.makeText(getActivity(),"There is no internet connection",Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putString("ImageURL", imageUrl);
super.onSaveInstanceState(savedInstanceState);
}
//We create a MyTask object,and execute the async. thread with the specified url which is shown just above.
private void requestData(String uri) {
MyTask task = new MyTask();
task.execute(uri);
}
//AsyncTask that will do the asynchronous threading. It displays the weather's icon,description
//and temperature in the main thread via the OnPostExecute(...) method.
private class MyTask extends AsyncTask<String, String, List<WeatherForecastData>> {
#Override
protected void onPreExecute() {
//Used to initialise Views such as Progress Bars which are not needed for this
//project.
}
#Override
protected List<WeatherForecastData> doInBackground(String... params) {
//Read the url,specify the METHOD GET, and store it in content.
String content = HttpManager.getData(params[0]);
//JSON parsing of the openweather api's response. It is not hard,but I had to use the
//debugger quite a lot to make sure that I deserialise the correct JSON values into Strings.
WeatherForecastDataList = WeatherJSONParser.parseFeed(content);
//Fetching the url image
for (WeatherForecastData d : WeatherForecastDataList) {
try {
imageUrl = IMG_URL + d.getPhoto();
InputStream in = (InputStream) new URL(imageUrl).getContent();
Bitmap bitmap = BitmapFactory.decodeStream(in);
//Is it deprecated?
d.setBitmap(bitmap);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return WeatherForecastDataList;
}
//WeatherForecastData is the Object that contains all that instances we want to display.
#Override
protected void onPostExecute(List<WeatherForecastData> result) {
if (result == null) {
Toast.makeText(getActivity(), "There is some wrong,and data can not be displayed", Toast.LENGTH_LONG).show();
return;
}
WeatherForecastDataList = result;
//Display the ListView.
WeatherAdapter adapter = new WeatherAdapter(getActivity(), R.layout.weather_row, WeatherForecastDataList);
listView.setAdapter(adapter);
}
}
protected boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
} else {
return false;
}
}
}
My question is how to make my async task class to work when phone rotates.In other words,I don't want my Fragment to be killed,but storing the weather get I get. I saw other questions here too,but I am confused in this part. Thank you.
Making config changes in the manifest is not the recommended way to save the instance of the fragment.
Instead, you should save the instance of the fragment in container activity's onSaveInstanceState() overriden method.
Below is a small snippet that will help you:
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState,"fragmentInstanceSaved",getSupportFragmentManager().findFragmentById(R.id.fragment_container));
}
Now, in your container activity's onCreate method check if bundle is null or not:
if(savedInstanceState!=null){
Fragment fragment = getSupportFragmentManager().getFragment(savedInstanceState,"fragmentInstanceSaved");
//recreate your preserved fragment here
}else{
//goto ur default activity or fragment....
}
I have a fragment activity and want to get data from my php script. I need this data to draw my ui effectively. My problem is my UI/fragment draws before i get data back, im not sure why as i fire it as early as i can in onCreate'. I put a dialog into pre and post to effectively freeze UI while data is retreived in background but....I dont see this happening, i think im too late in calling itas when the dialog appears during debug it shows ontop of a drawn screen which is baffling to me.
I have an alternative solution which is to fire the asyncTask in calling activity (previous activity) and pass result in bundle but i don't like this solution as its rigid and may cause issues with screen rotation.
I have been stuck on this for ages, can anybody tell me specifically where to put my async execute - the dialog should effectively make it a sync process. I have placed my asynctask everywhere i think possible/sensible and no luck.
In below i have the execute in the oncreate(). Note the execute doesnt d anything but update a test string which is "no change" beforehand, and "changed" in the postexecute so i can see what state its in at various points in code. It doesnt change before i draw my screen.
public class StaggeredGridActivityFragment extends FragmentActivity {
String test ="not changed";
private TilesAdapter mAdapter;
private ArrayList<String> mData;
private StaggeredGridView mGridView;
private static final String TAG = "StaggeredGridActivityFragment";
#Override
protected void onCreate(Bundle savedInstanceState) {
try
{
// Loading tile data in Background Thread
new GetLoginTiles().execute();
}
catch (Exception e)
{
e.printStackTrace();
}
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE); //remove title bar
final FragmentManager fm = getSupportFragmentManager();
// Create the list fragment and add it as our sole content.
if (fm.findFragmentById(android.R.id.content) == null) {
final StaggeredGridFragment fragment = new StaggeredGridFragment();
fm.beginTransaction().add(android.R.id.content, fragment).commit();
}
Intent i=getIntent();
Bundle extras = i.getExtras();
String tmp = extras.getString("myKey");
}
private class StaggeredGridFragment extends Fragment implements AbsListView.OnScrollListener, AbsListView.OnItemClickListener {
//private StaggeredGridView mGridView;
private boolean mHasRequestedMore;
// private TilesAdapter mAdapter;
//private ArrayList<String> mData;
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return inflater.inflate(R.layout.activity_sgv, container, false);
}
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
List<NameValuePair> params = new ArrayList<NameValuePair>();
//Encapsulate all within a post cereate from a async task or call a blocking http call
super.onActivityCreated(savedInstanceState);
mGridView = (StaggeredGridView) getView().findViewById(R.id.grid_view);
if (savedInstanceState == null) {
final LayoutInflater layoutInflater = getActivity().getLayoutInflater();
View header = layoutInflater.inflate(R.layout.list_item_header_footer, null);
mGridView.addHeaderView(header);
}
if (mAdapter == null) {
mAdapter = new TilesAdapter(getActivity(), R.id.summary1_value);
}
if (mData == null) {
mData = ActivityTileData.getLoginTileDataArray(getActivity());
}
for (String data : mData) {
mAdapter.add(data); //Add each mData TileAdapter element to an mAdapter where it will be further broken down and used by the TileAdapter
}
mGridView.setAdapter(mAdapter);
mGridView.setOnScrollListener(this);
mGridView.setOnItemClickListener(this);
}
#SuppressLint("LongLogTag")
#Override
public void onScrollStateChanged(final AbsListView view, final int scrollState) {
Log.d(TAG, "onScrollStateChanged:" + scrollState);
}
#SuppressLint("LongLogTag")
#Override
public void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount, final int totalItemCount) {
Log.d(TAG, "onScroll firstVisibleItem:" + firstVisibleItem +
" visibleItemCount:" + visibleItemCount +
" totalItemCount:" + totalItemCount);
// our handling
if (!mHasRequestedMore) {
int lastInScreen = firstVisibleItem + visibleItemCount;
if (lastInScreen >= totalItemCount) {
Log.d(TAG, "onScroll lastInScreen - so load more");
mHasRequestedMore = true;
onLoadMoreItems();
}
}
}
//Loads all of the objects from the getLoginTileData() if called
private void onLoadMoreItems() {
while(mAdapter.getCount()<mData.size()) {
//final ArrayList<String> sampleData = SampleData.generateSampleData();
final ArrayList<String> loginTileData = ActivityTileData.getLoginTileDataArray(getActivity());
for (String data : loginTileData) {
mAdapter.add(data.toString());
}
// stash all the data in our backing store
mData.addAll(loginTileData);
// notify the adapter that we can update now
mAdapter.notifyDataSetChanged();
mHasRequestedMore = false;
}
}
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Toast.makeText(getActivity(), "Item Clicked: " + position, Toast.LENGTH_SHORT).show();
}
}
// Progress Dialog
private ProgressDialog qDialog;
// JSON parser class
JSONParser jParser = new JSONParser();
String url_login ="http://xxx/xxx.php";
/**
* Background Async Task to Load all images by making HTTP Request
* */
class GetLoginTiles extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
super.onPreExecute();
qDialog = new ProgressDialog(StaggeredGridActivityFragment.this);
qDialog.setMessage("Please wait...");
qDialog.setIndeterminate(false);
qDialog.setCancelable(false);
qDialog.show();
}
#Override
protected String doInBackground(String... args) {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
// getting JSON string from URL
JSONObject jsonLogin = jParser.makeHttpRequest(url_login, "GET", params);
test=jsonLogin.toString();
return jsonLogin.toString();
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String jsonString) {
// dismiss the dialog after getting all questions
qDialog.dismiss();
// updating UI from Background Thread
runOnUiThread(new Runnable() {
public void run() {
/**
* Updating parsed JSON data into imagebuttons
* */
test="local test has changed";
}
});
}
}
}
I have an alternative solution which is to fire the asyncTask in calling activity (previous activity) and pass result in bundle but i don't like this solution as its rigid and may cause issues with screen rotation.
this is a good way to do it
override onSaveInstanceState to save the extras between rotations
also see here for more details
edit: it seems you are trying to change the text using
test="local test has changed";
whaat you need to do is pass the activity to the asynctask then
VIEWTYPEHERE button= ( VIEWTYPEHERE) activity.findViewById(R.id.YOUR_VIEW"S_ID_HERE);
button.setText("");
a couple of notes
on post execute runs on ui thread you don't need a new runnable
also you forgot to call .run() on it
I have a fragment activity. When i click the fragment it fires a listener which fires an AsyncTask. I need the Async tasks result before moving to the next line of code in the listener i.e i need the asyncTask to be synchronous.
To do this i usually use a dialog to effectively make user wait for asyncTask onPostExecute(). But my dialog isnt appearing and my code is moving on past the asyncTask and into the bundle code which then adds null variables, sad face.
Here is the bones of my fragment class, let me know if you need anything else, i'm conscious of posting too much but i am sure its connected to the structure of my class and fact i'm using fragments.
public class Login_StaggeredGrid_Fragment_Activity extends FragmentActivity
{
private ArrayList<String[]> gameSummaryTilesData;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
final FragmentManager fm = getSupportFragmentManager();
// Create the list fragment and add it as our sole content.
if (fm.findFragmentById(android.R.id.content) == null) {
final StaggeredGridFragment fragment = new StaggeredGridFragment();
fm.beginTransaction().add(android.R.id.content, fragment).commit();
}
}
private class StaggeredGridFragment extends Fragment implements AbsListView.OnScrollListener, AbsListView.OnItemClickListener
{
private StaggeredGridView mGridView;
private boolean mHasRequestedMore;
private TilesAdapter mAdapter;
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return inflater.inflate(R.layout.activity_sgv, container, false);
}
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
List<NameValuePair> params = new ArrayList<NameValuePair>();
//Encapsulate all within a post cereate from a async task or call a blocking http call
super.onActivityCreated(savedInstanceState);
mGridView = (StaggeredGridView) getView().findViewById(R.id.grid_view);
if (savedInstanceState == null) {
final LayoutInflater layoutInflater = getActivity().getLayoutInflater();
View header = layoutInflater.inflate(R.layout.list_item_header_footer, null);
mGridView.addHeaderView(header);
}
if (mAdapter == null) {
mAdapter = new TilesAdapter(getActivity(), R.id.summary1_value);
}
for (String[] data : loginTilesData) {
mAdapter.add(data); //Add each loginTilesData TileAdapter element to an mAdapter where it will be further broken down and used by the TileAdapter
}
mGridView.setAdapter(mAdapter);
mGridView.setOnScrollListener(this);
mGridView.setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id)
{
try
{
// Loading Games in Background Thread
new GetGamesSummaryTiles().execute();
}
catch (Exception e)
{
e.printStackTrace();
}
Intent i = new Intent(Login_StaggeredGrid_Fragment_Activity.this, GamesSummary_Fragment_Activity.class);
i.putExtra("gamesSummaryTilesData", gameSummaryTilesData);
startActivity(i);
}
}
/**
* Background Async Task to get data for next activity by making HTTP Request
* */
// Progress Dialog
private ProgressDialog qDialog;
// JSON parser class
JSONParser jParser = new JSONParser();
String url_login ="http://XX.XX.XXX.XX/XXXX.php";
class GetGamesSummaryTiles extends AsyncTask<String, String, String>
{
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute()
{
super.onPreExecute();
qDialog = new ProgressDialog(getBaseContext());
qDialog.setMessage("Please wait...");
qDialog.setIndeterminate(false);
qDialog.setCancelable(false);
qDialog.show();
}
#Override
protected String doInBackground(String... args)
{
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
// getting JSON string from URL
JSONObject jsonLogin = jParser.makeHttpRequest(url_login, "GET", params);
pk_http pk_dbComms = new pk_http();
try {
gameSummaryTilesData = pk_dbComms.formatHttpResponse_SummaryTile(jsonLogin);
} catch (JSONException e) {
String test = e.getStackTrace().toString();
e.printStackTrace();
}
return jsonLogin.toString();
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String jsonString)
{
// dismiss the dialog after getting all questions
qDialog.dismiss();
// updating UI from Background Thread
/*runOnUiThread(new Runnable() {
public void run() {
}
});*/
}
}
}
Put the your intent calling code in your onPostExecute method and your problem will be solved
move the below code from onItemClick() to onPostExceute
Intent i = new Intent(Login_StaggeredGrid_Fragment_Activity.this, GamesSummary_Fragment_Activity.class);
i.putExtra("gamesSummaryTilesData", gameSummaryTilesData);
startActivity(i);
put your below code in postExecute() methode of asyncTask...
Intent i = new Intent(Login_StaggeredGrid_Fragment_Activity.this, GamesSummary_Fragment_Activity.class);
i.putExtra("gamesSummaryTilesData", gameSummaryTilesData);
startActivity(i);
Can any one please explain how to make endless adapter concept for view pager
I am currently using view pager to see my datas. On every 10th swipe of the view pager I need to hit the server and take dynamic response and need to update the viewpager. Obviously we need to use the endless adapter concept. But I was confused with the exact concept. Anyone please do the needful...
Thanks in advance...
I’ve implemented an endless ViewPager. I think it suits you needs. The request is simulated with a time delay in the AsyncTask thread.
//ViewPagerActivity
public class ViewPagerActivity extends FragmentActivity {
private ViewPager vp_endless;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_endless_view_pager);
vp_endless = (ViewPager) findViewById(R.id.vp_endless);
vp_endless.setAdapter(new FragmentViewPagerAdapter(getSupportFragmentManager()));
}
}
//FragmentViewPagerAdapter
public class FragmentViewPagerAdapter extends FragmentStatePagerAdapter {
private List<CustomObject> _customObjects;
private volatile boolean isRequesting;
private static final int ITEMS_PER_REQUEST = 10;
public FragmentViewPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
_customObjects = HandlerCustomObject.INSTANCE._customObjects;
}
#Override
public Fragment getItem(int position) {
CustomFragment fragment = new CustomFragment();
fragment.setPositionInViewPager(position);
if (position == _customObjects.size() && !isRequesting)
new AsyncRequestItems().execute("www.test.com");
return fragment;
}
#Override
public int getCount() {
return Integer.MAX_VALUE;
}
public class AsyncRequestItems extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... urls) {
isRequesting = true;
//Fake request lag
try {Thread.sleep(2500);}
catch (InterruptedException e) {e.printStackTrace();}
for (int i = 0; i < ITEMS_PER_REQUEST; i++) {
_customObjects.add(new CustomObject());
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
isRequesting = false;
}
}
}
//CustomFragment
public class CustomFragment extends Fragment {
private CustomObject _customObject;
private TextView tv_position;
private ProgressBar pb_loading;
private View root;
private int _positionInViewPager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
root = inflater.inflate(R.layout.frament_endless_view_pager, container, false);
pb_loading = (ProgressBar) root.findViewById(R.id.pb_loading);
tv_position = (TextView) root.findViewById(R.id.tv_position);
_customObject = retrieveDataSafety();
if(_customObject != null) bindData();
else createCountDownToListenerForUpdates();
return root;
}
public void createCountDownToListenerForUpdates() {
new CountDownTimer(10000, 250) {
public void onTick(long millisUntilFinished) {
_customObject = retrieveDataSafety();
if(_customObject != null) {
bindData();
cancel();
}
}
public void onFinish() {}
}.start();
}
private CustomObject retrieveDataSafety() {
List<CustomObject> customObjects = HandlerCustomObject.INSTANCE._customObjects;
if(customObjects.size() > _positionInViewPager)
return customObjects.get(_positionInViewPager);
else
return null;
}
private void bindData() {
pb_loading.setVisibility(View.GONE);
String feedback = "Position: " + _positionInViewPager;
feedback += System.getProperty("line.separator");
feedback += "Created At: " + _customObject._createdAt;
tv_position.setText(feedback);
}
public void setPositionInViewPager(int positionAtViewPager) {
_positionInViewPager = positionAtViewPager;
}
}
//CustomObject
public class CustomObject {
public String _createdAt;
public CustomObject() {
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
_createdAt = dateFormat.format(new Date());
}
}
//HandlerCustomObject
public enum HandlerCustomObject {
INSTANCE;
public List<CustomObject> _customObjects = new ArrayList<CustomObject>();
}
Well, let's start from the beginning.
If you would like to have 'endless' number of pages you need to use some trick. E.g. you can't store endless number of pages in memory. Probably Android will destroy PageView everytime, when it isn't visible. To avoid destroying and recreating those views all the time you can consider recycling mechanism, which are used e.g. ListView. Here you can check and analyse idea how to implement recycling mechanism for pager adapter.
Moreover to make your UI fluid, try to make request and download new data before user gets to X0th page (10, 20, 30, 40...). You can start downloading data e.g when user is at X5th (5, 15, 25...) page. Store data from requests to model (it could be e.g. sqlite db), and user proper data based on page number.
It's just a brief of solution, but it's interesting problem to solve as well;)
Edit
I've started looking for inspiration and just found standalone view recycler implemented by Jake Wharton and called Salvage. Maybe it will be good start to create solution for your problem.
I have an android app that I am having trouble with.
Basically the ProgressDialog is not showing at all. I believe this to be a threading issue of some sort but I don't know how to fix it.
I am using ActionBarSherlock with some Fragments. I am also using the new Android DrawerLayout where I have my options on the drawer, which replace a fragment when clicked.
On first load of my app, I want to check the database to see if the inital data has been downloaded. If not, then I go off and begin an AsyncTask to download the data. This SHOULD have a ProgressDialog display during this, but it doesnt.
Can someone see where I am going wrong? Thanks.
MainScreen - The default landing page/fragment when the app opens
public class MainScreen extends SherlockFragment {
public static final String TAG = "MainScreen";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_main, container, false);
setHasOptionsMenu(false);
ImageView imgLogo = (ImageView) rootView.findViewById(R.id.imgMainScreen);
imgLogo.setOnClickListener(new ButtonHandler(getActivity()));
checkDatabase();
return rootView;
}
private void checkDatabase() {
//Ensure there is data in the database
DBHelper db = new DBHelper(this.getSherlockActivity());
db.checkDatabase();
}
...
}
DBHelper.checkDatabase() - The method that initiates the download
public void checkDatabase() {
if (isEmpty()) {
//Connect to net and download data
NetworkManager nm = new NetworkManager(activity);
if (!nm.downloadData()) {
Toast.makeText(activity, R.string.internetCheck, Toast.LENGTH_SHORT).show();
}
}
}
and finally
NetworkManager.downloadData() - The method that kicks off the AsyncTask:
public boolean downloadData() {
try {
return new HttpConnection(activity).execute().get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return false;
}
public class HttpConnection extends AsyncTask<Void, Void, Boolean> {
private ProgressDialog progressDialog;
private Activity m_activity;
protected HttpConnection(Activity activity) {
m_activity = activity;
}
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(m_activity);
progressDialog.setMessage("Wait ...");
progressDialog.setCancelable(false);
progressDialog.setMax(100);
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.show();
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Void... params) {
String[] types = new String[]{"type1", "type2", "type3", "type4", };
StringBuilder sb = new StringBuilder();
for(String type : types) {
sb = new StringBuilder();
if(DBHelper.TYPE4_TABLE.equals(type)) {
InputStream is = activity.getResources().openRawResource(R.raw.dbdata);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
try {
sb.append(reader.readLine());
} catch (IOException e) {
Toast.makeText(activity.getApplicationContext(), "Error retriveving data", Toast.LENGTH_SHORT).show();
Log.e(Constants.TAG, "Error reading data");
e.printStackTrace();
}
} else {
sb = fetchURLData(Constants.ALL_URL+type);
}
cleanDataAndStore(sb, type);
}
return true;
}
#Override
protected void onPostExecute(Boolean result){
progressDialog.hide();
}
}
Using the above code, all I get is a white screen as the app tries to load, and sometimes an ANR. When the download is done, the fragment loads. So it works fine except for the missing ProgressDialog.
PS, Notice I'm setting the activity in each constructor.
Thanks.
Remove .get() from return new HttpConnection(activity).execute().get(); You are basically locking your UI thread. Once removed it should work as AsyncTasks are expected to work.
The purpose is to be Asynchronous so boolean downloadData() should have a return type of void. If you need to do something with the data then you should implement an interface "listener" and pass it to the AsyncTask.
Example Listener:
class TaskConnect extends AsyncTask<Void, Void, ConnectionResponse> {
private final AsyncTaskListener mListener;
/**
*
*/
public TaskConnect(AsyncTaskListener listener) {
...
mListener = listener;
}
#Override
protected void onPreExecute() {
if (mListener != null) {
mListener.onPreExecute(mId);
}
}
#Override
protected ConnectionResponse doInBackground(Void... cData) {
...
return responseData;
}
#Override
protected void onPostExecute(ConnectionResponse response) {
if (mListener != null) {
mListener.onComplete(response);
} else {
LOG.w("No AsyncTaskListener!", new Throwable());
}
}
}
public interface AsyncTaskListener {
public abstract void onPreExecute(int id);
public abstract void onComplete(ConnectionResponse response);
}
My issue was not the common issue of others where they were calling get() method after execute() method. My issue was the Context I was passing to my AsyncTask method. I have a settingsActivity and I have a ReadMeActivity that calls the asynctask task. Instead of using the context in which is was being called (ReadMeActivity.this) I used the settingsActivity which prevented it from being seen. Once I switched it and passed it the context in which the activity was being called it worked.
Hope it helps someone else.