I posted a question yesterday regarding a problem with my listview. The state of an image button in the listview wasn't saved (it was reset to default state (unchecked)).
Android listview image button
However much I tried, I was unable to resolve it.
Rigt now though, I've got a problem with singletons:
I want to save a string from a row object when it's image button is "checked" and send it to a singleton ArrayList<String>.
The weird part is that the ArrayList only contains one element at the most and it even "flushes" (removes all objects) without being prompted to.
MainActivity (CONTAINS THE SINGLETON!!!)
package com.example.geostocks;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.json.JSONArray;
import org.json.JSONException;
import com.example.geostocks.R;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.SearchView;
/* MainActivity.
* Made by: Joakim Bajoul Kakaei (881129-0298)
* Description: Creates and sets up the MainActivity programmatically.
* It is mainly associated with activity_main.xml, but uses the
* listview_layout.xml in connection to it.
*
* The idea was to keep the class as "clean" as possible and use
* multiple classes to help making coding and efficiency more easier.
*/
public class MainActivity extends Activity {
public static ArrayList<String> checkedCompanies = new ArrayList<String>();
public Menu m; // Variable to store a menu-item as a public variable.
// This helps with data allocation; instead of declaring the
// searchview and searchmanager in the creation of the
// application,
// it will wait to do it once the user decides to start the
// search.
// an array to store all jsonobjects in.
private JSONArray companies;
// an arraylist to store multiple companyobjects created later.
private List<companiesBuilder> allCompanies = new ArrayList<companiesBuilder>();
/*
* (non-Javadoc)
*
* #see android.app.Activity#onCreate(android.os.Bundle)
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
/*
* executes the AsyncTask (top10). When the task is executed, it
* then gets the JSONArray which is bouncing around.
*/
companies = new top10().execute("DO IT!").get();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ExecutionException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
/*
* The following snippet mainly creates the adapterobject and associates
* it with it's elements, context and layout.
*/
final ListView companyList = (ListView) findViewById(R.id.listView);
final companiesAdapter compAdp = new companiesAdapter(this,
R.layout.listview_layout);
System.out.println("after"); // debugging
/*
* a loop to create companyBuilder-objects from the JSONArray and then
* add those objects to an ArrayList (allCompanies).
*/
for (int i = 0; companies.length() > i; i++) {
System.out.println("companies-looper"); // debugging
System.out.println(companies.length()); // debugging
try {
System.out.println(companies.getJSONObject(i)); // debugging
allCompanies.add(new companiesBuilder(companies
.getJSONObject(i)));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* this loop goes through every company that has been built and adds it
* to the custom listview adapter.
*/
for (companiesBuilder built : allCompanies) {
compAdp.add(built);
}
companyList.setAdapter(compAdp);
}
/*
* (non-Javadoc)
*
* #see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
m = menu; // adds a reference to the variable m (menu).
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return (super.onCreateOptionsMenu(menu)); // returns the super for
// efficiency.
}
/*
* (non-Javadoc)
*
* #see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.search:
openSearch(); // when searchbutton is clicked, it will start the
// opensearch method.
return true;
case R.id.action_settings:
// openSettings();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/*
* Written by: Joakim Bajoul Kakaei Description: Invoked when user presses
* search icon. Opens up the searchview in the menu.
*/
public void openSearch() {
/*
* snippet taken from
* http://developer.android.com/training/search/setup.html with some
* changes to it.
*/
SearchManager sm = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView sv = (SearchView) m.findItem(R.id.search).getActionView();
sv.setSearchableInfo(sm.getSearchableInfo(getComponentName()));
}
/*
* top10 (AsyncTask) Name: Joakim Bajoul Kakaei (881129-0298) Description:
* This class handles the connection between the JSONparser and the
* mainActivity using a different thread. It's mainly used to help with
* memory allocation as well as making sure the main-thread isn't too
* overloaded with too many assignments.
*/
private class top10 extends AsyncTask<String, String, JSONArray> {
#Override
protected JSONArray doInBackground(String... params) {
JSONparser jparser = new JSONparser();
companies = jparser.topCompanies();
System.out.println("background"); // debugging
return companies;
}
#Override
protected void onPostExecute(JSONArray jarr) {
System.out.println("onpost");
}
}
}
SearchActivity (onBackPressed() is called here to display all elements in the singleton)
package com.example.geostocks;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.json.JSONArray;
import org.json.JSONException;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.ListView;
public class SearchActivity extends Activity {
JSONArray companies;
String query;
private List<companiesBuilder> allCompanies = new ArrayList<companiesBuilder>();
companiesAdapter compAdp;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
handleIntent(getIntent());
try {
/*
* executes the AsyncTask (top10). When the task is executed, it
* then gets the JSONArray which is bouncing around.
*/
companies = new searchList().execute("DO IT!").get();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ExecutionException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
/*
* The following snippet mainly creates the adapterobject and associates
* it with it's elements, context and layout.
*/
final ListView companyList = (ListView) findViewById(R.id.listView_search);
compAdp = new companiesAdapter(this, R.layout.listview_layout);
System.out.println("after"); // debugging
/*
* a loop to create companyBuilder-objects from the JSONArray and then
* add those objects to an ArrayList (allCompanies).
*/
for (int i = 0; companies.length() > i; i++) {
System.out.println("companies-looper"); // debugging
System.out.println(companies.length()); // debugging
try {
System.out.println(companies.getJSONObject(i)); // debugging
allCompanies.add(new companiesBuilder(companies
.getJSONObject(i)));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* this loop goes through every company that has been built and adds it
* to the custom listview adapter.
*/
for (companiesBuilder built : allCompanies) {
for (int i = 0; i < MainActivity.checkedCompanies.size(); i++) {
System.out.println("CHECKED" + MainActivity.checkedCompanies.get(i));
if (MainActivity.checkedCompanies.get(i).equals(built.getSymbol())) {
built.setSelect(true);
}
}
compAdp.add(built);
}
companyList.setAdapter(compAdp);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
super.onBackPressed();
System.out.println(MainActivity.checkedCompanies.size());
System.out.println("BACK PRESSED!");
for (int i = 0; i < MainActivity.checkedCompanies.size(); i++) {
System.out.println("CHECKED" + MainActivity.checkedCompanies.get(i));
}
}
return true;
}
#Override
protected void onNewIntent(Intent intent) {
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
query = intent.getStringExtra(SearchManager.QUERY);
System.out.println(query);
// use the query to search your data somehow
}
}
private class searchList extends AsyncTask<String, String, JSONArray> {
#Override
protected JSONArray doInBackground(String... params) {
JSONparser jparser = new JSONparser();
companies = jparser.search(query);
System.out.println("background"); // debugging
return companies;
}
#Override
protected void onPostExecute(JSONArray jarr) {
System.out.println("onpost");
}
}
}
CompaniesAdapter (Where I have a onClickListener to the ImageButton and it tries to
manipulate the singleton):
package com.example.geostocks;
import java.util.ArrayList;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.TextView;
/* companiesAdapter.
* Made by: Joakim Bajoul Kakaei (881129-0298)
* Description: Since the listview we have decided to use has multiple objects on each row,
* the listview's adapter needs to be customized to meet those requirements.
* This class may be revised later on (to add or remove objects from the rowItemObjects).
*/
public class companiesAdapter extends ArrayAdapter<companiesBuilder> implements
OnClickListener {
private final int companiesBuilderResource;
private ArrayList<companiesBuilder> companies;
private static ArrayList<String> checked = new ArrayList<String>();
public companiesAdapter(final Context context,
final int companiesBuilderResource) {
super(context, 0);
this.companiesBuilderResource = companiesBuilderResource;
companies = new ArrayList<companiesBuilder>();
}
public void addChecked(String symbol) {
MainActivity.checkedCompanies.add(symbol);
}
public void removeChecked(String symbol) {
MainActivity.checkedCompanies.remove(symbol);
}
public void add(companiesBuilder row) {
companies.add(row);
notifyDataSetChanged();
}
#Override
public int getCount() {
return companies.size();
}
#Override
public companiesBuilder getItem(int i) {
return companies.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(final int position, final View convertView,
final ViewGroup parent) {
// We need to get the best view (re-used if possible) and then
// retrieve its corresponding rowItem, to optimize lookup efficiency.
final View view = getourView(convertView);
final rowItem rowItem = getrowItem(view);
// final companiesBuilder company = getItem(position);
final companiesBuilder row = companies.get(position);
// Setting up both the titleobject's with their corresponding variables
// (from the row-object).
rowItem.titleView_left.setText(row.getName());
rowItem.titleView_right.setText(row.getPrice());
// Setting up the subtitle's items will be a little bit tougher, since
// it requires
// some manipulating of the xml-data.
rowItem.subTitleView_left.setText(row.getSymbol());
/*
* If-clauses to change the right subtitle's color palette to make it
* easier for the user to distinguish increase and decrease.
*/
if (Double.parseDouble(row.getChange()) < 0) {
rowItem.subTitleView_right
.setTextColor(Color.parseColor("#E51400"));
rowItem.subTitleView_right.setText(row.getPercent() + "%" + " "
+ "( " + row.getChange() + ")");
} else if (Double.parseDouble(row.getChange()) > 0) {
rowItem.subTitleView_right
.setTextColor(Color.parseColor("#339933"));
rowItem.subTitleView_right.setText(row.getPercent() + "%" + " "
+ "( +" + row.getChange() + ")");
} else {
rowItem.subTitleView_right.setText(row.getPercent() + "%" + " "
+ "(" + row.getChange() + ")");
}
// Setting image view is simple enough...
for (int i = 0; checked.size() > i; i++) {
System.out.println("CHECKED" + checked.get(i));
}
rowItem.imageButton.setSelected(row.getSelected());
view.setOnClickListener(new OnClickListener() {
/*
* Add an onClickListener that is associated with view (view being
* every row).
*/
#Override
public void onClick(View v) {
new AlertDialog.Builder(getContext()).setTitle(row.getName())
.show();
}
});
rowItem.imageButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View button) {
if (button.isSelected()) {
button.setSelected(false);
addChecked(row.getSymbol());
} else {
button.setSelected(true);
removeChecked(row.getSymbol());
}
row.setSelect(view.isSelected());
for (int i = 0; MainActivity.checkedCompanies.size() > i; i++) {
System.out.println("CHECKEDLOOP"
+ MainActivity.checkedCompanies.get(i));
}
}
});
return view;
}
private View getourView(final View convertView) {
// The ourView will be recycling / reusing the convertview if
// possible.
// Guess why? Exactly. CUZ WE LOOOOOOOOOOVE HAVING EFFICIENT CODE! <3
View ourView = null;
if (null == convertView) {
final Context context = getContext();
final LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ourView = inflater.inflate(companiesBuilderResource, null);
} else {
ourView = convertView;
}
return ourView;
}
private rowItem getrowItem(final View ourView) {
// Recycling and reusing tags and objects is the name of the game!
final Object tag = ourView.getTag();
rowItem rowItem = null;
/*
* Sets up the listview's rowitems with their corresponding listview
* items (textviews and images).
*/
if (null == tag || !(tag instanceof rowItem)) {
rowItem = new rowItem();
rowItem.titleView_right = (TextView) ourView
.findViewById(R.id.title_right);
rowItem.titleView_left = (TextView) ourView
.findViewById(R.id.title_left);
rowItem.subTitleView_left = (TextView) ourView
.findViewById(R.id.subtitle_left);
rowItem.subTitleView_right = (TextView) ourView
.findViewById(R.id.subtitle_right);
rowItem.imageButton = (ImageButton) ourView
.findViewById(R.id.add_button);
ourView.setTag(rowItem);
} else {
rowItem = (rowItem) tag;
}
return rowItem;
}
/*
* since views are recycled, these references will always be there to be
* reused. Again, it's all about optimization!
*/
private static class rowItem {
public TextView titleView_left;
public TextView titleView_right;
public TextView subTitleView_left;
public TextView subTitleView_right;
public ImageButton imageButton;
}
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
}
}
I've also tried using a global variable in the sense that I used a class with the application=name.
However, I can't use that class in the adapter. This in turn makes it impossible for me to manipulate said global variables, since context is missing.
This is the global class:
package com.example.geostocks;
import java.util.ArrayList;
import android.app.Application;
public class checkedCompanies extends Application{
private ArrayList<companiesBuilder> checked = new ArrayList<companiesBuilder>();
public ArrayList<companiesBuilder> get() {
return checked;
}
public void set(companiesBuilder built) {
checked.add(built);
}
public void remove(companiesBuilder removeIndex){
checked.remove(removeIndex);
}
}
Related
I want to use Identify Task in ARCGIS API for android.I used this example and it works fine but when I try to change the URL to get data from another WMS it shows error
here is my another wms
I get error in folowing line
for (int index = 0; index < results.length; index++) {
result_1 = results[index];
String displayFieldName = result_1.getDisplayFieldName();
Map<String, Object> attr = result_1.getAttributes();
for (String key : attr.keySet()) {
if (key.equalsIgnoreCase(displayFieldName)) {
resultList.add(result_1);
}
}
}
in this class which I have got from example
package com.esri.arcgis.android.samples.identifytask;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import com.esri.android.action.IdentifyResultSpinner;
import com.esri.android.action.IdentifyResultSpinnerAdapter;
import com.esri.android.map.Callout;
import com.esri.android.map.MapView;
import com.esri.android.map.ags.ArcGISTiledMapServiceLayer;
import com.esri.android.map.event.OnSingleTapListener;
import com.esri.core.geometry.Envelope;
import com.esri.core.geometry.Point;
import com.esri.core.tasks.identify.IdentifyParameters;
import com.esri.core.tasks.identify.IdentifyResult;
import com.esri.core.tasks.identify.IdentifyTask;
/**
* This sample allows the user to identify data based on single tap and view the
* results in a callout window which has a spinner in its layout. Also the user
* can select any of the results displayed and view its details. The details are
* the attribute values.
*
* The output value shown in the spinner is the display field.
*
*/
public class Identify extends Activity {
// create ArcGIS objects
MapView mMapView = null;
IdentifyParameters params = null;
// create UI objects
static ProgressDialog dialog;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Retrieve the map and initial extent from XML layout
mMapView = (MapView) findViewById(R.id.map);
// add demographic layer to the map
mMapView.addLayer(new ArcGISTiledMapServiceLayer(this.getResources()
.getString(R.string.identify_task_url_for_avghouseholdsize)));
// set Identify Parameters
params = new IdentifyParameters();
params.setTolerance(20);
params.setDPI(98);
params.setLayers(new int[] { 4 });
params.setLayerMode(IdentifyParameters.ALL_LAYERS);
// Identify on single tap of map
mMapView.setOnSingleTapListener(new OnSingleTapListener() {
private static final long serialVersionUID = 1L;
#Override
public void onSingleTap(final float x, final float y) {
if (!mMapView.isLoaded()) {
return;
}
// Add to Identify Parameters based on tapped location
Point identifyPoint = mMapView.toMapPoint(x, y);
params.setGeometry(identifyPoint);
params.setSpatialReference(mMapView.getSpatialReference());
params.setMapHeight(mMapView.getHeight());
params.setMapWidth(mMapView.getWidth());
params.setReturnGeometry(false);
// add the area of extent to identify parameters
Envelope env = new Envelope();
mMapView.getExtent().queryEnvelope(env);
params.setMapExtent(env);
// execute the identify task off UI thread
MyIdentifyTask mTask = new MyIdentifyTask(identifyPoint);
mTask.execute(params);
}
});
}
private ViewGroup createIdentifyContent(final List<IdentifyResult> results) {
// create a new LinearLayout in application context
LinearLayout layout = new LinearLayout(this);
// view height and widthwrap content
layout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
// default orientation
layout.setOrientation(LinearLayout.HORIZONTAL);
// Spinner to hold the results of an identify operation
IdentifyResultSpinner spinner = new IdentifyResultSpinner(this, results);
// make view clickable
spinner.setClickable(false);
spinner.canScrollHorizontally(BIND_ADJUST_WITH_ACTIVITY);
// MyIdentifyAdapter creates a bridge between spinner and it's data
MyIdentifyAdapter adapter = new MyIdentifyAdapter(this, results);
spinner.setAdapter(adapter);
spinner.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT));
layout.addView(spinner);
return layout;
}
/**
* This class allows the user to customize the string shown in the callout.
* By default its the display field name.
*
* A spinner adapter defines two different views; one that shows the data in
* the spinner itself and one that shows the data in the drop down list when
* spinner is pressed.
*
*/
public class MyIdentifyAdapter extends IdentifyResultSpinnerAdapter {
String m_show = null;
List<IdentifyResult> resultList;
int currentDataViewed = -1;
Context m_context;
public MyIdentifyAdapter(Context context, List<IdentifyResult> results) {
super(context, results);
this.resultList = results;
this.m_context = context;
}
// Get a TextView that displays identify results in the callout.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
String LSP = System.getProperty("line.separator");
StringBuilder outputVal = new StringBuilder();
// Resource Object to access the Resource fields
Resources res = getResources();
// Get Name attribute from identify results
IdentifyResult curResult = this.resultList.get(position);
if (curResult.getAttributes().containsKey(
res.getString(R.string.NAME))) {
outputVal.append("Place: "
+ curResult.getAttributes()
.get(res.getString(R.string.NAME)).toString());
outputVal.append(LSP);
}
if (curResult.getAttributes().containsKey(
res.getString(R.string.ID))) {
outputVal.append("State ID: "
+ curResult.getAttributes()
.get(res.getString(R.string.ID)).toString());
outputVal.append(LSP);
}
if (curResult.getAttributes().containsKey(
res.getString(R.string.ST_ABBREV))) {
outputVal.append("Abbreviation: "
+ curResult.getAttributes()
.get(res.getString(R.string.ST_ABBREV))
.toString());
outputVal.append(LSP);
}
if (curResult.getAttributes().containsKey(
res.getString(R.string.TOTPOP_CY))) {
outputVal.append("Population: "
+ curResult.getAttributes()
.get(res.getString(R.string.TOTPOP_CY))
.toString());
outputVal.append(LSP);
}
if (curResult.getAttributes().containsKey(
res.getString(R.string.LANDAREA))) {
outputVal.append("Area: "
+ curResult.getAttributes()
.get(res.getString(R.string.LANDAREA))
.toString());
outputVal.append(LSP);
}
// Create a TextView to write identify results
TextView txtView;
txtView = new TextView(this.m_context);
txtView.setText(outputVal);
txtView.setTextColor(Color.BLACK);
txtView.setLayoutParams(new ListView.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
txtView.setGravity(Gravity.CENTER_VERTICAL);
return txtView;
}
}
#Override
protected void onPause() {
super.onPause();
mMapView.pause();
}
#Override
protected void onResume() {
super.onResume();
mMapView.unpause();
}
private class MyIdentifyTask extends
AsyncTask<IdentifyParameters, Void, IdentifyResult[]> {
IdentifyTask task = new IdentifyTask(Identify.this.getResources()
.getString(R.string.identify_task_url_for_avghouseholdsize));
IdentifyResult[] M_Result;
Point mAnchor;
MyIdentifyTask(Point anchorPoint) {
mAnchor = anchorPoint;
}
#Override
protected void onPreExecute() {
// create dialog while working off UI thread
dialog = ProgressDialog.show(Identify.this, "Identify Task",
"Identify query ...");
}
protected IdentifyResult[] doInBackground(IdentifyParameters... params) {
// check that you have the identify parameters
if (params != null && params.length > 0) {
IdentifyParameters mParams = params[0];
try {
// Run IdentifyTask with Identify Parameters
M_Result = task.execute(mParams);
} catch (Exception e) {
e.printStackTrace();
}
}
return M_Result;
}
#Override
protected void onPostExecute(IdentifyResult[] results) {
// dismiss dialog
if (dialog.isShowing()) {
dialog.dismiss();
}
ArrayList<IdentifyResult> resultList = new ArrayList<IdentifyResult>();
IdentifyResult result_1;
for (int index = 0; index < results.length; index++) {
result_1 = results[index];
String displayFieldName = result_1.getDisplayFieldName();
Map<String, Object> attr = result_1.getAttributes();
for (String key : attr.keySet()) {
if (key.equalsIgnoreCase(displayFieldName)) {
resultList.add(result_1);
}
}
}
Callout callout = mMapView.getCallout();
callout.setContent(createIdentifyContent(resultList));
callout.show(mAnchor);
}
}
}
and this is error
06-11 19:01:21.384 18989-18989/com.tehranuni.hazard.hazard E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.tehranuni.hazard.hazard, PID: 18989
java.lang.NullPointerException: Attempt to get length of null array
at com.tehranuni.hazard.hazard.gatter_geo_data$MyIdentifyTask.onPostExecute(gatter_geo_data.java:714)
at com.tehranuni.hazard.hazard.gatter_geo_data$MyIdentifyTask.onPostExecute(gatter_geo_data.java:661)
at android.os.AsyncTask.finish(AsyncTask.java:632)
at android.os.AsyncTask.access$600(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:211)
at android.app.ActivityThread.main(ActivityThread.java:5321)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1016)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:811)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:117)
As the error say results is null and I think it is because it does not get fields from WMS layer.What so you think about this error?Is there any way to fix it?
Thank you so much for your help
IdentifyTask works only with an ArcGIS Server map service, not a WMS.
First of all I'd like to thank all of you for helping me on numerous occasions before. SO have alwasy been my go-to place when faced with problems with programming.
This time however, I've been unable to find a solution to my problem...
I'm currently developing an android app that uses two activities (one main activity and a search activity).
Both of which hold a listview - the main activity has an already populated and fully functional listview and, the search activity has a populated one which seems to lack functionallity.
The listview is created in a custom adapter and contains an image button (toggling with a selector) and four textviews.
My problem is that when I toggle the image button in my search activity and then press back to get back to the main activity and finally go back to the search results, the image button is "unchecked".
Since the image button is a CRUCIAL point in both the design and the following functionallity, I'd really appriciate any kind of help.
package com.example.geostocks;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.json.JSONArray;
import org.json.JSONException;
import com.example.geostocks.R;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.SearchView;
/* MainActivity.
* Made by: Joakim Bajoul Kakaei (881129-0298)
* Description: Creates and sets up the MainActivity programmatically.
* It is mainly associated with activity_main.xml, but uses the
* listview_layout.xml in connection to it.
*
* The idea was to keep the class as "clean" as possible and use
* multiple classes to help making coding and efficiency more easier.
*/
public class MainActivity extends Activity {
public Menu m; // Variable to store a menu-item as a public variable.
// This helps with data allocation; instead of declaring the
// searchview and searchmanager in the creation of the
// application,
// it will wait to do it once the user decides to start the
// search.
// an array to store all jsonobjects in.
private JSONArray companies;
// an arraylist to store multiple companyobjects created later.
private List<companiesBuilder> allCompanies = new ArrayList<companiesBuilder>();
/*
* (non-Javadoc)
*
* #see android.app.Activity#onCreate(android.os.Bundle)
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
/*
* executes the AsyncTask (top10). When the task is executed, it
* then gets the JSONArray which is bouncing around.
*/
companies = new top10().execute("DO IT!").get();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ExecutionException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
/*
* The following snippet mainly creates the adapterobject and associates
* it with it's elements, context and layout.
*/
final ListView companyList = (ListView) findViewById(R.id.listView);
final companiesAdapter compAdp = new companiesAdapter(this,
R.layout.listview_layout);
System.out.println("after"); // debugging
/*
* a loop to create companyBuilder-objects from the JSONArray and then
* add those objects to an ArrayList (allCompanies).
*/
for (int i = 0; companies.length() > i; i++) {
System.out.println("companies-looper"); // debugging
System.out.println(companies.length()); // debugging
try {
System.out.println(companies.getJSONObject(i)); // debugging
allCompanies.add(new companiesBuilder(companies
.getJSONObject(i)));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* this loop goes through every company that has been built and adds it
* to the custom listview adapter.
*/
for (companiesBuilder built : allCompanies) {
compAdp.add(built);
}
companyList.setAdapter(compAdp);
}
/*
* (non-Javadoc)
*
* #see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
m = menu; // adds a reference to the variable m (menu).
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return (super.onCreateOptionsMenu(menu)); // returns the super for
// efficiency.
}
/*
* (non-Javadoc)
*
* #see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.search:
openSearch(); // when searchbutton is clicked, it will start the
// opensearch method.
return true;
case R.id.action_settings:
// openSettings();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/*
* Written by: Joakim Bajoul Kakaei Description: Invoked when user presses
* search icon. Opens up the searchview in the menu.
*/
public void openSearch() {
/*
* snippet taken from
* http://developer.android.com/training/search/setup.html with some
* changes to it.
*/
SearchManager sm = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView sv = (SearchView) m.findItem(R.id.search).getActionView();
sv.setSearchableInfo(sm.getSearchableInfo(getComponentName()));
}
/*
* top10 (AsyncTask) Name: Joakim Bajoul Kakaei (881129-0298) Description:
* This class handles the connection between the JSONparser and the
* mainActivity using a different thread. It's mainly used to help with
* memory allocation as well as making sure the main-thread isn't too
* overloaded with too many assignments.
*/
private class top10 extends AsyncTask<String, String, JSONArray> {
#Override
protected JSONArray doInBackground(String... params) {
JSONparser jparser = new JSONparser();
companies = jparser.topCompanies();
System.out.println("background"); // debugging
return companies;
}
#Override
protected void onPostExecute(JSONArray jarr) {
System.out.println("onpost");
}
}
}
package com.example.geostocks;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.json.JSONArray;
import org.json.JSONException;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.ListView;
public class SearchActivity extends Activity {
JSONArray companies;
String query;
private List<companiesBuilder> allCompanies = new ArrayList<companiesBuilder>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
handleIntent(getIntent());
try {
/*
* executes the AsyncTask (top10). When the task is executed, it
* then gets the JSONArray which is bouncing around.
*/
companies = new searchList().execute("DO IT!").get();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ExecutionException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
/*
* The following snippet mainly creates the adapterobject and associates
* it with it's elements, context and layout.
*/
final ListView companyList = (ListView) findViewById(R.id.listView_search);
final companiesAdapter compAdp = new companiesAdapter(this,
R.layout.listview_layout);
System.out.println("after"); // debugging
/*
* a loop to create companyBuilder-objects from the JSONArray and then
* add those objects to an ArrayList (allCompanies).
*/
for (int i = 0; companies.length() > i; i++) {
System.out.println("companies-looper"); // debugging
System.out.println(companies.length()); // debugging
try {
System.out.println(companies.getJSONObject(i)); // debugging
allCompanies.add(new companiesBuilder(companies
.getJSONObject(i)));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* this loop goes through every company that has been built and adds it
* to the custom listview adapter.
*/
for (companiesBuilder built : allCompanies) {
compAdp.add(built);
}
companyList.setAdapter(compAdp);
}
#Override
public void onBackPressed() {
super.onBackPressed();
}
#Override
protected void onNewIntent(Intent intent) {
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
query = intent.getStringExtra(SearchManager.QUERY);
System.out.println(query);
// use the query to search your data somehow
}
}
private class searchList extends AsyncTask<String, String, JSONArray> {
#Override
protected JSONArray doInBackground(String... params) {
JSONparser jparser = new JSONparser();
companies = jparser.search(query);
System.out.println("background"); // debugging
return companies;
}
#Override
protected void onPostExecute(JSONArray jarr) {
System.out.println("onpost");
}
}
}
Custom listviewAdapter:
package com.example.geostocks;
import java.util.ArrayList;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.TextView;
/* companiesAdapter.
* Made by: Joakim Bajoul Kakaei (881129-0298)
* Description: Since the listview we have decided to use has multiple objects on each row,
* the listview's adapter needs to be customized to meet those requirements.
* This class may be revised later on (to add or remove objects from the rowItemObjects).
*/
public class companiesAdapter extends ArrayAdapter<companiesBuilder> implements
OnClickListener {
private final int companiesBuilderResource;
private ArrayList<companiesBuilder> companies;
public companiesAdapter(final Context context,
final int companiesBuilderResource) {
super(context, 0);
this.companiesBuilderResource = companiesBuilderResource;
companies = new ArrayList<companiesBuilder>();
}
public void add(companiesBuilder row) {
companies.add(row);
notifyDataSetChanged();
}
#Override
public int getCount() {
return companies.size();
}
#Override
public companiesBuilder getItem(int i) {
return companies.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(final int position, final View convertView,
final ViewGroup parent) {
// We need to get the best view (re-used if possible) and then
// retrieve its corresponding rowItem, to optimize lookup efficiency.
final View view = getourView(convertView);
final rowItem rowItem = getrowItem(view);
// final companiesBuilder company = getItem(position);
final companiesBuilder row = companies.get(position);
// Setting up both the titleobject's with their corresponding variables
// (from the row-object).
rowItem.titleView_left.setText(row.getName());
rowItem.titleView_right.setText(row.getPrice());
// Setting up the subtitle's items will be a little bit tougher, since
// it requires
// some manipulating of the xml-data.
rowItem.subTitleView_left.setText(row.getSymbol());
/*
* If-clauses to change the right subtitle's color palette to make it
* easier for the user to distinguish increase and decrease.
*/
if (Double.parseDouble(row.getChange()) < 0) {
rowItem.subTitleView_right
.setTextColor(Color.parseColor("#E51400"));
rowItem.subTitleView_right.setText(row.getPercent() + "%" + " "
+ "( " + row.getChange() + ")");
} else if (Double.parseDouble(row.getChange()) > 0) {
rowItem.subTitleView_right
.setTextColor(Color.parseColor("#339933"));
rowItem.subTitleView_right.setText(row.getPercent() + "%" + " "
+ "( +" + row.getChange() + ")");
} else {
rowItem.subTitleView_right.setText(row.getPercent() + "%" + " "
+ "(" + row.getChange() + ")");
}
// Setting image view is simple enough...
rowItem.imageButton.setSelected(row.getSelected());
view.setOnClickListener(new OnClickListener() {
/*
* Add an onClickListener that is associated with view (view being
* every row).
*/
#Override
public void onClick(View v) {
new AlertDialog.Builder(getContext()).setTitle(row.getName())
.show();
}
});
rowItem.imageButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View button) {
if (button.isSelected()) {
button.setSelected(false);
} else {
button.setSelected(true);
}
row.setSelect(view.isSelected());
}
});
return view;
}
private View getourView(final View convertView) {
// The ourView will be recycling / reusing the convertview if
// possible.
// Guess why? Exactly. CUZ WE LOOOOOOOOOOVE HAVING EFFICIENT CODE! <3
View ourView = null;
if (null == convertView) {
final Context context = getContext();
final LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ourView = inflater.inflate(companiesBuilderResource, null);
} else {
ourView = convertView;
}
return ourView;
}
private rowItem getrowItem(final View ourView) {
// Recycling and reusing tags and objects is the name of the game!
final Object tag = ourView.getTag();
rowItem rowItem = null;
/*
* Sets up the listview's rowitems with their corresponding listview
* items (textviews and images).
*/
if (null == tag || !(tag instanceof rowItem)) {
rowItem = new rowItem();
rowItem.titleView_right = (TextView) ourView
.findViewById(R.id.title_right);
rowItem.titleView_left = (TextView) ourView
.findViewById(R.id.title_left);
rowItem.subTitleView_left = (TextView) ourView
.findViewById(R.id.subtitle_left);
rowItem.subTitleView_right = (TextView) ourView
.findViewById(R.id.subtitle_right);
rowItem.imageButton = (ImageButton) ourView
.findViewById(R.id.add_button);
ourView.setTag(rowItem);
} else {
rowItem = (rowItem) tag;
}
return rowItem;
}
/*
* since views are recycled, these references will always be there to be
* reused. Again, it's all about optimization!
*/
private static class rowItem {
public TextView titleView_left;
public TextView titleView_right;
public TextView subTitleView_left;
public TextView subTitleView_right;
public ImageButton imageButton;
}
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
}
}
Selector for imagebutton
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/ic_added_button" android:state_selected="true"/>
<item android:drawable="#drawable/ic_add_button" android:state_selected="false"/>
</selector>
Create model for companies (ex. Company class).
In Company class add property isSelected.
Fill array of companies from your JSONArray. Pass this array to ListView adapter.
In rowItem.imageButton.setOnClickListener update rowItem state (selected or not) in source array (array of companies, which was created from JSONArray).
Note: if you will save list row state, you should save this state in source array of your list adapter.
In MainActivity:
CompanyListAdapter adapter = new CompanyListAdapter(activity);
ArrayList<Company> companies = getCompaniesFromJsonArray();
for(Company company : companies){
adapter.add(company);
}
listView.setAdapter(adapter);
Company.java
package com.donvigo.TestCustomActionBar;
public class Company {
private String name;
private boolean isSelected;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isSelected() {
return isSelected;
}
public void setSelected(boolean isSelected) {
this.isSelected = isSelected;
}
}
CompanyListAdapter.java
package com.donvigo.TestCustomActionBar;
import android.app.Activity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
public class CompanyListAdapter extends BaseAdapter {
private Activity activity;
private ArrayList<Company> companies;
public CompanyListAdapter(Activity activity){
this.activity = activity;
companies = new ArrayList<Company>();
}
public void add(Company company){
companies.add(company);
notifyDataSetChanged();
}
#Override
public int getCount() {
return companies.size();
}
#Override
public Object getItem(int i) {
return companies.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
ViewHolder holder;
if(convertView == null){
convertView = activity.getLayoutInflater().inflate(R.layout.list_row_layout, null);
holder = new ViewHolder();
holder.textViewName = (ImageView) convertView.findViewById(R.id.textViewName);
holder.rowImage = (ImageView) convertView.findViewById(R.id.rowImage);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
final Company row = companies.get(position);
// refresh state of your row image
holder.rowImage.setSelected(row.isSelected());
holder.rowImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (view.isSelected()) {
view.setSelected(false);
} else {
view.setSelected(true);
}
row.setSelected(view.isSelected());
}
});
return convertView;
}
private class ViewHolder{
public TextView textViewName;
public ImageView rowImage;
}
}
This is main idea. Also, if you will save row states in ListView permanently (not just 1 time when you download and show data from internet) - you have to save you companies data in database, or in another data storage (ex.: in text file) and next time when you open activity - restore previously saved companies list.
Seen your code, no where you are saving checked state of button. Point is when you navigate from MainActivity to SearchActivity your listview with custom adapter is populated and displayed, there you set some button, now once you navigate back to main activity from there you SearchAvtivity is destroyed and is completely redrawn when you navigate back. Hence you see every then fresh again.
If you want to retain checked state of button, you should save their latest state in preference and load it from there or you can keep global data variable for holding checked states of buttons so to retain it during entire life cycle of your applications.
Read about Activity life cycle and stack, when they are destroyed and created, this will throw you more insight over why this is happening.
hope it help.
I've got this problem where when I change the orientation of my device, for some reason the on-screen representation of the ListView associated with my ListFragment is retained, and a new ListView is inflated beneath it. To give you some context, I am creating a very simple app whose purpose is to test some DAO objects I created. I would have preferred to post some screenshots depicting the behavior my app is experiencing, but unfortunately, my reputation is too low at the moment.
The best I could describe it would be that when I change the orientation of the device from portrait to landscape (and vice versa), it inflates a whole new ListView without deflating the previous one. I have been looking into this for a couple of days now, and quite honestly, I am stumped. Any help you guys could offer would be greatly appreciated.
Here is the code for the ListFragment:
package edu.uark.csce.mobile.healthyshopper;
import android.app.ListFragment;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Loader;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
/**
* A fragment representing a list of Items.
* <p />
* <p />
* Activities containing this fragment MUST implement the {#link Callbacks}
* interface.
*/
public class ViewFragment extends ListFragment implements
LoaderCallbacks<Cursor> {
// Class Fields:
private static final String TAG = "healthyshopper.ViewFragment";
private static final int MAIN_DB_LOADER = 0;
// In the final application, any query to the main database needs to return
// at least these fields:
private final String[] NECESSARY_COLUMNS = { DAOContentProvider.FOOD_DES,
DAOContentProvider.FOOD_CALORIES, DAOContentProvider.FOOD_FAT,
DAOContentProvider.FOOD_CARBS, DAOContentProvider.FOOD_PROTEIN };
private final String FROM[] = {DAOContentProvider.FOOD_GROUP, DAOContentProvider.FOOD_DES,
DAOContentProvider.FOOD_MANUFAC, DAOContentProvider.FOOD_PROTEIN,
DAOContentProvider.FOOD_FAT, DAOContentProvider.FOOD_CARBS,
DAOContentProvider.FOOD_CALORIES, DAOContentProvider.FOOD_SERV_SIZE};
private final int TO[] = {R.id.fd_group, R.id.shrt_desc,
R.id.manufac, R.id.protein,
R.id.fat, R.id.carb,
R.id.cal, R.id.amt};
private int threadMode;
private int queryType;
private int foodGroupId;
private CursorLoader loader;
private SimpleCursorAdapter listAdapter;
// Preference Option Constants:
private int UI_THREAD = 0;
private int BRANCHED_THREAD = 1;
private int ALL_ROWS = 0;
private int SPECIFIC_FD_GROUP = 1;
private int LIMITED_ROWS = 2;
private OnFragmentInteractionListener mListener;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public ViewFragment() {
}
/***************************************
* Life cycle callbacks:
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e(TAG, "in onCreate()");
setRetainInstance(true);
}
#Override
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
if(savedInstanceState == null){
listAdapter = new SimpleCursorAdapter(getActivity(), R.layout.list_node, null, FROM, TO, 0);
setListAdapter(listAdapter);
}
}
#Override
public void onStart(){
super.onStart();
}
#Override
public void onResume(){
super.onResume();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()
.getApplicationContext());
Log.d(TAG, preferences.getString("THREADING_MODE", "BLANK"));
//Load testing preferences:
threadMode = Integer.valueOf(preferences.getString("THREADING_MODE","0"));
queryType = Integer.valueOf(preferences.getString("QUERY_TYPE", "0"));
foodGroupId = Integer.valueOf(preferences.getString("FOOD_GROUP", "0")); // Default
if (threadMode == BRANCHED_THREAD) {
loader = (CursorLoader) getLoaderManager().initLoader(
MAIN_DB_LOADER, null, this);
} else {
String[] projection = null;
String selection = null;
if (queryType == SPECIFIC_FD_GROUP) {
Log.d(TAG, "Query Type: " + (getResources().getStringArray(R.array.query_type_select))[queryType]);
selection = DAOContentProvider.FOOD_GROUP + " = " + foodGroupId;
} else if (queryType == LIMITED_ROWS) {
projection = NECESSARY_COLUMNS;
}
/*This is for testing only. Ordinarily, you should NEVER perform Db operations on the UI thread.*/
listAdapter.swapCursor(getActivity().getContentResolver().query(
DAOContentProvider.CONTENT_URI, projection, selection, null, null));
}
}
#Override
public void onPause(){
super.onPause();
}
#Override
public void onStop(){
super.onStop();
}
#Override
public void onDestroyView(){
super.onDestroyView();
Log.e(TAG, "in onDestroyView()");
setListAdapter(null);
listAdapter.swapCursor(null);
listAdapter = null;
}
#Override
public void onDestroy(){
super.onDestroy();
}
#Override
public void onDetach(){
super.onDetach();
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
if (null != mListener) {
}
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated to
* the activity and potentially other fragments contained in that activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
public void onFragmentInteraction(String id);
}
/**
* LoaderManager Callbacks;
*/
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) {
case MAIN_DB_LOADER:
String[] projection = null;
String selection = null;
if (queryType == SPECIFIC_FD_GROUP) {
Log.d(TAG,
"Query Type: "
+ (getResources()
.getStringArray(R.array.query_type_select))[queryType]);
selection = DAOContentProvider.FOOD_GROUP + " = " + foodGroupId;
} else if (queryType == LIMITED_ROWS) {
projection = NECESSARY_COLUMNS;
}
return new CursorLoader(getActivity(),
DAOContentProvider.CONTENT_URI, projection, selection,
null, null);
default:
return null;
}
}
#Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor arg1) {
listAdapter.swapCursor(arg1);
listAdapter.notifyDataSetChanged();
}
#Override
public void onLoaderReset(Loader<Cursor> arg0) {
listAdapter.swapCursor(null);
listAdapter.notifyDataSetChanged();
}
}
And here is the code for its associated Activity:
package edu.uark.csce.mobile.healthyshopper;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class TestingActivity extends Activity implements ViewFragment.OnFragmentInteractionListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_testing);
ViewFragment list = new ViewFragment();
getFragmentManager().beginTransaction().add(R.id.test_layout, list).commit();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.testing, menu);
return true;
}
#Override
public void onFragmentInteraction(String id) {
// TODO Auto-generated method stub
}
}
You're using setRetainInstance(true); in your fragment. This makes the fragment to be retained and reused when the activity is re-created.
You can read more detailed description in this question: Further understanding setRetainInstance(true)
When i am trying to call the method "refresh" of main activity from another Api class,the method was called and also it shows some fatal errors.And it didn't change the adapter values.Can anyone give any idea to clear that.?
package com.example.hotspot;
import com.example.hotspot.HotspotApi;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.ListView;
import android.widget.TextView;
public class HotSpot extends Activity {
TextView textview;
ListView listview;
HotspotAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.hot_spot);
textview = (TextView) findViewById(R.id.textView1);
listview = (ListView) findViewById(R.id.listView1);
adapter = new HotspotAdapter(this);
listview.setAdapter(adapter);
new HotspotApi(adapter).execute();
}
public void refresh() {
System.out.println("refresh() is called");
adapter.notifyDataSetChanged();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.hot_spot, menu);
return true;
}
}
hotspot.java
package com.example.hotspot;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.example.hotspot.HotspotModel;
import com.example.hotspot.HotspotAdapter;
import android.os.AsyncTask;
public class HotspotApi extends AsyncTask<Void, Integer, Void> implements
Icommon {
public Boolean IsServerErr = false;
private JSONArray response_array;
String url = "some url";
HotspotAdapter adapter;
HotSpot hot;
public HotspotApi(HotspotAdapter adapter) {
this.adapter = adapter;
}
#Override
protected Void doInBackground(Void... arg0) {
// TODO Auto-generated method stub
getresult();
return null;
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
hot=new HotSpot();
hot.refresh();
super.onPostExecute(result);
}
void getresult() {
InternetManager manager = new InternetManager(url);
String category_jsonresponse = manager.URLRequest();
if (!manager.IsServerConn) {
IsServerErr = true;
}
if (category_jsonresponse != null) {
System.out.println("Hotspot_jsonresponse" + category_jsonresponse);
try {
response_array = new JSONArray(category_jsonresponse);
for (int i = 1; i < response_array.length(); i++) {
JSONObject image_object = response_array.getJSONObject(i);
HotspotModel h = new HotspotModel();
h.setId(image_object.getString("id") == null ? ""
: image_object.getString("id"));
h.setContent(image_object.getString("content") == null ? ""
: image_object.getString("content"));
h.setImg(image_object.getString("img") == null ? ""
: image_object.getString("img"));
h.setName(image_object.getString("name") == null ? ""
: image_object.getString("name"));
arraylist.add(h);
}
System.out.println("HotspotModelsize() is " + arraylist.size());
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
HotspotAdapter.java
package com.example.hotspot;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class HotspotAdapter extends BaseAdapter implements Icommon{
private TextView textview;
private View view;
ImageView imageview;
private LayoutInflater inflater;
public HotspotAdapter(Context context ){
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return arraylist.size();
}
#Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return arraylist.get(arg0);
}
#Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
#Override
public View getView(int arg0, View arg1, ViewGroup arg2) {
if (arg1 == null) {
view = inflater.inflate(R.layout.custom_layout, null);
} else {
view = arg1;
}
textview = (TextView) view.findViewById(R.id.txt_content);
textview.setText(arraylist.get(arg0).getName());
return view;
}
}
In your HotSpotApi class you are creating a new HotSpot activity, this seems wrong. I guess that you are getting json data from internet and load it into a listview.
Solution:
In HotspotApi change following instead of calling activity method:
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
adapter.notfiyDatasetChanged();
}
Hope this will help you.
hot=new HotSpot(); ?? you cannot use like that! HotSpot is an activity, should be called by Framework for example, activitymanager. Or use startActivity() to show a activity.
Refresh method (adapter.notifyDataSetChanged();) will result in refresh of UI. However, hot = new HotSpot() will not call onCreated() method,which means the UI is not created. So it definitely results in the fatal error.
I'd never see anyone call an Activity with new operator.
You should reference the common process about how use a activity and adapter.
I am setting up to use the Loader pattern and had issues using the cursor approach, so I have refactored my code because my tables do not use _id as the primary key because of the use of association tables and I setup my code to use the same basic structure as the LoaderCustomSupport.java example from the android developer site. All of the code works without errors and I can see that I have the proper data back and ready for the ListFragment to display but after the onLoadFinished call back completes the setData on the adapter the getView is never called. My getView looks like this:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
PhoneNumberListHolder holder;
if (row == null) {
row = mInflater.inflate(R.layout.phonenumber_row, parent, false);
holder=new PhoneNumberListHolder(row);
row.setTag(holder);
} else {
holder = (PhoneNumberListHolder)row.getTag();
}
holder.populateForm(this.phoneNumbers.get(position));
return row;
}
I am trying to use the holder pattern, but I am thinking that maybe it is part of my issue. Any ideas where I might be going wrong?
Here is the loader code (Like I said I followed the Google example for my first run changing what I thought I would need)
The Abstract Loader for my Class
/*
* Custom version of CommonsWare, LLC, AbstractCursorLoader
*
*/
package myApp.service.data;
import java.util.List;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
abstract public class AbstractPhoneNumberLoader extends AsyncTaskLoader<List<PhoneNumber>> {
abstract protected List<PhoneNumber> buildPhoneNumber();
List<PhoneNumber> lastPhoneNumber=null;
public AbstractPhoneNumberLoader(Context context) {
super(context);
}
#Override
public List<PhoneNumber> loadInBackground() {
List<PhoneNumber> data=buildPhoneNumber();
if (data!=null) {
// Make sure we fill the person
data.size();
}
return (data);
}
/**
* This will run on the UI thread, routing the results from the
* background to the consumer of the Person object
* (e.g., a PhoneNumberListAdapter).
*/
#Override
public void deliverResult(List<PhoneNumber> data) {
if (isReset()) {
// An async query attempted a call while the loader is stopped
if (data!=null) {
data.clear();
data=null;
//not sure the best option here since we cannot close the List object
}
return;
}
List<PhoneNumber> oldPhoneNumber=lastPhoneNumber;
lastPhoneNumber=data;
if (isStarted()) {
super.deliverResult(data);
}
if (oldPhoneNumber!=null && oldPhoneNumber!=data && oldPhoneNumber.isEmpty()) {
oldPhoneNumber.clear();
oldPhoneNumber=null;
}
}
/**
* Start an asynchronous load of the requested data.
* When the result is ready the callbacks will be called
* on the UI thread. If a previous load has completed
* and is still valid the result may be passed back to the
* caller immediately.
*
* Note: Must be called from the UI thread
*/
#Override
protected void onStartLoading() {
if (lastPhoneNumber!=null) {
deliverResult(lastPhoneNumber);
}
if (takeContentChanged() || lastPhoneNumber==null) {
forceLoad();
}
}
/**
* Must be called from the UI thread, triggered by
* a call to stopLoading().
*/
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task
cancelLoad();
}
/**
* Must be called from the UI thread, triggered by a
* call to cancel(). Here, we make sure our Person
* is null, if it still exists and is not already empty.
*/
#Override
public void onCanceled(List<PhoneNumber> data) {
if (data!=null && !data.isEmpty()) {
data.clear();
}
}
/**
* Must be called from the UI thread, triggered by a
* call to reset(). Here, we make sure our Person
* is empty, if it still exists and is not already empty.
*/
#Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (lastPhoneNumber!=null && !lastPhoneNumber.isEmpty()) {
lastPhoneNumber.clear();
}
lastPhoneNumber=null;
}
}
The Data Loader
/*
* Custom version of CommonsWare, LLC, SQLiteCursorLoader
*
*/
package myApp.service.data;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.List;
import myApp.service.data.ActorDbAdapter;
import android.content.Context;
public class PhoneNumberDataLoader extends AbstractPhoneNumberLoader {
ActorDbAdapter db=null;
protected final String actorId;
protected final String _PHONENUMBERID = "PhoneNumberId";
protected SimpleDateFormat dateFormat = new SimpleDateFormat("dd/mm/yyyy");
/**
* Constructor - takes the context to allow the database to be
* opened/created
*
* #param ctx the Context within which to work
*/
public PhoneNumberDataLoader(Context ctx, String actorId) {
super(ctx);
this.actorId = actorId;
getHelper(ctx);
}
// Get a database connection
private void getHelper(Context ctx) {
if (db==null) {
db=new ActorDbAdapter(ctx);
}
db.open();
}
// Loader Methods
/**
* Runs on a worker thread and performs the actual
* database query to retrieve the PhoneNumber List.
*/
#Override
protected List<PhoneNumber> buildPhoneNumber() {
return(db.readPhoneById(actorId));
}
/**
* Writes a semi-user-readable roster of contents to
* supplied output.
*/
#Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
super.dump(prefix, fd, writer, args);
writer.print(prefix);
writer.print("actorId=");
writer.println(actorId);
}
public void insert(PhoneNumber data, String actorId) {
new InsertTask(this).execute(db, data, actorId);
}
// Saved for Later, get Reads and Writes working first
// public void update(PhoneNumber data, String actorId, String whereClause, String[] whereArgs) {
// new UpdateTask(this).execute(db, data, actorId, whereClause, whereArgs);
// }
//
// public void delete(String actorId, String phoneNumberId, String whereClause, String[] whereArgs) {
// new DeleteTask(this).execute(db, actorId, phoneNumberId, whereClause, whereArgs);
// }
public void execSQL(String actorId) {
new ExecSQLTask(this).execute(db, actorId);
}
private class InsertTask extends ContentChangingTask<Object, Void, Void> {
InsertTask(PhoneNumberDataLoader loader) {
super(loader);
}
#Override
protected Void doInBackground(Object... params) {
ActorDbAdapter db=(ActorDbAdapter)params[0];
PhoneNumber data=(PhoneNumber)params[1];
int actorId=Integer.parseInt((String)params[2]);
db.createPhoneNumber(data, actorId);
return(null);
}
}
// Saved for Later, get Reads and Writes working first
// private class UpdateTask extends
// ContentChangingTask<Object, Void, Void> {
// UpdateTask(PhoneNumberDataLoader loader) {
// super(loader);
// }
//
// #Override
// protected Void doInBackground(Object... params) {
// ActorDbAdapter db=(ActorDbAdapter)params[0];
// String table=(String)params[1];
// int actorId=Integer.parseInt((String)params[2]);
// String where=(String)params[3];
// String[] whereParams=(String[])params[4];
//
// db.updatePhoneNumber(table, values, where, whereParams);
//
// return(null);
// }
// }
//
// private class DeleteTask extends
// ContentChangingTask<Object, Void, Void> {
// DeleteTask(PhoneNumberDataLoader loader) {
// super(loader);
// }
//
// #Override
// protected Void doInBackground(Object... params) {
// ActorDbAdapter db=(ActorDbAdapter)params[0];
// int actorId=Integer.parseInt((String)params[1]);
// int phoneNumberId=Integer.parseInt((String)params[2]);
// String where=(String)params[3];
// String[] whereParams=(String[])params[3];
//
// db.deletePhoneNumber(table, where, whereParams);
//
// return(null);
// }
// }
private class ExecSQLTask extends
ContentChangingTask<Object, Void, Void> {
ExecSQLTask(PhoneNumberDataLoader loader) {
super(loader);
}
#Override
protected Void doInBackground(Object... params) {
ActorDbAdapter db=(ActorDbAdapter)params[0];
String actorId=(String)params[1];
db.readPhoneById(actorId);
return(null);
}
}
}
Here is my full ListAdapter
package myApp.planner.utilities;
import java.util.ArrayList;
import java.util.List;
import myApp.planner.R;
import myApp.planner.codes.PhoneOrAddressTypeCode;
import myApp.service.data.PhoneNumber;
import myApp.service.data.PhoneNumberListData;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.TextView;
public class PhoneNumberListAdapter extends ArrayAdapter<PhoneNumber> {
private List<PhoneNumber> phoneNumbers;
private final LayoutInflater mInflater;
private Activity activity;
public PhoneNumberListAdapter(Activity a, int textViewResourceId) {
super(a, textViewResourceId);
activity = a;
mInflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void setData(List<PhoneNumber> data) {
if (this.phoneNumbers==null) {
this.phoneNumbers = new ArrayList<PhoneNumber>();
}
this.phoneNumbers.clear();
if (data != null) {
for (PhoneNumber phoneNumber : data) {
this.phoneNumbers.add(phoneNumber);
}
}
}
public static class PhoneNumberListHolder {
private TextView actorid=null;
private TextView phonenumberid=null;
private TextView phonetype=null;
private TextView phonenumber=null;
private CheckBox isprimary=null;
PhoneNumberListHolder(View row) {
actorid=(TextView)row.findViewById(R.id.actorid);
phonenumberid=(TextView)row.findViewById(R.id.phonenumberid);
phonetype=(TextView)row.findViewById(R.id.txtphonetype);
phonenumber=(TextView)row.findViewById(R.id.txtphonenumber);
isprimary=(CheckBox)row.findViewById(R.id.isprimary);
}
//void populateForm(ArrayList<PhoneNumberListData> c, int position) {
void populateForm(PhoneNumber data) {
//PhoneNumberListData data = c.get(position);
// Attempt to add the Actor ID
if (actorid != null){
actorid.setText(data.getActor().get(0).getActorId()==0 ? "0": Integer.toString(data.getActor().get(0).getActorId()));
}
// Attempt to add the Phone Number Item ID
if (phonenumberid != null){
phonenumberid.setText(data.getPhoneNumberId()==0 ? "0": Integer.toString(data.getPhoneNumberId()));
}
// Attempt to add the Phone Number Type
if (phonetype != null){
phonetype.setText(data.getPhoneType()==null ? "": PhoneOrAddressTypeCode.valueOf(data.getPhoneType()).toString());
}
// Attempt to add the Phone Number
if (phonenumber != null){
phonenumber.setText(data.getPhoneNumber1()==null ? "": data.getPhoneNumber1());
}
// Attempt to add the is Primary Flag
if (isprimary != null){
isprimary.setChecked(data.getIsPrimary()==0 ? Boolean.FALSE: Boolean.TRUE);
}
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
PhoneNumberListHolder holder;
if (row == null) {
row = mInflater.inflate(R.layout.phonenumber_row, parent, false);
holder=new PhoneNumberListHolder(row);
row.setTag(holder);
} else {
holder = (PhoneNumberListHolder)row.getTag();
}
holder.populateForm(this.phoneNumbers.get(position));
return row;
}
}
The ListFragment:
package myApp.planner;
import java.util.ArrayList;
import java.util.List;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SearchViewCompat;
import android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat;
import android.text.TextUtils;
import android.content.Intent;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.database.Cursor;
import android.view.ContextMenu;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ListView;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import myApp.planner.R;
import myApp.planner.utilities.PhoneNumberListAdapter;
import myApp.service.data.PhoneNumber;
import myApp.service.data.PhoneNumberDataLoader;
public class ActorPhoneNumberListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<List<PhoneNumber>> {
public final static String ID_EXTRA="myapp.planner.actorid";
protected final static String TAG = "ActorPhoneNumberListFragment";
private static final int ADD_ID=Menu.FIRST + 1;
private static final int DELETE_ID=Menu.FIRST + 3;
private PhoneNumberListAdapter mAdapter=null;
private PhoneNumberDataLoader loader=null;
private String mCurFilter;
private String actorId = "0";
//private SharedPreferences prefs=null;
OnActorPhoneNumberListListener listener=null;
OnQueryTextListenerCompat mOnQueryTextListenerCompat;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
this.actorId = getActivity().getIntent().getExtras().getString(ID_EXTRA).toString();
}
#Override
public void onResume() {
super.onResume();
Bundle args=getArguments();
if (args!=null) {
loadPhoneNumbers(args.getString(ID_EXTRA));
}
// init Empty Test for no Phone numbers Found
// Add the menu options that we need to manage the list
setHasOptionsMenu(true);
// Hookup the dbAdapter and create a blank adapter
initList();
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onListItemClick(ListView list, View view, int position, long id) {
if (listener!=null) {
//We will actually want the PhoneNumber Id here for the popup edit screen
String mId = actorId;
listener.onActorPhoneNumberListSelected(mId);
}
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.phonenumber_opton, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId()==R.id.addNewPhone) {
//add();
return(true);
} else if (item.getItemId()==R.id.help) {
startActivity(new Intent(getActivity(), HelpPage.class));
return(true);
} else if (item.getItemId()==R.id.phoneRefresh) {
//startActivity(new Intent(getActivity(), ActorPhoneNumberListFragment.class));
//We may just need to refresh the loader
return(true);
} else
return(super.onOptionsItemSelected(item));
}
public void setOnActorPhoneNumberListListener(OnActorPhoneNumberListListener listener) {
this.listener=listener;
}
public void loadPhoneNumbers(String actorId) {
this.actorId=actorId;
}
private void initList() {
mAdapter=new PhoneNumberListAdapter(getActivity(), R.layout.phonenumber_row);
setListAdapter(mAdapter);
// Start out with a progress indicator.
setListShown(false);
getActivity().getSupportLoaderManager().initLoader(0, null, this);
}
public interface OnActorPhoneNumberListListener {
void onActorPhoneNumberListSelected(String actorId);
}
#Override
public Loader<List<PhoneNumber>> onCreateLoader(int loaderId, Bundle args) {
loader= new PhoneNumberDataLoader(getActivity(), actorId);
return(loader);
}
#Override
public void onLoadFinished(Loader<List<PhoneNumber>> loader, List<PhoneNumber> data) {
// Now give the data to the adapter
mAdapter.setData(data);
mAdapter.notifyDataSetChanged();
//setListAdapter(mAdapter);
// Show the list
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
#Override
public void onLoaderReset(Loader<List<PhoneNumber>> arg0) {
// TODO Auto-generated method stub
mAdapter.setData(null);
}
}