Executing Async tasks in fragments - android

I am attempting to execute an async task in a fragment after converting my activities into fragments. When I call my async task from the activity I have to pass 'this' with it in order to allow the async task to change text and things after it receives the information. I am a bit confused on how to do this all with fragments. Here is what I got so far:
I execute the asynck task with:
new GetYourTopTasteBeers(this).execute(url);
the code for the async task is:
public class GetYourTopTasteBeers extends AsyncTask<String, Void, String> {
Context c;
private ProgressDialog Dialog;
public GetYourTopTasteBeers (Context context)
{
c = context;
Dialog = new ProgressDialog(c);
}
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
return readJSONFeed(arg0[0]);
}
protected void onPreExecute() {
Dialog.setMessage("Getting beers");
Dialog.setTitle("Loading");
Dialog.setCancelable(false);
Dialog.show();
}
protected void onPostExecute(String result){
//decode json here
try{
JSONArray jsonArray = new JSONArray(result);
//acces listview
ListView lv = (ListView) ((Activity) c).findViewById(R.id.topTasteBeers);
//make array list for beer
final List<ShortBeerInfo> tasteList = new ArrayList<ShortBeerInfo>();
for(int i = 0; i < jsonArray.length(); i++) {
String beer = jsonArray.getJSONObject(i).getString("beer");
String rate = jsonArray.getJSONObject(i).getString("rate");
String beerID = jsonArray.getJSONObject(i).getString("id");
String breweryID = jsonArray.getJSONObject(i).getString("breweryID");
int count = i + 1;
beer = count + ". " + beer;
//create object
ShortBeerInfo tempTaste = new ShortBeerInfo(beer, rate, beerID , breweryID);
//add to arraylist
tasteList.add(tempTaste);
//add items to listview
ShortBeerInfoAdapter adapter1 = new ShortBeerInfoAdapter(c ,R.layout.brewer_stats_listview, tasteList);
lv.setAdapter(adapter1);
//set up clicks
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
ShortBeerInfo o=(ShortBeerInfo)arg0.getItemAtPosition(arg2);
String tempID = o.id;
String tempBrewID = o.brewery;
Toast toast = Toast.makeText(c, tempID, Toast.LENGTH_SHORT);
toast.show();
//todo: change fragment to beer page
Intent myIntent = new Intent(c, BeerPage2.class);
myIntent.putExtra("id", tempID);
myIntent.putExtra("breweryID", tempBrewID);
c.startActivity(myIntent);
}
});
}
}
catch(Exception e){
}
Dialog.dismiss();
}
public String readJSONFeed(String URL) {
StringBuilder stringBuilder = new StringBuilder();
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(URL);
try {
HttpResponse response = httpClient.execute(httpGet);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) {
HttpEntity entity = response.getEntity();
InputStream inputStream = entity.getContent();
BufferedReader reader = new BufferedReader(
new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
inputStream.close();
} else {
Log.d("JSON", "Failed to download file");
}
} catch (Exception e) {
Log.d("readJSONFeed", e.getLocalizedMessage());
}
return stringBuilder.toString();
}
}
My problem is that I can not pass 'this' from a fragment...
Bonus Question:
Also as you can see I am not done converting my code for the fragments. I need to change this to load a fragment instead of change activity:
//todo: change fragment to beer page
Intent myIntent = new Intent(c, BeerPage2.class);
myIntent.putExtra("id", tempID);
myIntent.putExtra("breweryID", tempBrewID);
c.startActivity(myIntent);
HOw can I pass values between fragments like I am doing between activities in that above code?

Since Fragments don't admit this, you may call getActivity() instead which will provide the context you need to execute the AsyncTask.
Be careful, though, as running an AsyncTask within a Fragment may lead to return a result to the caller Activity that has already been destroyed at the time your AsyncTask concluded its process. It's necessary to take additional precautions, and always check whether the Fragment hasn't already been destroyed. This can be done using this.isAdded() in your Fragment.
A good practice is to cancel your AsyncTask in the onStop() and onPause() methods. That will make the onPostExecute() not execute code if the Fragment is not active anymore (getActivity() would return null).

You cannot pass this because in this situation this referrers to your fragment, which doesn't extend Context. But you need Context (your GetYourTopTasteBeers takes Context as a parameter):
public GetYourTopTasteBeers (Context context)
Instead, pass your Activity like so:
new GetYourTopTasteBeers(getActivity()).execute(url);

Related

Change content of listview on button click(on same screen)

