I've been reading all day threads regarding this issue I came up with a strategy but can't make it work
I have a listview fetching json data from a sql server
this listview already has a on swipe refresh function
I need this listview to refresh automatically only when new row was inserted in the data base.
So I wrote a php file fetching number of rows and echoing it witha 3 second refresh (on the php itself) so every time I enter the php file I get the realtime row numbers of my table.
I'm trying to build a function inside my MainActivity:
int OldNumberOfRows = data from the php file
while(true){
int newNumberOfRows = fetch data again using that php
if(both arent equal) execute refresh command.
}
Note: I got no idea how to extract the string from my asynctask to start manipulating my code with it.
That's it in general, Iv'e added the main activity , the "outer class" (FetchNumRowAsync) calling that php the swipe class and the php itself
MainActivity:
public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {
private String TAG = MainActivity.class.getSimpleName();
private String URL = "http://troyka.esy.es/troyka/orders.php";
private SwipeRefreshLayout swipeRefreshLayout;
private ListView listView;
private SwipeListAdapter adapter;
private List<Order> orderList;
// initially offset will be 0, later will be updated while parsing the json
private int offSet = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new FetchRowNumAsync(this).execute("http://troyka.esy.es/numberofrows.php");
listView = (ListView) findViewById(R.id.listView);
//RelativeLayout.LayoutParams layout_description = new RelativeLayout.LayoutParams(50,10);
//Rl.setLayoutParams(layout_description);
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);
orderList = new ArrayList<>();
adapter = new SwipeListAdapter(this, orderList);
listView.setAdapter(adapter);
swipeRefreshLayout.setOnRefreshListener(this);
/**
* Showing Swipe Refresh animation on activity create
* As animation won't start on onCreate, post runnable is used
*/
swipeRefreshLayout.post(new Runnable() {
#Override
public void run() {
swipeRefreshLayout.setRefreshing(true);
fetchOrders();
}
}
);
}
/**
* This method is called when swipe refresh is pulled down
*/
#Override
public void onRefresh() {
fetchOrders();
}
/**
* Fetching movies json by making http call
*/
private void fetchOrders() {
// showing refresh animation before making http call
swipeRefreshLayout.setRefreshing(true);
// appending offset to url
String url = URL + offSet;
// Volley's json array request object
JsonArrayRequest req = new JsonArrayRequest(url,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
if (response.length() > 0) {
// looping through json and adding to order list
for (int i = 0; i < response.length(); i++) {
try {
JSONObject orderObj = response.getJSONObject(i);
int rank = orderObj.getInt("rank");
String title = orderObj.getString("title");
Order m = new Order(rank, title);
orderList.add(0, m);
// updating offset value to highest value
if (rank >= offSet)
offSet = rank;
} catch (JSONException e) {
Log.e(TAG, "JSON Parsing error: " + e.getMessage());
}
}
adapter.notifyDataSetChanged();
}
// stopping swipe refresh
swipeRefreshLayout.setRefreshing(false);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "Server Error: " + error.getMessage());
Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_LONG).show();
// stopping swipe refresh
swipeRefreshLayout.setRefreshing(false);
}
});
// Adding request to request queue
MyApplication.getInstance().addToRequestQueue(req);
}
}
FetchRowNumAsync:
public class FetchRowNumAsync extends AsyncTask<String, Void, String> {
private Context mContext;
public FetchRowNumAsync(Context ctx){
this.mContext = ctx;
}
protected String doInBackground(String... urls)
{
String fullString = "";
try{
URL url = new URL(urls[0]);
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
String line;
while ((line = reader.readLine()) != null) {
fullString += line;
}
reader.close();
}catch(Exception e ){
e.getMessage();
}
return fullString;
}
#Override
protected void onPostExecute(String value){
try{
((OnValueFetchedListener) mContext).onValueFetched(value);
}catch(ClassCastException e){}
}
public interface OnValueFetchedListener{
void onValueFetched(String columns);
}
}
SwipeListAdapter:
public class SwipeListAdapter extends BaseAdapter {
private Activity activity;
private LayoutInflater inflater;
private List<Order> orderList;
private String[] bgColors;
public SwipeListAdapter(Activity activity, List<Order> orderList) {
this.activity = activity;
this.orderList = orderList;
bgColors = activity.getApplicationContext().getResources().getStringArray(R.array.movie_serial_bg);
}
#Override
public int getCount() {
return orderList.size();
}
#Override
public Object getItem(int location) {
return orderList.get(location);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (inflater == null)
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null)
convertView = inflater.inflate(R.layout.list_row, null);
TextView serial = (TextView) convertView.findViewById(R.id.serial);
TextView title = (TextView) convertView.findViewById(R.id.title);
serial.setText(String.valueOf(orderList.get(position).id));
title.setText(orderList.get(position).title);
String color = bgColors[position % bgColors.length];
serial.setBackgroundColor(Color.parseColor(color));
return convertView;
}
}
PHP
<?php
header("refresh: 3;");
$mysqli = new mysqli("irrelevant","irrelevant","irrelevant","irrelevant");
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$query = "SELECT COUNT(*) FROM orders";
$result = mysqli_query($mysqli,$query);
$rows = mysqli_fetch_row($result);
echo ($rows[0]);
$result->close();
$mysqli->close();
?>
Try this approach:
Create an endpoint in your server like the following:
//http://somesite.com/api/data/pull/check
Then, you can easily check this endpoint that returns some value like true or false depending on whether there is new data inserted into the db.
From the result you receive, you can then decide on whether to refresh your data on the phone by making another HTTP request or not. You always want to avoid making unnecessary requests to the server - remember users spend money every time they use their data plan (service).
I, like in the comments above, recommend having a column with a timestamp that you can check so that you only get the newly added data instead of everything!
I hope this gives you a simple idea on how to approach this issue! Good luck!
android app will not know when you have added/updated data in your table on the server until and unless you call script from app and fetch the data and update in your device.
only if your app has implemented these feature's
push notification- call Script every time you receive notification.
XMPP service- used for chat apps(which is not probably answer for
your question right now)
here is my suggestion for you
From server side:
create timestamp field in your table on server. update it with
current timestamp value every time you do changes(i.e update/add) in
the table.and when when that script is called send it across in json
and make your app save it in sqlite along with data.
server will compare for timestamp posted by app everytime with the
saved timestamp in the server for new data.
from client side:
for fist time timestamp from app will be 0. server will check it and
send the whole data along with the timestamp saved during changes in
table. save the data along with time stamp . second time when the
script is called App will be sending the timestamp that was last
saved.
with all this your app will not come to know still if new data is added until you call script and check. but atleast it will come to know if new data is received or not and whether to refresh ur screen
now comes script calling part from client side that is executing of assynch task, do it using handler to execute assynch class every minute
final Handler timerHandler = new Handler();
Runnable timerRunnable;
timerRunnable = new Runnable() {
#Override
public void run() {
new FetchRowNumAsync(context).execute(url);
timerHandler.postDelayed(timerRunnable, 60000); // run every minute
}
};
and unregister it in onDestroy()
#Override
public void onDestroyView() {
// TODO Auto-generated method stub
super.onDestroyView();
timerHandler.removeCallbacks(timerRunnable);
}
My app normally works just fine, until I face a strange problem on specific device. There are 2 activities in App. After I start ActivityB inside of ActivityA, ActivityA starts with no issue. However, after I go back to the ActivityA with pushing back hardware button or calling finish(); inside of closeButton in ActivityB, ActivityA reloads itself. It triggers onCreate() again and reloads all its contents. And I'm not changing orientation of phone. This strange behavior only appears in 15 phones over 1.000 download of app.
This problem only occurs on Galaxy S3 Android OS 4.1.2. And this is also strange.
Do you have any idea why this is happening?
When I start a new Activity inside of button listener like this:
ActivityA.java (MesajlarListViewActivity)
public class MesajlarListViewActivity extends TrackedActivity {
Context context = null;
// contacts JSONArray
JSONArray contacts = null;
ArrayList<Message> productArray = new ArrayList<Message>();
private ProductAdapter adapter;
private ListView productList;
private Runnable viewOrders;
private HoloProgressIndicator profilInfoProgress = null;
ImageView kapatButton = null;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.mesajlar_list);
context = this;
kapatButton = (ImageView) findViewById(R.id.kapat_button);
/* kapat button onclick listener. */
// =================================================================================================================
kapatButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view)
{
// Set vibration on touch.
KnetGenericClass.vibratePhone(context);
finish();
}
});
// =================================================================================================================
//Progress bar.
profilInfoProgress = (HoloProgressIndicator) findViewById(R.id.profil_info_progress);
// cheking internet connectivity.
if(KnetGenericClass.checkInternetConnection(context))
{
// start task!
/* internet var ise web service baglantisi kurmaya baslayabiliriz. */
startActivityIndicatorWithThread();
}
else
{
KnetGenericClass.printErrorMessage(context, "Bağlantı Hatası",
"Lütfen internet bağlantınızı kontrol ediniz.");
}
productList = (ListView) findViewById(R.id.product_list);
adapter = new ProductAdapter(this, R.layout.message_row, productArray);
productList.setAdapter(adapter);
// When user click a view on list view new page is appearing.
productList.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
// Set vibration on touch.
KnetGenericClass.vibratePhone(context);
/* Navigate to message detay activity class with ilan ID. */
Intent myIntent = new Intent(view.getContext(), MesajDetayActivity.class);
myIntent.putExtra("messageID", productArray.get(position).getId());
startActivity(myIntent);
// setting image of clicked message null.
RelativeLayout relativeLayout = (RelativeLayout) view;
ImageView unreadedImageView = (ImageView) relativeLayout.findViewById(R.id.unreaded_image);
unreadedImageView.setImageResource(0);
}
});
}
public class ProductAdapter extends ArrayAdapter<Message> {
ArrayList<Message> items;
public ProductAdapter(Context context, int textViewResourceId, ArrayList<Message> objects) {
super(context, textViewResourceId, objects);
this.items = objects;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
if(convertView == null)
{
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.message_row, null);
}
ImageView unreadedImageView = (ImageView) convertView.findViewById(R.id.unreaded_image);
TextView productName = (TextView) convertView.findViewById(R.id.product_name);
TextView productDetail = (TextView) convertView.findViewById(R.id.product_detail);
// TextView productDate = (TextView)
// convertView.findViewById(R.id.product_date);
TextView sentDate = (TextView) convertView.findViewById(R.id.product_date);
productName.setText(items.get(position).getSender());
productDetail.setText(items.get(position).getTitle());
// String bodyNoHTML = items.get(position).getBody();
if(items.get(position).getIsReaded())
{
unreadedImageView.setImageResource(0);
}
else
{
unreadedImageView.setImageResource(R.drawable.bluedot);
}
String dateStr = items.get(position).getSentDate();
try
{
sentDate.setText(dateStr.substring(6, 8) + "." + dateStr.substring(4, 6) + "." + dateStr.substring(0, 4)
+" "+dateStr.substring(8, 10)+":"+dateStr.substring(10, 12));
}
catch(Exception e)
{
sentDate.setText("");
}
return convertView;
}
}// #end of product adapter class.
/* web service'e baglanti kurulan methodu threadin icerisinde cagiriyoruz. */
public void startActivityIndicatorWithThread()
{
// ==============================================================================================
// getting ilan details into arraylist.
// setting up thread.
viewOrders = new Runnable() {
public void run()
{
getMessageListFromWebService();
}
};
Thread thread = new Thread(null, viewOrders, "MagentoBackground");
thread.start();
profilInfoProgress.start();
// ==============================================================================================
// #end of the thread declaration.
}
public void getMessageListFromWebService()
{
// Creating JSON Parser instance
JSONParser jParser = new JSONParser(context);
// getting JSON string from URL
JSONArray jsonArray = jParser.getAuthorizedInfoFromUrlToJSONArray(
WebServiceInfo.getKnetWebServiceLink()+"/API/Member/GetInboxMessageList", MainActivity.getAccessToken());
// if json is null then there is a problem.
if(jsonArray == null)
{
// if json array is null then print error message.
runOnUiThread(showAlertMessage);
runOnUiThread(returnRes);
return;
}
try
{
// Eger aranilan kritere gore ilan yok ise hata mesaji basiyoruz.
if(jsonArray.length() == 0)
{
// if json array is null then print error message.
runOnUiThread(showAlertIlanYokMessage);
runOnUiThread(returnRes);
return;
}
// looping through All Contacts
for (int i = 0; i < jsonArray.length(); i++)
{
JSONObject c = jsonArray.getJSONObject(i);
// Storing each json item in variable
// String id = c.getString(TAG_ID);
String id = c.getString("Id");
String sender = c.getString("Sender");
// String body = c.getString("Body");
String title = c.getString("Title");
String sentDate = c.getString("SentDate");
Boolean isReaded = c.getBoolean("IsRead");
Message productObject = new Message(id, sender, "", title, sentDate, isReaded);
productArray.add(productObject);
}
}
catch (Exception e)
{
Log.e("BACKGROUND_PROC", e.getMessage());
}
runOnUiThread(returnRes);
}
// #end of thread.
private Runnable returnRes = new Runnable() {
public void run()
{
profilInfoProgress.stop();
adapter.notifyDataSetChanged();// refreshing data over adapter in
// list view.
}
};
// #end of thread.
private Runnable showAlertMessage = new Runnable() {
public void run()
{
// Bu hata genelde linkteki problemden, servera ulasilamamasindan
// veya timeouttan meydana gelir.
Toast.makeText(getApplicationContext(),
"Mesajlar alınamadı lütfen daha sonra tekrar deneyiniz.",
Toast.LENGTH_LONG).show();
}
};
private Runnable showAlertIlanYokMessage = new Runnable() {
public void run()
{
// Bu hata aranilan kelimeye gore ilan bulunamazsa gelir.
Toast.makeText(getApplicationContext(),
"Mesajlar bulunamadı.",
Toast.LENGTH_LONG).show();
}
};
}
========================================================================
ActivityB.java (MesajDetayActivity.java)
public class MesajDetayActivity extends TrackedActivity {
private HoloProgressIndicator profilInfoProgress = null;
TextView titleTextView = null;
TextView senderTextView = null;
TextView dateTextView = null;
WebView bodyWebView = null;
Message messageObject = null;
String messageID = null;
ImageView kapatButton = null;
Context context;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.mesajdetaylari);
context = this;
kapatButton = (ImageView) findViewById(R.id.kapat_button);
/* kapat button onclick listener. */
// =================================================================================================================
kapatButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view)
{
// Set vibration on touch.
KnetGenericClass.vibratePhone(context);
finish();
}
});
// =================================================================================================================
//Progress bar.
profilInfoProgress = (HoloProgressIndicator) findViewById(R.id.profil_info_progress);
Bundle extras = getIntent().getExtras();
if(extras != null)
{
messageID = extras.getString("messageID");
}
titleTextView = (TextView) findViewById(R.id.title_textview);
senderTextView = (TextView) findViewById(R.id.sender_textview);
dateTextView = (TextView) findViewById(R.id.date_textview);
bodyWebView = (WebView) findViewById(R.id.mesaj_webView);
// Show the ProgressDialog on this thread
profilInfoProgress.start();
// Start a new thread that will download all the data
new MakeItTask().execute();
}
// Async task.
private class MakeItTask extends AsyncTask<String, Void, Object> {
protected Object doInBackground(String... args)
{
Log.i("MyApp", "Background thread starting");
// This is where you would do all the work of downloading your data
// getting message detay
/* connect to web service */
getMessageDetayFromWebService();
return null;
}
protected void onPostExecute(Object result)
{
// Pass the result data back to the main activity
// TakipListeActivity.this.data = result;
try
{
titleTextView.setText("Başlık: " + messageObject.getTitle());
senderTextView.setText("Gönderen: " + messageObject.getSender());
dateTextView.setText("Tarih: " + messageObject.getSentDate().substring(6, 8) + "."
+ messageObject.getSentDate().substring(4, 6) + "."
+ messageObject.getSentDate().substring(0, 4));
if(!messageObject.getBody().contains("img"))
{
bodyWebView.loadDataWithBaseURL(null, messageObject.getBody(), "text/html", "UTF-8", null);
}
}
catch (Exception e)
{
Log.e(CONNECTIVITY_SERVICE, "Mesaj Detayi bilgileri basilamadi.");
}
profilInfoProgress.stop();
}
}
/* web service'e baglanti kurulan methodu threadin icerisinde cagiriyoruz. */
public void getMessageDetayFromWebService()
{
// Creating JSON Parser instance
JSONParser jParser = new JSONParser(context);
// getting JSON string from URL
JSONObject jsonObject = jParser.getAuthorizedInfoFromUrlToJSONObject(
WebServiceInfo.getKnetWebServiceLink()+"/API/Member/GetInboxMessage/" + messageID, MainActivity.getAccessToken());
// if json is null then there is a problem.
if(jsonObject == null)
{
return;
}
try
{
String title = jsonObject.getString("Title");
String id = jsonObject.getString("Id");
String sender = jsonObject.getString("Sender");
String date = jsonObject.getString("SentDate");
String body = jsonObject.getString("Body");
messageObject = new Message(id, sender, body, title, date, true);
}
catch (Exception e)
{
Log.e("BACKGROUND_PROC", e.getMessage());
}
}// #end of getIlanDetayFromWebService.
}
Edit: Not only these two activities have this problem, all the activities acting same behavior on some phones.
Check to see whether Don't keep activities under Settings > System > Developer options > Apps is enabled or not.
The Activity documentation (http://developer.android.com/reference/android/app/Activity.html) says the following about the lifecycle of a background activity:
A background activity (an activity that is not visible to the user and has been paused) is no longer critical, so the system may safely kill its process to reclaim memory for other foreground or visible processes. If its process needs to be killed, when the user navigates back to the activity (making it visible on the screen again), its onCreate(Bundle) method will be called with the savedInstanceState it had previously supplied in onSaveInstanceState(Bundle) so that it can restart itself in the same state as the user last left it.
In other words, ActivityA may or may not be destroyed by the operating system while ActivityB is active, so this situation has to be handled in the code. If ActivityA has been destroyed, onCreate(Bundle) will be called, when the user presses the back button in ActivityB.
There's an Android developer setting called "Do not keep activities". The description for this option is "Destroy every activity as soon as the user leaves it." This sounds like a good description of what you're seeing, and since you're only seeing it on a few phones the idea that this is caused by a non-default system setting seems plausible.
Ideally your app would still work in this scenario, even if less optimally. But if this setting is a problem for your app, you may wish to document this problem for your users.
Have you tried changing the launchmode in the Android Manifest? Try adding this to your Activity declaration:
android:launchMode="singleTask"
Next, try using startActivityForResult, instead of startActivity. This will force Activity A to call its onActivityResult(int, int, Intent) method when Activity B finishes - which may skip this (buggy) call to onCreate. Then, in Activity A, implement the method to do something (such as printing a debug statement):
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
Log.i("Test", "Did this work???");
//TODO send notification to your server to verify this works?
}
I do not see any problem in this behaviour.
In case you wish to preserve the state of ActivityA, make use of the methods onSaveInstanceState and onRestoreInstanceState. See Activity Lifecycle at http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle for more details.
See also https://stackoverflow.com/a/10492967/332210 for a deeper understanding.
You can try one thing provide your layout in onCreate() and do the rest of the work in onStart() ?? if it works??
LIKE:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.show);
}
and
#Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
Log.i(TAG, "On Start .....");
}
See Activity Lifecycle
Perhaps you should use
Intent startIntent = new Intent(view.getContext(), ActivityB.class);
startActivity(startIntent);
finish() ;
And
Intent startIntent = new Intent(view.getContext(), ActivityA.class);
startActivity(startIntent);
finish() ;
each time you go back or forward.
It too faced the exact problem and solved issue by Using android:launchMode="standard" in activity of manifest.
Override onStart() and onResume method in Activity A and check if the problem is still persist. and if possible please give your activtiy A and B code here.
Activity A uses layout R.layout.mesajlar_list
Activity B uses layout R.layout.mesajdetaylari
But both have the following line of code:
kapatButton = (ImageView) findViewById(R.id.kapat_button);
Which layout is R.id.kapat_button in? Using the same id in different layouts is a very risky thing to do. I can't guarantee it's causing what you're seeing, but it is the sort of thing that may cause weird behaviour.
I think it is not because of memory the limit.
https://www.box.com/s/7pd0as03bb8wwumuc9l9
You should test these two activities and check whether it is happening in this example too or not. Please share your AndroidManifest.xml file content too, it will help with debugging.
I got this issue recently, and this make me annoyed. I think that issue around 2 options solution to check but useless.
About the setting "Don't keep activities" corrected here, I used this code to check that it optional checked or not (my test device customize base on version 2.3.5 and not show this option):
private boolean isAlwaysFinishActivitiesOptionEnabled() {
int alwaysFinishActivitiesInt = 0;
if (Build.VERSION.SDK_INT >= 17) {
alwaysFinishActivitiesInt = Settings.System.getInt(getApplicationContext().getContentResolver(), Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0);
} else {
alwaysFinishActivitiesInt = Settings.System.getInt(getApplicationContext().getContentResolver(), Settings.System.ALWAYS_FINISH_ACTIVITIES, 0);
}
if (alwaysFinishActivitiesInt == 1) {
return true;
} else {
return false;
}
}
Result check is false in my case. I also check the memory when running application and it nothing occur.
you can use android:launchMode="singleTop"in manifest.
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:launchMode="singleTop"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
I have to update an expandableList from server, I am using asyncTask to download and fill new values in local database, everything is done in doInBackground but after its done I tried to refresh my expandableList in onPostExecute but I am getting a nullPointer on the very statement which runs fine before loading new data. All I am doing is calling the same method which instializes expandableList in the first place..
The method which intializes list for the first time:
public void initializeExpandableList() {
// TODO Auto-generated method stub
getValuesForList();
setupList();
setupClickListenersOnExpandList();
}
And the code for getValuesForList() and setUpList() is:
public void getValuesForList() {
// get which list_id are present in subtopic table
DataBaseHelper myDbHelper = new DataBaseHelper(context);
ArrayList<String> ids = myDbHelper.getListIdsFromSubTopic();
ArrayList<String> typeList = myDbHelper.getTypeListFromDB(ids);
// typeList = myDbHelper.getTypeListFromDB();
Log.v("typelist", typeList + "");
arrGroupelements = typeList.toArray(new String[typeList.size()]);
Log.v("arrGrp", arrGroupelements.toString() + "");
ArrayList<ArrayList<String>> subtopics = myDbHelper.getChildForGroup();
arrChildelements = new String[subtopics.size()][];
for (int i = 0; i < subtopics.size(); i++) {
ArrayList<String> row = subtopics.get(i);
arrChildelements[i] = row.toArray(new String[row.size()]);
}
Log.e("arrChildElements", arrChildelements.toString());
}
And for setUpList() method:
public void setupList() {
expList.setAdapter(adap);
// adap.notifyDataSetChanged();
((BaseAdapter) expList.getAdapter()).notifyDataSetChanged();
}
After inserting data in doInBackground(), inside onPostExecute I am calling a method refresh() which again makes a call to initializeExpandableList() where I am getting null pointer.
private void refresh() {
// TODO Auto-generated method stub
initializeExpandableList();
}
Instead of initializeExpandableLIst, also tried
((BaseAdapter) expList.getAdapter()).notifyDataSetChanged();
and also tried restarting the activity:
Intent intent = getIntent();
finish();
startActivity(intent);
again getting null pointer in last line startActivity(intent);
What am I missing here??
I have a json feed from this URL which contains 20 fields and I parse all the datas..but again I need to load more data from the json feed after showing the 20 fields in listview.
I have created a AsyncTask and loaded the json in listview. this is my class
public void onCreate(Bundle savedInstanceState) {
new DoInBackgrd().execute();
}
private class DoInBackgrd extends AsyncTask<Void, Void, Void> implements
DialogInterface.OnCancelListener {
private ProgressDialog processDialog;
#Override
protected void onPreExecute() {
processDialog = ProgressDialog.show(List.this, "",
getString(R.string.loading), true);
processDialog.setCancelable(true);
}
public void onCancel(DialogInterface arg0) {
// TODO Auto-generated method stub
if (processDialog.isShowing()) {
processDialog.dismiss();
}
}
#Override
protected Void doInBackground(Void... arg0) {
// TODO Auto-generated method stub
Jsonfunctions jParser = new Jsonfunctions();
JSONObject json = jParser.getJSONFromUrl(url);
try {
// Getting Array of Contacts
results = json.getJSONArray(TAG_RESULTS);
// looping through All Contacts
for (int i = 0; i < results.length(); i++) {
JSONObject c = results.getJSONObject(i);
id = c.getString(TAG_ID);
name = c.getString(TAG_NAME);
adress = c.getString(TAG_ADRRESS);
latitude = c.getString(TAG_LATITUDE);
latitudeAry.add(c.getString(TAG_LATITUDE).toString());
longitude = c.getString(TAG_lONGITUDE);
latitudeAry.add(c.getString(TAG_lONGITUDE).toString());
distance = c.getString(TAG_DISTANCE);
image = c.getString(TAG_IMAGE);
phone = c.getString(TAG_TELEPHONE);
telphonenumberAry
.add(c.getString(TAG_TELEPHONE).toString());
NameAry.add(c.getString(TAG_NAME).toString());
resourceAry.add(new ResourceClass(point, id, name, adress,
distance, latitude, longitude, phone));
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void unused) {
if (processDialog.isShowing()) {
processDialog.dismiss();
}
listView.setAdapter(new ASyncAdapter());
listView.setDividerHeight(2);
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long id) {
Intent details = new Intent(List.this, Details.class);
details.putExtra("position", position + 1);
details.putExtra("name", resourceAry.get(position)
.getName());
details.putExtra("adress", resourceAry.get(position)
.getAdress());
details.putExtra("phone", resourceAry.get(position)
.getTelephone());
details.putExtra("latitudes", latitude);
details.putExtra("longitudes", longitude);
startActivity(details);
}
});
}
}
Thanks in advance
I had just finished working on similar kind of requirement(issue faced on is specified in)
Hence I'm hoping to provide you proper solution that is helpful to you and saves ur time.
If I'm not wrong you need to populate same ListView with next 20(i.e. 21 - 40) fields obtained in response for server api.
In that case u need to call server api again and again for that u need an event. Say u add a 'Next' button and on its click u retrive next 20 fields(21 - 40).
Currently in ur code in 'DoInBackgrd', you are binding/setting Adapter(ASyncAdapter) each time you need to bind new records/fields to ListView. This is not a good practice, also it at a instance it will not refresh fields of newly assigned adapter in listView.
Hence you should :
Just retrieve/parse new fileds from JSon and set them in adapter. Adapter will notify your listView about data change and listView will refresh its view.
Considering that 'ASyncAdapter' is your custom adapter that implements ArrayAdapter, just add following(change Variable type from Restaurant to as per your requirement) method to it.
public void reSet(ArrayList<Resturant> resturantsCache) {
//This will clear your current fields/records in adpter
clear();
//This will new fields/records in adpter from provided resturantsCache ArrayList.
for (Resturant resturant : resturantsCache) {
add(resturant);
}
}
Hope you will be able to replace variable types in provided method and use it as per you requirements, In case you need more help please provide ASyncAdapter code.
Thanks.
I have this ListView which fetches its data (image+text) from JSON on the web.
Now I have a task to make the ListView is accessible without internet connection. My idea is by saving the JSON data from the web when the app is run for the first time with internet, and when it can't find internet connection it will get the data from the persistent Storage.
Can anybody help me with this? I'm still a beginner can't find the example of SharedPreferences with JSON.
Thanks a lot
public class ProjectsList extends Activity {
/** Called when the activity is first created. */
//ListView that will hold our items references back to main.xml
ListView lstTest;
//Array Adapter that will hold our ArrayList and display the items on the ListView
ProjectAdapter arrayAdapter;
//List that will host our items and allow us to modify that array adapter
ArrayList<Project> prjcts=null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.projects_list);
//Initialize ListView
lstTest= (ListView)findViewById(R.id.lstText);
//Initialize our ArrayList
prjcts = new ArrayList<Project>();
//Initialize our array adapter notice how it references the listitems.xml layout
arrayAdapter = new ProjectAdapter(ProjectsList.this, R.layout.listitems,prjcts,ProjectsList.this);
//Set the above adapter as the adapter of choice for our list
//lstTest.setAdapter(arrayAdapter);
lstTest.setAdapter(arrayAdapter);
if (isOnline())
{
//Instantiate the Web Service Class with he URL of the web service not that you must pass
WebService webService = new WebService("http://liebenwald.spendino.net/admanager/dev/android/projects.json");
//Pass the parameters if needed , if not then pass dummy one as follows
Map<String, String> params = new HashMap<String, String>();
params.put("var", "");
//Get JSON response from server the "" are where the method name would normally go if needed example
// webService.webGet("getMoreAllerts", params);
String response = webService.webGet("", params);
try
{
//Parse Response into our object
Type collectionType = new TypeToken<ArrayList<Project>>(){}.getType();
//JSON expects an list so can't use our ArrayList from the lstart
List<Project> lst= new Gson().fromJson(response, collectionType);
//Now that we have that list lets add it to the ArrayList which will hold our items.
for(Project l : lst)
{
prjcts.add(l);
ConstantData.projectsList.add(l);
}
//Since we've modified the arrayList we now need to notify the adapter that
//its data has changed so that it updates the UI
arrayAdapter.notifyDataSetChanged();
}
catch(Exception e)
{
Log.d("Error: ", e.getMessage());
}
}
lstTest.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent care = new Intent(ProjectsList.this, ProjectDetail.class);
care.putExtra("spendino.de.ProjectDetail.position",position);
startActivity(care);
}
});
}
#Override
public void onDestroy()
{
yAdapter.imageLoader.stopThread();
lstTest.setAdapter(null);
super.onDestroy();
}
protected boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnected()) {
return true;
} else {
AlertDialog.Builder alertbox = new AlertDialog.Builder(this);
alertbox.setTitle("spendino Helfomat");
alertbox.setMessage ("Please check your internet connection");
alertbox.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//Main.this.finish();
}
});
alertbox.show();
return false;
}
}
}
SharedPreferences has no methods for saving a JSON object as is, you must try to convert it to a String. Then when getting it you must parse this String back to JSON. Good luck!
JSON to String:
JSONObject o = new JSONObject(data.trim());
String name = o.getString(Constants.NAME);
long date = o.getLong(Constants.DATE);
String mes = o.getString(Constants.MESSAGE);
StringBuilder buf = new StringBuilder(text.getText());
buf.append(name).append(" (").append(dfTime.format(new Date(date))).append(")\n").append(mes).append("\n");
text.setText(buf.toString());
Making a JSON from a String is not a harder task, use StringTokenizer. Good luck!