Trying to set text in EditText from AsyncTask in my fragment. This works great in my other classes but the Fragment is throwing me off.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.profile_fragment_main, container,
false);
new getinfo().execute();
if (emailTwo != null) {
email2.setText(emailTwo);
}
if (emailThree != null) {
email3.setText(emailThree);
}
if (mailingaddress1 != null) {
mail1.setText(mailingaddress1);
}
} // end of onCreate
class getinfo extends AsyncTask<String, String, String> {
// onPreExecute() and onPostExecute here
#Override
protected String doInBackground(String... args) {
int success;
try {
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("username", restoredemail));
JSONObject json = jsonParser.makeHttpRequest(LOGIN_URL, "POST",
params);
success = json.getInt(TAG_SUCCESS);
if (success == 2) {
emailTwo = json.getString("secondemail");
emailThree = json.getString("thirdemail");
mailingaddress1 = json.getString("mailingaddress1");
return json.getString(TAG_MESSAGE);
} else {
Log.d("Login Failure!", json.getString(TAG_MESSAGE));
return json.getString(TAG_MESSAGE);
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
Any help would be GREATLY appreciated. I tried putting the editText .setText in the onPostExecute but the fragment won't allow it. I also tried returning the values but it only allows one item.
Try this approach:
Create an interface in your async task with a method.
Implement that interface in your activity. Override the method
Now inside your onPostExecute, call the interface method to notify the activity
From within that method (in your activity), just notify your fragment by calling its method which should simply set the text in the EditText field.
Example Code
public class FragmentA extends Fragment implements MyAsyncTask.OnDataFetchedListener
{
//do all your stuff here
private EditText text;
#Override
public View onCreateView( ....)
{
//get edit text views here
}
#Override
public void updatText(String[] data)
{
String firstValue = data[0];
text.setText(firstValue);
}
}
Now in your async task do the following:
public class MyAsyncTask extends AsnycTask<String, String, String>
{
private String[] data;
#Override onPreExecute(){}
#Override protected String doInBackground(String ..)
{
//do whatever you need here and return whatever you need
//add your data to the list here
}
#Override
public void onPostExecute(String result)
{
//you can return a list of results here
try{
((OnDataFetchedListener), getActivity()).updateText(data);
}catch(ClassCastException)
{
}
}
public interface OnDataFetchedListener
{
void updateText(String[] data);l
}
}
I hope this helps you.
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. 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);
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.
I'm doing the refactoring of an application that uses AsyncTask to make HTTP calls to a web service.
Now use a simple Activity, at the moment when I needs to invoke the service using a AsyncTask in this way:
private class MyAsyncTask extends AsyncTask {<String, Void, Boolean>
private ProgressDialog progressDialog;
private xmlHandler handler;
# Override
protected void OnPreExecute () {
progressDialog = new ProgressDialog (home.This);
progressDialog
. SetMessage (getString (R.string.home_loadinfo_attendere));
progressDialog.setCancelable (false);
progressDialog.show ();
}
# Override
protected Boolean doInBackground (String... params) {
try {
xmlHandler handler = new XmlHandler();
return Service
. GetInstance ()
. CallService (
ServiceType.GETINFO,
Home.This, handler, null);
} Catch (Exception e) {
e.printStackTrace ();
return false;
}
}
# Override
protected void OnPostExecute (Boolean success) {
progressDialog.dismiss ();
String message = null;
if (success | | (handler == null))
message = getString (R.string.server_result_msg500);
else {
switch (handler.getStatusCode ()) {
case 200:
doStuffWithHandler(handler);
return;
case 500:
message = getString (R.string.server_result_msg500);
break;
case 520:
message = getString (R.string.server_result_msg520);
break;
default:
message = getString (R.string.server_result_msg500);
break;
}
}
if (message! = null) {
AlertDialog.Builder builder = new AlertDialog.Builder (home.This);
builder.setTitle (R.string.home_loadinfo_error_title)
. SetMessage (message)
. SetCancelable (true)
. SetNegativeButton (R.string.close_title,
new DialogInterface.OnClickListener () {
# Override
public void onClick (DialogInterface dialog,
int id) {
dialog.cancel ();
}
});
AlertDialog alert = builder.create ();
Alert.show ();
}
}
}
doStuffWithHandler(handler){
// populate interface with data from service
}
I want to do the same but using Android compatibility libraries and FragmentActivity. I read a little about loader but I did not understand how I could use them in this same way, Could you please tell me if this is the right way (FragmentActivity, Fragment and Loader) and how to implement it also addresses giving me examples?
You could create a Loader, something like this:
public abstract class MyLoader extends AsyncTaskLoader<String> {
public MyLoader(Context context) {
super(context);
}
private String result;
protected String error;
#Override
public final String loadInBackground() {
try {
error = null;
// Load your data from the server using HTTP
...
result = ...
...
return result;
}
catch (Exception e) {
Logger.e("ResourceLoader", "Loading resource failed.", e);
error = e.getMessage();
}
return null;
}
#Override
protected void onStartLoading() {
if (!TextUtils.isEmpty(error)) {
deliverResult(result);
}
if (takeContentChanged()) {
forceLoad();
}
}
#Override
public void deliverResult(String data) {
if (isReset()) {
return;
}
result = data;
if (isStarted()) {
try {
super.deliverResult(data);
}
catch(Exception e) {
Log.e("ResourceLoader", "Caught exception while delivering result.", e);
}
}
}
public String getError() {
return error;
}
}
In your Fragment, you can initialize this loader:
public class MyLoaderFragment extends Fragment implements LoaderCallbacks<String> {
....
....
String message;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
....
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(0, getArguments(), this);
}
#Override
public Loader<String> onCreateLoader(int id, Bundle args) {
return new MyLoader(getActivity());
}
#Override
public void onLoadFinished(Loader<String> loader, String result) {
// Here you have the result in 'result'.
message = result;
...
}
....
}
And instead of just returning a simple 'String' result, you can return any object you like. Just adjust the MyLoader and LoaderCallbacks implementation accordingly.
You can use Asynctask in Fragment exactly as you did in your Activity, few things change, like:
progressDialog = new ProgressDialog (home.This);
change to:
progressDialog = new ProgressDialog (getApplication());
return Service
. GetInstance ()
. CallService (
ServiceType.GETINFO,
Home.This, handler, null);
change to:
return Service
. GetInstance ()
. CallService (
ServiceType.GETINFO,
getApplication(), handler, null);
Anything special to implements Asynctask in Fragment.
I think you need to read more about Fragment itself.
I am using Async tasks to get string from the menu activity and load up some stuff..but i am
not able to do so..Am i using it in the right way and am i passing the parameters correctly?
Please see the code snippet. thanks
private class Setup extends AsyncTask<Void, Integer, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
if (!(getIntent().getExtras().isEmpty())) {
Bundle gotid = getIntent().getExtras();
identifier = gotid.getString("key");
}
} catch (Exception e) {
e.getStackTrace();
} finally {
if (identifier.matches("abc")) {
publishProgress(0);
db.insert_fri();
} else if ((identifier.matches("xyz"))) {
publishProgress(1);
db.insert_met();
}
}
return null;
}
#Override
protected void onProgressUpdate(Integer... i) {
// start the song here
if (i[0] == 0) {
song.setLooping(true);
song.start();
}
}
#Override
protected void onPostExecute(Void res) {
}
#Override
protected void onPreExecute() {
// do something before execution
}
}
Avoid adding a constructor.
Simply pass your paramters in the task execute method
new BackgroundTask().execute(a, b, c); // can have any number of params
Now your background class should look like this
public class BackgroundTask extends AsyncTask<String, Integer, Long> {
#Override
protected Long doInBackground(String... arg0) {
// TODO Auto-generated method stub
String a = arg0[0];
String b = arg0[1];
String c = arg0[2];
//Do the heavy task with a,b,c
return null;
}
//you can keep other methods as well postExecute , preExecute, etc
}
Instead of this i would do
private class Setup extends AsyncTask<String, Integer, Void> {
#Override
protected Void doInBackground(String... params) {
String identifier = params[0];
if (identifier.matches("abc")) {
publishProgress(0);
db.insert_fri();
} else if ((identifier.matches("xyz"))) {
publishProgress(1);
db.insert_met();
}
}
return null;
}
#Override
protected void onProgressUpdate(Integer... i) {
// start the song here
if (i[0] == 0) {
song.setLooping(true);
song.start();
}
}
#Override
protected void onPostExecute(Void res) {
}
#Override
protected void onPreExecute() {
// do something before execution
}
}
and check for "identifier" before invoking the asynctask to prevent overhead of creating a AsyncTask
like this
if (!(getIntent().getExtras().isEmpty())) {
Bundle gotid = getIntent().getExtras();
identifier = gotid.getString("key");
new Setup().execute(identifier);
}
A simple way is to add a constructor:
public Setup(String a, Int b) {
this.a = a;
this.b = b;
}
AsyncTask means doInBackground() returns Void, onProgressUpdate() takes Integer params and doInbackground takes... String params !
So you don't need (and REALLY shouldn't) use Intent, since it is meant to be used for passing arguments through Activities, not Threads.
And as told before, you can make a constructor and a global parameter to your class called "identifier"
public class Setup...
{
private String identifier;
public Setup(String a) {
identifier = a;
}
}
Hoped it could help.
Regards