So In my MainActivity There are 3 rooms(coming from server).when i click on them popup is open.This popup will having shown the list of roomId(clicked on listview item).This works fine.
Now I need like this.In popup on click of next button next roomId with api to get its module is call and update the listview.
How i do this?
Problem is:-whenever going to do always it open with new popup.
As shown in picture I need to change the content of listview on toolbar's right arrow button.
My listview is in popup.so when i change content of listview this another new popup open for new list.
This is my 1st listview(where I load all images)
modules_list.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0,
android.view.View arg1, int arg2, long arg3) {
editor.putInt("response_position",arg2).commit();
editor.putString("roomid",response.getRooms()[arg2+1].getRooms_id().getRoomId()).commit();
String serverURL = "http://dashboard.droidhomes.in/api/module?room_id=" + response.getRooms()[arg2].getRooms_id().getRoomId();
// Use AsyncTask execute Method To Prevent ANR11 Problem
new GetallModules().execute(serverURL);
}
});
GetAllmodules class to get all modules and switches of Room:-
private class GetallModules extends AsyncTask<String, Void, Void> {
// Required initialization
// private final HttpClient Client = new DefaultHttpClient();
private String Content;
private String Error = null;
private ProgressDialog Dialog = new ProgressDialog(
MainActivity.this);
protected void onPreExecute() {
// NOTE: You can call UI Element here.
Dialog.setMessage("Please wait..");
Dialog.show();
}
// Call after onPreExecute method
protected Void doInBackground(String... urls) {
/************ Make Post Call To Web Server ***********/
BufferedReader reader = null;
try {
// Defined URL where to send data
URL url = new URL(urls[0]);
// Send POST data request
pref = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
editor = pref.edit();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
String auth_token = pref.getString("auth_token", "");
conn.setRequestProperty("Authorization", auth_token);
reader = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String line = null;
// Read Server Response
while ((line = reader.readLine()) != null) {
// Append server response in string
sb.append(line + "\n");
}
// Append Server Response To Content String
Content = sb.toString();
} catch (Exception ex) {
Error = ex.getMessage();
} finally {
try {
reader.close();
} catch (Exception ex) {
}
}
/*****************************************************/
return null;
}
protected void onPostExecute(Void unused) {
// NOTE: You can call UI Element here.
// Close progress dialog
// Content=Content.replaceAll("<string>","");
// Content=Content.replaceAll("</string>", "");
Dialog.dismiss();
if (Error != null) {
Toast toast = Toast.makeText(getApplicationContext(),
"Bad request", Toast.LENGTH_LONG);
toast.show();
// uiUpdate.setText("Output : " + Error);
} else {
// Show Response Json On Screen (activity)
// uiUpdate.setText(Content);
/****************** Start Parse Response JSON Data *************/
// String OutputData = "";
// JSONObject jsonResponse;
Gson gson = new Gson();
final SearchResponse response = gson.fromJson(Content,
SearchResponse.class);
if (response.getStatus() == true) {
//response.getAuth_token()
if (response.getModule().length > 0) {
LayoutInflater li1 = LayoutInflater.from(MainActivity.this);
View promptsView = li1.inflate(R.layout.prompts_modulesdialog1, null);
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MainActivity.this);
alertDialogBuilder.setView(promptsView);
ListView list_modules = (ListView) promptsView.findViewById(R.id.lv_modules);
TextView tv_roomname = (TextView) promptsView.findViewById(R.id.tv_roomName);
ImageView iv_left=(ImageView)promptsView.findViewById(R.id.iv_left);
ImageView iv_right=(ImageView)promptsView.findViewById(R.id.iv_right);
ArrayList<String> switches = new ArrayList<String>();
iv_right.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String room_id=pref.getString("roomid","");
String serverURL = "http://dashboard.droidhomes.in/api/module?room_id=" + room_id;
// Use AsyncTask execute Method To Prevent ANR11 Problem
new GetallModules().execute(serverURL);
}
});
for (int i = 0; i < response.getModule().length; i++) {
tv_roomname.setText(response.getModule()[i].getRoom_title());
for (int j = 0; j < response.getModule()[i].getSwitches().length; j++) {
if (response.getModule()[i].getModule_name().equals(response.getModule()[i].getSwitches()[j].getModule_name_switches())) {
switches.add(response.getModule()[i].getSwitches()[j].getSwitch_name());
}
}
}
ToggleButtonListAdapter t1=new ToggleButtonListAdapter(MainActivity.this, switches);
list_modules.setAdapter(t1);
t1.notifyDataSetChanged();
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
} else {
Toast.makeText(getApplicationContext(), "No module defined for this room!!!!!!", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getApplicationContext(), "status:-" + response.getStatus(), Toast.LENGTH_SHORT).show();
}
}
}
}
Same Scenario like this.
please help me!!

