In my Listfragment I can load my JSON results from online server (1,2,3,4), but when I press home button and comeback to my App... now my Listview have a duplicate list (1,2,3,4,1,2,3,4), and sometimes this happen when rotate the screen.
I read a lot... and there is a lot of posts but are diferents cases, so here is my case...
My UI... ViewPager > ListFragment
ListFragment: Loader, AsyncTaskLoader, BaseAdapter, JSON, HashMap
Not using/Not my case: Cursors, SQLite, ContentProvider, Activity, ListActivity, String[]
And yes... I'll change httpclient to httpurlconnection :)
And gets better... now when I comeback from another Activity to my ListFragment, and I select an Item... my App Crash!!!, LogCat says: "The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread".
I wanted to try with runOnUiThread(), but apparently doesn't work with ListFragment, but ListActivity... no my case.
Resume: I think this two problems it's beacuse I can't resolve well, the process of onLoadingBackground(), and onLoadingFinish() ...I'm not sure, I can't see it! :S
And... I'm using android:configChanges="orientation|screenSize"
and... i feel bad, it's cheating!!! xD
Just in case... I'm not using Volley, 'cause I want learn more about logic of JAVA/Android, and because if i ever have a problem with Volley... there is fewer people to answer questions :S
I did not want to ask for this but... I read a post a few hours ago, and it said something like: "I'm stuck for over an hour".
WHAAAT??? And I'm stuck in this for over 3 weeks 'cause I'm trying a lot of ways!!! :S (sorry for my bad english... I'm trying, I speak spanish)
public class miNewFragment extends ListFragment implements LoaderManager.LoaderCallbacks<List<Model>> {
static ParseadorJSON_func ParseadorJSON_objeto = new ParseadorJSON_func();
static ArrayList<HashMap<String, String>> arrayListaCompleta;
private static String urlPagina2 = "http://www.domain.com/json/mi_json.php";
private static final String TAG_SUCCESS = "success";
private static final String TAG_CATEGORIAS = "categorias";
private static final String TAG_PID = "idItem";
private static final String TAG_NAME = "name";
static JSONArray jsonCategorias = null;
private ListView miListView;
myBaseAdapter miAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.categorias, container, false);
miListView = (ListView)rootView.findViewById(android.R.id.list);
arrayListaCompleta = new ArrayList<HashMap<String, String>>();
Log.e("onCreateView = ", "miListView > arrayListacompleta > return rootView");
return rootView;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
myBaseAdapter miAdapter = new myBaseAdapter(getActivity());
miListView.setAdapter(miAdapter);
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(0, null, this);
Log.e("onActivityCreated = ", "myBaseAdapter > setAdapter > getLoaderManager");
}
@Override
public Loader<List<Model>> onCreateLoader(int arg0, Bundle arg1) {
Log.e("Loader/onCreateLoader = ", "myAsyncTaskLoader");
return new myAsyncTaskLoader(getActivity());
}
@Override
public void onLoadFinished(Loader<List<Model>> arg0, List<Model> data) {
miAdapter = new myBaseAdapter(getActivity());
miListView.setAdapter(miAdapter);
miAdapter.notifyDataSetChanged();
Log.e("Loader/onLoadFinished = ", "myBaseAdapter > setAdapter > notifyDataSetChanged");
}
@Override
public void onLoaderReset(Loader<List<Model>> arg0) {
Log.e("Loader/onLoaderReset = ", "Nothing");
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
Log.e("onListItemClick = ", "Nothing");
}
public class myBaseAdapter extends BaseAdapter {
private Context mContext;
public myBaseAdapter(Context c) {
mContext = c;
}
public int getCount() {
return arrayListaCompleta.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder = null;
if (convertView == null) {
holder = new Holder();
LayoutInflater ltInflate = (LayoutInflater) mContext.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
convertView = ltInflate.inflate(R.layout.categorias_list_item, null);
holder.h_categTag = (TextView) convertView.findViewById(R.id.categTag);
holder.h_categIdItem = (TextView) convertView.findViewById(R.id.categIdItem);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
}
holder.h_categTag.setText( arrayListaCompleta.get(position).get("name").toString() );
holder.h_categIdItem.setText( arrayListaCompleta.get(position).get("idItem").toString() );
return convertView;
}
class Holder {
TextView h_categTag;
TextView h_categIdItem;
}
}
public static class myAsyncTaskLoader extends AsyncTaskLoader<List<Model>> {
List<Model> mModels;
public myAsyncTaskLoader(Context context) {
super(context);
}
@Override
public List<Model> loadInBackground() {
Log.e("Async/loadInBackground = ", "Creating Array from JSON");
List<NameValuePair> arrayDelServidor = new ArrayList<NameValuePair>();
JSONObject jsonCompleto = ParseadorJSON_objeto.makeHttpRequest(urlPagina2, "GET", arrayDelServidor);
try {
int success = jsonCompleto.getInt(TAG_SUCCESS);
if (success == 1) {
jsonCategorias = jsonCompleto.getJSONArray(TAG_CATEGORIAS);
for (int i = 0; i < jsonCategorias.length(); i++) {
JSONObject jsonFila = jsonCategorias.getJSONObject(i);
String id = jsonFila.getString(TAG_PID);
String name = jsonFila.getString(TAG_NAME);
HashMap<String, String> mapaDatos = new HashMap<String, String>();
mapaDatos.put(TAG_PID, id);
mapaDatos.put(TAG_NAME, name);
arrayListaCompleta.add(mapaDatos);
}
} else {
//nada
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
@Override
public void deliverResult(List<Model> listOfData) {
if (isReset()) {
Log.e("Async/deliverResult = ", "isReset()");
if (listOfData != null) {
onReleaseResources(listOfData);
}
}
List<Model> oldApps = listOfData;
mModels = listOfData;
if (isStarted()) {
Log.e("Async/deliverResult = ", "isStarted()");
super.deliverResult(listOfData);
}
if (oldApps != null) {
Log.e("Async/deliverResult = ", "oldApps");
onReleaseResources(oldApps);
}
}
@Override
protected void onStartLoading() {
if (mModels != null) {
deliverResult(mModels);
Log.e("Async/onStartLoading = ", "mModels != null");
}
if (takeContentChanged()) {
forceLoad();
Log.e("Async/onStartLoading = ", "takeContentChanged()");
}
if (mModels == null) {
forceLoad();
Log.e("Async/onStartLoading = ", "mModels == null");
}
}
@Override
protected void onStopLoading() {
cancelLoad();
Log.e("Async/onStopLoading = ", "cancelLoad()");
}
@Override
public void onCanceled(List<Model> apps) {
super.onCanceled(apps);
onReleaseResources(apps);
Log.e("Async/onCanceled = ", "onReleaseResources(apps)");
}
@Override
protected void onReset() {
super.onReset();
onStopLoading();
if (mModels != null) {
onReleaseResources(mModels);
mModels = null;
Log.e("Async/onReset = ", "onReleaseResources(mModels)");
}
}
protected void onReleaseResources(List<Model> apps) {
Log.e("Async/onReleaseResources = ", "Entró pero no hizo nada");
}
}
}
And if anyone needs these codes...
final class Model {
private String name;
private String id;
public Model(String name, String id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
public static class ParseadorJSON_func {
InputStream is = null;
JSONObject jObj = null;
String json = "";
public ParseadorJSON_func() {
}
public JSONObject makeHttpRequest(String url, String method, List<NameValuePair> arrayDesdeServidor) {
try {
if(method == "POST"){
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new UrlEncodedFormEntity(arrayDesdeServidor));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
}else if(method == "GET"){
DefaultHttpClient httpClient = new DefaultHttpClient();
String paramString = URLEncodedUtils.format(arrayDesdeServidor, "utf-8");
url += "?" + paramString;
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
json = sb.toString();
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
try {
jObj = new JSONObject(json);
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
return jObj;
}
}
.
EDITED: loadInBackground()
When i returned from an Activity to this Listfragment and i selected an item, the App crashed because my loadInBackground changed the content of the adapter and not update the content. Now, with this if else... the App no crash because it check if the adapter is null or not, and then runs loadInBackground or not, but...
I think that the way that i did it... maybe is not the most appropriate way, i have not gotten there but i think that when i'll want update or add more results... this way may not work. Any help/example?
@Override
public List<Model> loadInBackground() {
Log.e("Async/loadInBackground = ", "Creating Array from JSON");
//NEW if else...
if( miAdapter != null ){
adaptadorEstado = "No es Null";
}else{
adaptadorEstado = "Si es Null";
List<NameValuePair> arrayDelServidor = new ArrayList<NameValuePair>();
JSONObject jsonCompleto = ParseadorJSON_objeto.makeHttpRequest(urlPagina2, "GET", arrayDelServidor);
try {
int success = jsonCompleto.getInt(TAG_SUCCESS);
if (success == 1) {
jsonCategorias = jsonCompleto.getJSONArray(TAG_CATEGORIAS);
for (int i = 0; i < jsonCategorias.length(); i++) {
JSONObject jsonFila = jsonCategorias.getJSONObject(i);
String id = jsonFila.getString(TAG_PID);
String name = jsonFila.getString(TAG_NAME);
HashMap<String, String> mapaDatos = new HashMap<String, String>();
mapaDatos.put(TAG_PID, id);
mapaDatos.put(TAG_NAME, name);
arrayListaCompleta.add(mapaDatos);
}
} else {
//nada
}
} catch (JSONException e) {
e.printStackTrace();
}
}//end new if else
Log.e("Async/loadInBackground = ", "Adaptador > "+adaptadorEstado);
return null;
}
.
NEW: onConfigurationChanged()
Since i've been cheating with android:configChanges="orientation|screenSize"
i try with onConfigurationChanged()
but it only work/responds when this configChanges
stay on the Manifest. So i think that this issue has to do with the way how i'm try resolve the loadInBackground(), i'm not sure.
On the other hand... i read a lot about make into onCreate
of my MainActivity, an if to check if savedInstanceState
is null or not, then use something like 'getSupportFragmentManager().beginTransaction().findFragmentByTag()', and when i try... it turns out this thing doesn't work because on my MainActivity i have miPagerAdapter = new funcionPagerAdapter(getSupportFragmentManager());
and i think that maybe in my case... it resolve with another way... but i can't figure how! :S
//In my ListFragment...
@Override
public void onConfigurationChanged(Configuration congfValues) {
super.onConfigurationChanged(congfValues);
Log.e("onConfigurationChanged = ", "Si entró");
if( miAdapter != null ){
Log.e("onConfigurationChanged = ", "Adaptador Lleno");
}else{
miAdapter = new myBaseAdapter(getActivity());
miListView.setAdapter(miAdapter);
Log.e("onConfigurationChanged = ", "Adaptador estaba Vacío (ya no)");
}
}
//In my MainActivity (onCreate)
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.home_viewpager);
Fragment_categorias miFragCategoria;
if (savedInstanceState!= null) {
miFragCategoria = (Fragment_categorias) getSupportFragmentManager().findFragmentByTag("tagCategoria");
} else {
miFragCategoria = new Fragment_categorias();
getSupportFragmentManager().beginTransaction().add(R.id.(i dont know), miFragCategoria, "tagCategoria").commit();
}
//viewpager
miPagerAdapter = new funcionPagerAdapter(getSupportFragmentManager());
miViewPager = (ViewPager) findViewById(R.id.vpContenedor);
miViewPager.setOffscreenPageLimit(5);
miViewPager.setAdapter(miPagerAdapter);
}