Show new id for newly list when it is pressed

I wonder how to show the new list id when it is pressed? Currently the new list is showing the old list id instead itself, but when I close the app and reopen it again, it will display its id.
Firstly the data will retrieved from MySQL and load into android listView. (Assume it has only one list only).
ListView listViewUpdate;
String ID, iD;
public static final int PROJECT_REQUEST_CODE = 1;
public static final int CAMERA_REQUEST_CODE = 2;
int mClickedPosition;
String ReceiveProject, ReceiveDescription, ReceiveTimeIn, ReceiveTimeOut;
Integer ReceiveProgress;
String myJSON;
JSONArray details = null;
TextView totalHours;
String MiNtimeIn,MaXtimeOut;
List<DetailsBean> details1=new ArrayList<>();
CustomBaseAdapter objadapter;
public void BuildEditDetails(final String ID) { // Assume the ID is foreign key
class GetDataJSON extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
DefaultHttpClient httpclient = new DefaultHttpClient(new BasicHttpParams());
HttpPost httppost = new HttpPost("http://192.168.107.115/Android/CRUD/detailsRetrieve.php?id=" + ID);
// Depends on your web service
httppost.setHeader("Content-type", "application/json");
InputStream inputStream = null;
String result = null;
try {
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
inputStream = entity.getContent();
// json is UTF-8 by default
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
result = sb.toString();
} catch (Exception e) {
// Oops
} finally {
try {
if (inputStream != null) inputStream.close();
} catch (Exception squish) {
}
}
return result;
}
#Override
protected void onPostExecute(String result) {
myJSON = result;
showList();
}
}
GetDataJSON g = new GetDataJSON();
g.execute();
}
protected void showList() {
try {
JSONObject jsonObj = new JSONObject(myJSON);
details = jsonObj.getJSONArray(Configs.TAG_RESULTS);
for (int i = 0; i < details.length(); i++) {
JSONObject c = details.getJSONObject(i);
String project = c.getString(Configs.TAG_PROJECT);
String description = c.getString(Configs.TAG_WORKDESCRIPTION);
int percentage = c.getInt(Configs.TAG_PERCENTAGE);
String in = c.getString(Configs.TAG_IN);
String out = c.getString(Configs.TAG_OUT);
iD = c.getString(Configs.TAG_ID); // its real id
DetailsBean dbean=new DetailsBean(iD,project,description,percentage,in,out);
details1.add(dbean);
}
objadapter=new CustomBaseAdapter(getActivity(),details1);
listViewUpdate.setAdapter(objadapter);
} catch (JSONException e) {
e.printStackTrace();
}
When pen icon is clicked (mClickedPosition==-1), it will intent to Activity B ,and add a new list in Activity A listView. If list is pressed**(mClickedPosition!==1), it shows its id, and intent to **B for user to edit.
listViewUpdate.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> listView, View view,
int position, long id) {
mClickedPosition = position;
String iD = details1.get(position).getID();
Intent intent = new Intent(getActivity(), Edit_Details.class);
intent.putExtra("iD", iD);
intent.putExtra("ID", ID);
intent.putExtra("mClickedPosition", mClickedPosition);
Toast.makeText(getActivity(), "This is" + iD + ID, Toast.LENGTH_LONG).show();
startActivityForResult(intent, PROJECT_REQUEST_CODE);
}
});
#Override public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.addDetails:
mClickedPosition = -1;
Intent intent = new Intent(getActivity(), Edit_Details.class);
intent.putExtra("ID", ID);
// intent.putExtra("iD", iD);
startActivityForResult(intent, PROJECT_REQUEST_CODE);
break;
OnActivityResult Activity A
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { // receive from Activity B and populate ListView A
if (resultCode == Activity.RESULT_OK) {
if (requestCode == PROJECT_REQUEST_CODE) {
ReceiveProject = data.getStringExtra("project1");
ReceiveDescription = data.getStringExtra("description");
ReceiveProgress = data.getIntExtra("progress", 0);
ReceiveTimeIn = data.getStringExtra("timeIn");
ReceiveTimeOut = data.getStringExtra("timeOut");
if(mClickedPosition==-1)
{ // add list
if(objadapter!=null)
{
objadapter.addNewItem(iD,ReceiveProject,ReceiveDescription,ReceiveProgress,ReceiveTimeIn,ReceiveTimeOut);
}
}
else
{ // update list
if(objadapter!=null)
{
objadapter.changeItem(mClickedPosition,iD,ReceiveProject,ReceiveDescription,ReceiveProgress,ReceiveTimeIn,ReceiveTimeOut);
}
}
}
}
Finally CustomBaseAdapter
public class CustomBaseAdapter extends ArrayAdapter<DetailsBean>{ // for ListView
Activity context;
List<DetailsBean> details;
public CustomBaseAdapter(Activity context,List<DetailsBean> details) {
super(context, R.layout.retrieve_details, details);
this.context = context;
this.details = details;
}
public void changeItem(int m,String ID,String Project,String Description,int Percentage,String in,String out)
{
DetailsBean obj = new DetailsBean(ID, Project, Description, Percentage, in, out);
obj.setProject(Project);
obj.setProgress(Percentage+"");
obj.setTimeIn(in);
obj.setTimeOut(out);
obj.setDescription( Description);
details.set(m,obj);
this. notifyDataSetChanged();
}
public void addNewItem(String ID,String Project,String Description,int Percentage,String in,String out) {
DetailsBean obj = new DetailsBean(ID, Project, Description, Percentage, in, out);
obj.setProject(Project);
obj.setProgress(Percentage+"");
obj.setTimeIn(in);
obj.setTimeOut(out);
obj.setDescription( Description);
details.add(obj);
this.notifyDataSetChanged();
}
New list already can added below the previous list, but when I click
the new list, it still showing the old list id..How can I make it
display its id? Thanks
When come to this class, it retrieve value from MySQL
When I click 1 list or 2 list, it display their id, (1 and 2)
Now I added a new list , 3 list now
when I click the third list, it suppose to display 3 but it display 2
Show new id for newly list when it is pressed
Use onPostExecute of AddMore class for getting latest id and sending data back to previous Activity.like:
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
loading.dismiss();
try{
JSONObject jsonObject=new JSONObject(s);
int latestID=jsonObject.optInt("lastId");
//call setResult here
....
returnIntent.putExtra("project1", project1);
returnIntent.putExtra("description", description);
returnIntent.putExtra("progress", progress);
returnIntent.putExtra("timeIn", timeIn);
returnIntent.putExtra("iD", latestID); //<<<
}catch(Exception ex){
}
}
Try in adapter CustomBaseAdapter class:
public List<DetailsBean> getDetails(){
return details;
}
in onItemClick
#Override
public void onItemClick(AdapterView<?> listView, View view,
int position, long id) {
mClickedPosition = position;
String iD = listViewUpdate.getDetails().get(position).getID();
//so check id here
....
check onActivityResult:
what is iD ?? What is value of this variable?
objadapter.addNewItem(iD,ReceiveProject,ReceiveDescription,ReceiveProgress,ReceiveTimeIn,ReceiveTimeOut

android AsyncTask and UI thread interaction

I'm using the AsyncTask to open a URL, access the server, fetch the content and display them in a list view in the main activity. The content extracted consists of a title of the newspaper and a URL to the website, which will be displayed on a WebView in a second activity, if a "read" button is clicked. I coded out the program straight away and it works, but when I looked back at it, I found something that seems unreasonable, so mainly I want to make clear how the code works. Here is the code for the main activity:
package com.example.newsapp;
public class MainActivity extends Activity {
static final private String LOG_TAG = "main";
private ArrayList<Content> aList;
private class Content{
Content() {};
public String title;
public String url;
}
private class MyAdapter extends ArrayAdapter<Content>{
int resource;
public MyAdapter(Context _context, int _resource, List<Content> titles) {
super(_context, _resource, titles);
resource = _resource;
// this.context = _context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout newView;
final Content content = getItem(position);
// Inflate a new view if necessary.
if (convertView == null) {
newView = new LinearLayout(getContext());
String inflater = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater vi = (LayoutInflater) getContext().getSystemService(inflater);
vi.inflate(resource, newView, true);
} else {
newView = (LinearLayout) convertView;
}
// Fills in the view.
TextView tv = (TextView) newView.findViewById(R.id.listText);
ImageButton b = (ImageButton) newView.findViewById(R.id.listButton);
b.setBackgroundResource(0);
tv.setText(content.title);
Typeface type = Typeface.createFromAsset(getAssets(),"LiberationSerif-BoldItalic.ttf");
tv.setTypeface(type);
// Sets a listener for the button, and a tag for the button as well.
b.setTag(Integer.toString(position));
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Reacts to a button press.
Intent intent = new Intent(MainActivity.this, WebPage.class);
Bundle bundle = new Bundle();
bundle.putString("URL", content.url);
intent.putExtras(bundle);
startActivity(intent);
}
});
return newView;
}
}
class MyAsyncTask extends AsyncTask<String, String, String> {
private ProgressDialog progressDialog = new ProgressDialog(MainActivity.this);
InputStream inputStream = null;
String result = "";
Content content;
protected void onPreExecute() {
super.onPreExecute();
progressDialog.setMessage("Downloading the news...");
progressDialog.show();
progressDialog.setOnCancelListener(new OnCancelListener() {
public void onCancel(DialogInterface arg0) {
MyAsyncTask.this.cancel(true);
}
});
}
#Override
protected String doInBackground(String... params) {
String url_select = params[0];
ArrayList<NameValuePair> param = new ArrayList<NameValuePair>();
try {
// Set up HTTP post
// HttpClient is more then less deprecated. Need to change to URLConnection
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url_select);
httpPost.setEntity(new UrlEncodedFormEntity(param));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
// Read content & Log
inputStream = httpEntity.getContent();
} catch (UnsupportedEncodingException e1) {
Log.e("UnsupportedEncodingException", e1.toString());
e1.printStackTrace();
} catch (ClientProtocolException e2) {
Log.e("ClientProtocolException", e2.toString());
e2.printStackTrace();
} catch (IllegalStateException e3) {
Log.e("IllegalStateException", e3.toString());
e3.printStackTrace();
} catch (IOException e4) {
Log.e("IOException", e4.toString());
e4.printStackTrace();
}
// Convert response to string using String Builder
try {
BufferedReader bReader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"), 8);
StringBuilder sBuilder = new StringBuilder();
String line = null;
while ((line = bReader.readLine()) != null) {
sBuilder.append(line + "\n");
}
inputStream.close();
result = sBuilder.toString();
} catch (Exception e) {
Log.e("StringBuilding & BufferedReader", "Error converting result " + e.toString());
}
return result;
} // protected Void doInBackground(String... params)
protected void onPostExecute(String result) {
//parse JSON data
try {
super.onPostExecute(result);
Log.i(LOG_TAG, result);
JSONObject object = new JSONObject(result);
JSONArray jArray = object.getJSONArray("sites");
for(int i=0; i < jArray.length(); i++) {
JSONObject jObject = jArray.getJSONObject(i);
content = new Content();
if (jObject.has("title") && jObject.has("url")){
content.title = jObject.getString("title");
content.url = jObject.getString("url");
aList.add(content);
aa.notifyDataSetChanged();
}
} // End Loop
progressDialog.dismiss();
} catch (JSONException e) {
// progressDialog.dismiss();
Log.e("JSONException", "Error: " + e.toString());
}
} // protected void onPostExecute(String result)
}
private MyAdapter aa;
private MyAsyncTask loadTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadTask = new MyAsyncTask();
loadTask.execute("http://luca-ucsc.appspot.com/jsonnews/default/news_sources.json");
aList = new ArrayList<Content>();
aa = new MyAdapter(this, R.layout.list_element, aList);
ListView myListView = (ListView) findViewById(R.id.listView1);
myListView.setAdapter(aa);
aa.notifyDataSetChanged();
}
public void refresh(View v){
if (loadTask.getStatus() == AsyncTask.Status.FINISHED){
aList.clear();
aa.notifyDataSetChanged();
new MyAsyncTask().execute("http://luca-ucsc.appspot.com/jsonnews/default/news_sources.json");
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
So you can see that only after loadTask.execute() in onCreate(), do I create the object for alist and aa, but I'm already using them in onPostExecute() in the AsyncTaks class, so I'm not very clear what happens here, because onPostExecute() and the UI are on the same thread, so the code in onPostExecute() should be executed first.
I thought I should put
aList = new ArrayList<Content>();
aa = new MyAdapter(this, R.layout.list_element, aList);
into onPostExecute(), which is more logical to me, but the app crashes this way. Also I think deleting aa.notifyDataSetChanged(); in onPostExecute() shouldn't be a problem because it's also in the onCreate() method, but this actually causes the list view to be blank, without any content. Actually, putting any of the codes after loadTask.execute() into the if block of the onPostExecute() method causes some problem, or crashes the app. That would be great if somebody can give some insight or hint. Thanks for reading.
onPostExecute is called on the UI thread after the background task completes its work. You cannot guarantee the timing of this call in relation to other calls on the UI thread.
Since you are already implementing getView yourself, I recommend you extend BaseAdapter instead of ArrayAdapter and implement the other few required methods. It's not hard and you can use whatever data structure you want to back the adapter. Assuming you use a List<Content> to back the adapter, you can write a method to swap the list in place like so:
public void swapList(List<Content> newList) {
this.list = newList;
notifyDataSetChanged();
}
In your AsyncTask, you have complete control of the Params, Progress, and Result parameterized types. They don't all have to be String. You can do this instead:
private class myAsyncTask extends AsyncTask<String, Void, List<Content>> {
/* ... */
}
The String for Params is the URL (same as you do now). Void for Progress because you don't publish progress anyway. List<Content> for Result because that's the thing you actually want to end up with after doing your task.
You should do ALL of your work in doInBackground. There is no reason to deserialize a String into a JSONArray and mess around with that in onPostExecute, particularly since that is happening on the main thread. Rewrite doInBackground to return a List<Content>, and all you need in onPostExecute is this:
public void onPostExecute(List<Content> result) {
adapter.swapList(result);
}
Now you can create the adapter once (in onCreate()) and just swap the list whenever it's appropriate.

trying to launch a fragment from an async task

I have an async task which is called for a fragment and populates a listview. When I try and set the OnClick for the listview I get an error in my code for setting the fragment to load based on the listview item clicked:
FragmentManager man= getFragmentManager();
FragmentTransaction tran=man.beginTransaction();
Fragment_one = new StylePage2();
final Bundle bundle = new Bundle();
bundle.putString("beerIDSent", bID);
Fragment_one.setArguments(bundle);
tran.replace(R.id.main, Fragment_one);//tran.
tran.addToBackStack(null);
tran.commit();
The error shows for the line:
FragmentManager man= getFragmentManager();
The error is, can not resolve method getFragmentManager()
I am assuming you can only access that method from within a fragment, so I am a bit lost on how to launch it from something that extends asynctask.
The full code for the async task is below:
public class GetStyleStatisticsJSON extends AsyncTask<String, Void, String> {
Context c;
private ProgressDialog Dialog;
android.support.v4.app.Fragment Fragment_one;
public GetStyleStatisticsJSON(Context context)
{
c = context;
Dialog = new ProgressDialog(c);
}
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
return readJSONFeed(arg0[0]);
}
protected void onPreExecute() {
Dialog.setMessage("Analyzing Statistics");
Dialog.setTitle("Loading");
Dialog.setCancelable(false);
Dialog.show();
}
protected void onPostExecute(String result){
//decode json here
try{
JSONArray jsonArray = new JSONArray(result);
//acces listview
ListView lv = (ListView) ((Activity) c).findViewById(R.id.yourStyleStatistics);
//make array list for beer
final List<StyleInfo> tasteList = new ArrayList<StyleInfo>();
for(int i = 0; i < jsonArray.length(); i++) {
String style = jsonArray.getJSONObject(i).getString("style");
String rate = jsonArray.getJSONObject(i).getString("rate");
String beerID = jsonArray.getJSONObject(i).getString("id");
int count = i + 1;
style = count + ". " + style;
//create object
StyleInfo tempTaste = new StyleInfo(style, rate, beerID);
//add to arraylist
tasteList.add(tempTaste);
//add items to listview
StyleInfoAdapter adapter1 = new StyleInfoAdapter(c ,R.layout.brewer_stats_listview, tasteList);
lv.setAdapter(adapter1);
//set up clicks
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
StyleInfo o=(StyleInfo)arg0.getItemAtPosition(arg2);
String bID = o.id;
//todo: add onclick for fragment to load
FragmentManager man= getFragmentManager();
FragmentTransaction tran=man.beginTransaction();
Fragment_one = new StylePage2();
final Bundle bundle = new Bundle();
bundle.putString("beerIDSent", bID);
Fragment_one.setArguments(bundle);
tran.replace(R.id.main, Fragment_one);//tran.
tran.addToBackStack(null);
tran.commit();
}
});
}
}
catch(Exception e){
}
Dialog.dismiss();
}
public String readJSONFeed(String URL) {
StringBuilder stringBuilder = new StringBuilder();
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(URL);
try {
HttpResponse response = httpClient.execute(httpGet);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) {
HttpEntity entity = response.getEntity();
InputStream inputStream = entity.getContent();
BufferedReader reader = new BufferedReader(
new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
inputStream.close();
} else {
Log.d("JSON", "Failed to download file");
}
} catch (Exception e) {
Log.d("readJSONFeed", e.getLocalizedMessage());
}
return stringBuilder.toString();
}
}
UPDATE
I tried changing it to this:
FragmentManager man = ((Activity) c).getFragmentManager();
BUt I am getting this error:
Incompatible types.
Required:
android.support.v4.app.FragmentManager
Found:
android.app.FragmentManager
Update 2
I just tried this:
FragmentManager man= MainDraw.getFragmentManager();
and get this error:
Non-static method 'getFragmentManager()' cannot be referenced from a static context
It is very good practice to always create fragments from the holding activity only, so in this case what you would do is create a callback (interface) in your onclick to your activity that would create the fragment just like you would if you needed to communicate with your activity from your fragment.
doing this will fix your problem because Activity has getFragmentManager()
EDIT
OnArticleSelectedListener listener;
public interface OnArticleSelectedListener{
public void onArticleSelected(/*whatever you want to pass in it*/);
}
in your GetStyleStatisticsJSON create a method that sets the listener
public void setOnArticleSelectedListener(OnArticleSelectedListener listener){
this.listener = listener;
}
then in your onClick just call it
listener.onArticleSelected();
then declare your asynctask like this
GetStyleStatisticsJSON task = new GetStyleStatisticsJSON(getActvity());
task.setOnArticleSelectedListener(new OnArticleSelectedListener(){
#Override
public void onArticleSelected(){
}
});
task.execute(url)
Using
FragmentManager man= YourActivity.getFragmentManager();
instead of
FragmentManager man= getFragmentManager();

Android ListAdapter How to Correct: Cannot make a static reference to the non-static method

I'm trying to put some custom list adapters into their own classes to make my app have less redundant code and to make it more manageable.
I call on the different adapter classes thru a conditional statement within a ListFragment. I originally had the adapters in the ListFragment class and this all worked as planed. Now to clean up everything and to get all that code out of the ListFragment, I moved the Adapters out and into their own classes. Since that was done, these methods have to be static so I can call on them but these new classes now containa lot of:
Cannot make a static reference to the non-static method
setListAdapter(ListAdapter) from the type ListFragment
Specifically the setListAdapter, setListAdapter, getFragmentManager, and getFragmentManager methods. I don't want a ton of ListView Fragment classes and since a lot of code would be reused, It makes more since to only have one ListFragment and use conditionals to get the correct adapter but I don't know how to fix these new classes so I can use them.
Sorry for the long explanation. I'll try to only post the relevant code to get the idea to what I am trying to accomplish and for you to guide me.
Can this be done the way I am doing this and how do I correct it?
If there is a better way, please post some code with your explination or code in what needs to be changed within my Adapter Class.
In my fragment's onActivityCreated:
. . .
// Get the string to query from last Fragment and pass it to this
// Fragment
Bundle args = this.getArguments();
boolean rawRes = args.getBoolean(KEY_IS_RAW_RES);
String url = args.getString(KEY_URL);
int fileName = args.getInt(KEY_RES_FILE);
this.getJsonFile(url, rawRes, fileName);
}
public void getJsonFile(String url, boolean rawRes, int fileName) {
if (rawRes == true) {
getFromRawRes(fileName);
} else {
getFromURL(url);
}
}
public void getFromRawRes(int fileName) {
InputStream file = getResources().openRawResource(fileName);
JSONParser jParser = new JSONParser();
JSONArray json = jParser.getJSONFromRes(file);
ListAdapter_SevenItem.callback(json, context);//<--THIS IS A CALL TO THE ADAPTER!!
}
One of the Adapters:
public class ListAdapter_SevenItem extends ListViewFragment {
. . .
public static void callback(JSONArray json, Context c) {
if (json != null) {
// Hashmap for ListView
. . .
// create the list item mapping
String[] from = new String[]{TAG_LABEL, TAG_TITLE, TAG_DISCR, TAG_RES_FILE, TAG_IS_RAW_RES, TAG_CONT_ID};
int[] to = new int[]{R.id.listLabel, R.id.listTitle, R.id.listDiscription, R.id.listResFile, R.id.listIsRawRes, R.id.listContID};
// Updating parsed JSON data into ListView
SimpleAdapter adapter = new SimpleAdapter(c, mList, R.layout.list_item, from, to);
setListAdapter(adapter);
// selecting single ListView item
final ListView lv = setListAdapter();
// Launching new screen on Selecting Single ListItem
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
MainActivity.mLayout.toggleSidebar();
setHasOptionsMenu(true);
FragmentManager fm = getFragmentManager();
final FragmentTransaction lcFT = fm.beginTransaction();
lcFT.setCustomAnimations(R.anim.slide_in, R.anim.hyperspace_out, R.anim.hyperspace_in, R.anim.slide_out);
final Bundle args = new Bundle();
String resFile = ((TextView) view.findViewById(R.id.listResFile)).getText().toString();
int passResFile = getFragmentManager().getIdentifier(resFile, "raw", "com.andaero.app");
args.putInt("KEY_RES_FILE", passResFile);
boolean isRawRes = true;
args.putBoolean("KEY_IS_RAW_RES", isRawRes);
// Delayed to improve animations
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
ListViewFragment lvf = new ListViewFragment();
lcFT.replace(R.id.listContainer, lvf).commit();
lvf.setArguments(args);
}
}, 300);
}
});
}
}
}
You're overcomplicating things.
There should not be static method/calls like the one you use. It should be very simple. Within the list fragment's onActivityCreated(Bundle savedInstanceState) you create an instance of your list adapter, and set it as the adapter using the setListAdapter().
Check for TitlesFragment sample in the tutorial on fragments.
A ListView Fragment Class that can be reused thru-out an application.
I use jgilfelt's universal JasonArrayAdapter class that can be downloaded on GitHub. The class here below can be used over and over thru-out the application so its the only ListView class needed - Which means a reduction in redundant code/classes. Esp., if you have list views that require different attributes and/or layouts.
If your loading this ListViewFragment from another Fragment:
String uri = "http://www.xxxx/myjsonfile.json";//EXAMPLE IF FROM A URL
String uri = "json/myjsonfile.json";//EXAMPLE GETTING FROM YOUR ASSETS FOLDER
args.putString("KEY_URI", uri);
String adptrID = "#";//USED TO DETERMINE WHICH LAYOUT TO USE
args.putString("KEY_ADPTR_ID", adptrID);
ListViewFragment lvf = new ListViewFragment();
lcFT.replace(R.id.myContainer, lvf).commit();
lvf.setArguments(args);
If If your loading this ListViewFragment from within it's self, just add the appropriate items in your JSON files and get them into your setArguments(args) Bundle.
If you have any improvements/etc to the methods, feel free to add it to your comment/answer. I'm new to Android and learning as I go... Thnx
ListViewFragment Class:
public class ListViewFragment extends ListFragment implements OnItemClickListener {
. . .
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Bundle getArgs = this.getArguments();
String URI = getArgs.getString(KEY_URI);
. . .
new GetJSONTask().execute(URI);
}
class GetJSONTask extends AsyncTask<String, Integer, String> {
protected String doInBackground(String... arg0) {
String uri = arg0[0];
InputStream is = null;
if (uri.contains("http") == true) {// Get JSON from URL
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(uri);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
BufferedReader rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
while ((line = rd.readLine()) != null) {
json += line;
}
rd.close();
return json;
} catch (Exception e) {
e.printStackTrace();
return null;
}
} else {//Get JSON from Assets
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
InputStream jsonFile = getActivity().getAssets().open(uri);
Reader reader = new BufferedReader(new InputStreamReader(jsonFile, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
jsonFile.close();
} catch (IOException e) {
e.printStackTrace();
}
json = writer.toString();
// return JSON String
return json;
}
}
#Override
protected void onPostExecute(String result) {
try {
showData(result);
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getActivity(), "something went wrong", Toast.LENGTH_SHORT).show();
}
}
}
private void showData(String json) throws JSONException {
JSONObject o = new JSONObject(json);
JSONArray data = o.getJSONArray("results");
Bundle getArgs = this.getArguments();
String adptrID = getArgs.getString(KEY_ADPTR_ID);
if (adptrID == "3") {//Adapter for 3 items
String[] from = new String[]{"label", "title", "description", "uri", "adapterID", "containerID"};
int[] to = new int[]{R.id.listLabel, R.id.listTitle, R.id.listDiscription, R.id.listURI, R.id.listAdapterID, R.id.listContID};
ListAdapter adapter = new JSONArrayAdapter(getActivity(), data, R.layout.list_item, from, to, null);
getListView().setOnItemClickListener(this);
getListView().setAdapter(adapter);
}
if (adptrID == "4") {//Adapter for 4 items - Get the idea?
. . .
} . . .//Additional Adapter can be added....
}
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final Bundle args = new Bundle();
Bundle getArgs = this.getArguments();
String uri = ((TextView) view.findViewById(R.id.listURI)).getText().toString();
args.putString("KEY_URI", uri);
String adptrID = ((TextView) view.findViewById(R.id.listAdapterID)).getText().toString();
args.putString("KEY_ADPTR_ID", adptrID);
String contID = ((TextView) view.findViewById(R.id.listContID)).getText().toString();
args.putString("KEY_CONTAINER_ID", contID);
//Conditional to determine witch container to load the ListViewFragment(this)
if (containerID == "listContainer") {
lcFT.replace(R.id.listContainer, lvf).commit();
lvf.setArguments(args);
}
if (containerID == "someOtherContainer") {
lcFT.replace(R.id.discriptionListContainer, lvf).commit();
lvf.setArguments(args);
}. . .
}

Categories

Resources