I am using an API that delivers me the gas stations in Germany. I get the location and the name of the gas station using Asynctask.
I am putting these datas into a listView. For the listView I have implemented the setOnItemClickListener method, that is currently in doInBackground. If you click on a item, a new layout will be opened where all the fetched data are listed again, nothing special.
At the office I am using Android Studio 3.2.1 (Windows) at home I am using Android Studio 2.3.2 (Linux Ubuntu 64 bit).
At home I get the warning that the setOnItemClickListener should not be in DoInBackground. I know, that UI operations should be not there, yes.
But at office I don't get this warning. The syntax of the code is correct, when I start it from the office pc, everything works.
When I do the same at home, my whole phone (Samsung Galaxy S7) crashes (System.UI has stopped working) and even a hard reset did not work. For my home laptop Jack is enabled in order to work with Java 1.8 the API requires this.
The freezing appears when I scroll down the ListView and click on Items. Here is the code, I really do not know what kind of error this is:
public class ListOfGasStations extends AppCompatActivity {
Button button;
EditText editText;
ListView listView;
List<String> names = new ArrayList<String>();
int size;
String[] locationArray;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_of_gas_stations);
editText = findViewById(R.id.inputaddress);
button = findViewById(R.id.buttonaddress);
listView = findViewById(R.id.listviewgas);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Test().execute();
}
});
}
class Test extends AsyncTask<Void, Void, Void> {
#SuppressLint("NewApi")
#Override
protected Void doInBackground(Void... params) {
double addresslat = getLat(String.valueOf(editText.getText()));
double addresslong = getLong(String.valueOf(editText.getText()));
StationListResult result;
Tankerkoenig.Api api = new Tankerkoenig.ApiBuilder()
.withApiKey("MY_API_KEY")
.build();
try {
result = api.list(addresslat, addresslong)
.setSorting(StationListRequest.SortingRequestType.DISTANCE)
.setGasRequestType(GasRequestType.DIESEL)
.setSearchRadius(5)
.execute();
size = result.getStations().size();
int sizeOfStations;
System.out.println("Size" + size);
locationArray = new String[size];
for (int k = 0; k < size; k++) {
//size of the station names
sizeOfStations = String.valueOf(result.getStations().get(k).getBrand()).length();
//get gas stations name
String removeUmlaute = String.valueOf(result.getStations().get(k).getBrand()).substring(9, sizeOfStations - 1).toUpperCase();
//get street names
String location = String.valueOf(result.getStations().get(k).getLocation().getStreetName();
locationArray[k] = location;
names.add(removeUmlaute + "\n" + "\n" + location");
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
for (int i = 0; i < size; i++) {
if (position == i) {
Intent intent = new Intent(ListOfGasStations.this, NavToLocation.class);
intent.putExtra("message", locationArray[i]);
startActivity(intent);
}
}
}
});
}
} catch (RequesterException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void foo) {
super.onPostExecute(foo);
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(ListOfGasStations.this, android.R.layout.simple_list_item_1, names);
listView.setAdapter(arrayAdapter);
}
}
public double getLat(String address) {
double p1 = 0;
Geocoder coder = new Geocoder(this);
try {
ArrayList<Address> addresses = (ArrayList<Address>) coder.getFromLocationName(editText.getText().toString(), 1);
for (Address add : addresses) {
p1 = add.getLatitude();
}
} catch (IOException e) {
e.printStackTrace();
}
return p1;
}
public double getLong(String address) {
double p2 = 0;
Geocoder coder = new Geocoder(this);
try {
ArrayList<Address> addresses = (ArrayList<Address>) coder.getFromLocationName(editText.getText().toString(), 1);
for (Address add : addresses) {
p2 = add.getLongitude();
}
} catch (IOException e) {
e.printStackTrace();
}
return p2;
}
}
The warning may be different on different IDE version. There are some reason for freezing UI.
May be the listview item is so long. Cause listview load all items at a time. (Solution: Better is using RecyclerView)
It is true that you cannot touch UI element from async thread but you calling onclick in doInBackground. (Solution: use it in uiThread ).
You are calling onclick for every listViewItem that means you creating a memory inside doInBackground. May be it is the problem to reuse it. (So betting create onclik in onPostExecute or after finish async.)
Remember: onPostExecute call can destroy async execution (Mean work in donInBackground). So i am afraid to using onCLick in doInBackGround may the main cause of app freeze..
Related
I have a Activity that contains over 100 complex views (with images, text views etc). Showing up these views is to hard to do it without a Thread that loads the views asynchronously. So I tried to do it with an AsyncTask. I am not sure whether this is the correct way because the "hard staff" is something that HAS to be done in the UI Thread.
Now I've got the problem that the UI freezes though I used the onProgressUpdate for adding the views in the to parent view. I thought that this would result in single loading views that appear successive in the parent view. But this is not the case.
doInBackground fires all publishProgress calls and after that the main thread is blocked (activity frozen, loadbar does not rotate anymore). Is there a way to achieve what I wanted to have? I looked for solutions but alway ended up with ideas of using AsyncTask and no one had to do view-stuff as "hard staff". I am not using "get" in the AsyncTask what seems to be a problem with AsyncTask.
Here is my code for this. If you need any further information please tell me!
Is there any other way to solute this problem? Is my AsyncTask implementation not correct? I am looking for a way to load these complex views asyncronous to the parent view without blocking the main thread.
Thanks in advance!
public class LoadKraut extends AsyncTask<Integer,Kraut,Void> {
private Context context;
private LinearLayout parent;
private HashMap<String,HeadlineAlphabet> headlinesAlphabet = new HashMap<String, HeadlineAlphabet>();
private long time;
private Integer kategorie;
private char letter = 'X';
private int counter = 0;
private ProgressDialog dialog;
public LoadKraut(Context context) {
/**
* Kategorie:
* 1 - A-Z
* 2 - Notiz
* 3 - Favorit
* 4 - Giftig
*/
Log.i("Kraut", "Start thread" + (System.currentTimeMillis()-time) + "ms");
this.context = context;
this.dialog = new ProgressDialog(context);
this.time = System.currentTimeMillis();
}
#Override
protected void onPreExecute() {
dialog.setMessage("Lade Kräuter. Dieser Vorgang kann einen Moment dauern.");
dialog.show();
}
#Override
protected Void doInBackground(Integer... params) {
this.kategorie = params[0];
//Create overview
try {
DatabaseHelper databaseHelper = new DatabaseHelper(context);
Dao<Kraut,Integer> dao = databaseHelper.getKrautDAO();
parent = (LinearLayout) ((Activity) context).findViewById(R.id.ll_conainter_sv_uebersicht_kraeuter);
//setKraeuter(list, linearLayout, giftig)
long test = System.currentTimeMillis();
List<Kraut> list = new ArrayList<>();
switch (kategorie) {
case 1:
list = dao.queryForAll();
break;
case 2:
list = dao.queryBuilder().where().ne("notiz","").query();
break;
case 3:
list = dao.queryBuilder().where().eq("favorit",true).query();
break;
case 4:
list = dao.queryBuilder().where().eq("toedlichBunny",true).query();
break;
}
Log.i("Kraut","Fetching duration: " + String.valueOf(System.currentTimeMillis() - test));
Iterator<Kraut> iterator = list.iterator();
while(iterator.hasNext()) {
Kraut kraut = iterator.next();
Log.i("Kraut","called pp for" + kraut.getName());
publishProgress(kraut);
}
} catch (SQLException e) {
e.printStackTrace();
}
Log.i("Kraut", "End " + (System.currentTimeMillis()-time) + "ms");
return null;
}
#Override
protected void onProgressUpdate(Kraut... value) {
//Set all Krauts and headlines A-Z
long test = System.currentTimeMillis();
Kraut kraut = value[0];
Log.i("Kraut", String.valueOf(counter));
if((kategorie==1 || kategorie==4) && kraut.getName().charAt(0)!=letter) {
letter = kraut.getName().charAt(0);
HeadlineAlphabet letterHeadline = new HeadlineAlphabet(context);
letterHeadline.setText(String.valueOf(kraut.getName().charAt(0)));
headlinesAlphabet.put(String.valueOf(letterHeadline.getText()),letterHeadline);
parent.addView(letterHeadline);
}
KrautView krautView=null;
if(kategorie==1 || kategorie==3) {
krautView = new KrautUebersicht(context,kategorie);
} else if(kategorie==2) {
krautView = new KrautUebersichtNotiz(context);
}
if(krautView!=null) {
krautView.setKraut(kraut);
parent.addView((LinearLayout) krautView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
parent.getRootView().invalidate();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
Log.i("Kraut","Kraut View creation duration: " + String.valueOf(System.currentTimeMillis() - test));
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if(kategorie==1) {
//Set Alphabet Column right side
ArrayList<String> anfangsbuchstaben = Kraut.getAnfangsbuchstaben(context);
// Do this with an xml !
for (int i = 1; i <= 26; i++) {
//Log.i("Kraut", String.valueOf(i));
String currentLetter = Helper.getCharForNumber(i);
int id = context.getResources().getIdentifier("tv_"+currentLetter.toLowerCase(),"id",context.getPackageName());
TextView textView = (TextView) ((Activity) context).findViewById(id);
//If no Kraut contains Letter
if (!anfangsbuchstaben.contains(currentLetter)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
textView.setTextColor(context.getResources().getColor(R.color.darkgrey, context.getTheme()));
} else {
textView.setTextColor(context.getResources().getColor(R.color.darkgrey));
}
//Make clickable to jump to A-Z Headlines
} else {
textView.setOnClickListener(new JumpToLetterOnClickListener(headlinesAlphabet));
}
}
}
parent.invalidate();
if(dialog.isShowing()) {
dialog.dismiss();
}
}
}
Note that onProgressView() is called repeatedly as your AsyncTask runs. Therefore, it should be kept as short as possible. This also means that your current code is creating lots of views and adding them to the UI. Instead, you should add the view just once and then update its data in onProgressView().
Also, as Mike M. states in the comments, you should not call Thread.sleep() in onProgressView() since it runs on the UI thread. This is most likely the main reason your app is freezing.
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 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 am very new to android. I got two activities A, B . Activity A parse the data from the sever and iterate through the levels. and calls the activity B through intent. Activity B takes some time to display the data so I am trying to display the progress bar. Here is my code.
public class Display extends Activity {
ProgressDialog dialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.attributequestions);
new asynctask().execute();
}
class asynctask extends AsyncTask<Context,Void,Void>{
Survey[] surveyque=null;
// i hace created seperated class forsurvey that has info about data
String list[];
private ProgressDialog Dialog;
#Override
protected void onPreExecute()
{
Dialog=ProgressDialog.show(Display.this, "Parsing Data", "Please wait..........");
}
#Override
protected void onPostExecute(Void unused)
{
try
{
if(Dialog.isShowing())
{
Dialog.dismiss();
}
Intent intent=getIntent();
}
catch(Exception e)
{
Log.d("Onsitev4", "error");
}
}
#Override
protected Void doInBackground(Context... params) {
try {
LinearLayout layout1 = (LinearLayout) findViewById(R.id.linearLayout1);
//getting exception here. I dont understant why
// I have declared layout params and displaying activities in another class
ButtonView c = new ButtonView();
c.layout=layout1;
c.context =getBaseContext();
DbCoreSqlSurveys surveys=new DbCoreSqlSurveys(getBaseContext());
Document doc =surveys.getSurveySet();
surveyquestions= GetSurveyLevels(doc,c );
} catch (TransformerFactoryConfigurationError e) {
e.printStackTrace();
}
return null;
}
}
public SurveyObject[] GetSurveyLevels(Document doc, ButtonView c) {
NodeList nlQuestions = doc.getElementsByTagName("Survey");
SurveyObject[] allsurveys = new SurveyObject[nlQuestions.getLength()];
for (int i = 0; i < nlQuestions.getLength(); i++){
Node survey = nlQuestions.item(i);
String f =survey.getNodeName();
Log.d("OnsiteV4", "survey " + f);
NodeList surveyChildNodes = survey.getChildNodes();
SurveyObject s=new SurveyObject();
for (int j = 0; j < surveyChildNodes.getLength(); j++){
Node surveyChild = surveyChildNodes.item(j);
String h =surveyChild.getNodeName();
Log.d("OnsiteV4", "survey child node = " + h);
if (h !="#text"){
Surveys t = Surveys.valueOf(h);
switch(t){
case KeySurvey:
s.KeySurvey=surveyChild.getTextContent();
displaySurveyLink(s.SurveyDescription,"",c,0,s.SurveyDescription,"","","","");
break;
case SurveyDescription:
s.SurveyDescription=surveyChild.getTextContent();
displaySurveyLink(s.SurveyDescription,"",c,0,s.SurveyDescription,"","","","");
break;
case SurveyUserCode:
s.SurveyUserCode=surveyChild.getTextContent();
break;
case Level1:
if(surveyChild.hasChildNodes()){
s.Level1= processLevel1Nodes(surveyChild,c,s.SurveyDescription);
}
break;
default:
break;
}
}
allsurveys[i]=s;
}
}
return allsurveys;
}
// methods iterating through levels that is not showed
private void displaySurveyLink(final String description, String tag, ButtonView c, int indentation, final String surveyDescription, final String level1description, final String level2description, final String level3description, final String level4description)
{
if (description == null || tag == null){
return;
}
final TextView tv = c.addButton(description,tag,indentation);
tv.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
final Intent intent = new Intent();
intent.setClass(v.getContext(),ActivityB.class);
intent.putExtra("KeyLevel",tv.getTag().toString());
intent.putExtra("SurveyDescription",surveyDescription);
intent.putExtra("level1description",level1description);
intent.putExtra("level2description",level2description);
intent.putExtra("level3description",level3description);
intent.putExtra("level4description",level4description);
intent.putExtra("Description",description);
if (tv.getTag() != null){
if (tv.getTag().toString() != ""){
startActivity(intent);
}
}
}
});
}
}
I am getting exception in doinbackground. I am confused . please help me..
You are getting an exception because you are accessing UI elements on a non-UI thread. The main thread that the application creates is the UI thread, and that's where all of your visual elements are created and therefore the only thread in which you should access them.
To appropriately use AsyncTask, you run your long-running operations in doInBackground, and you use onPreExecute, onPostExecute and onProgressUpdated to work with the UI (show/hide progress dialogs, update views, etc). Whenever I use an AsyncTask and I want to show progress, I override onProgressUpdated giving it parameter type Integer and I call publishProgress from doInBackground. This would require a change of the base class signature from AsyncTask<Context,Void,Void> to AsyncTask<Context,Integer,Void>. You can use other object types for this as well...I just use Integer as an example if you want to show the percentage of the task that is complete, for example.
It's becoz your code should throwing exception as you are doing UI stuff in the doinbackgound of asyc task. Please remove all the UI related work from doingbackgound method.
I have an Activity where a user types in an EditText, hits a search button, and the app queries a web service and places the results in a ListView.
I'd like to do away with the search button.
Obviously I don't want every character the user types to hit the web service. I want to only execute 1 web service call when the user is finished typing.
The way I'm achieving this is like so:
I have a member variable which holds an AsyncTask. When the text in the EditText changes, the AsyncTask fires. Inside doInBackground(), a call to Thread.sleep() is hit. This sleep period is essentially a timer waiting to see if the user types anything else. After the sleep call, the call to the web service is made if the AsyncTask has not been cancelled. If the user types another letter, cancel() is called on the AsyncTask (to stop the web service from being called), the member variable holding the AsyncTask is set to null, and a new instance of the AsyncTask is created.
I have a few questions here: Am I leaking memory? Is this particularly bad in any way? I understand it may not be most efficient, but am I going to seriously slow down someone's phone? Is there a better way of doing this?
private SearchTask mSearchTask = null;
...
mSearchText.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Auto-generated method stub
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// Auto-generated method stub
}
public void afterTextChanged(Editable s) {
if (s != null && s.length() > 0) {
// stop any current search thread
if (mSearchTask != null && !mSearchTask.isCancelled()) {
mSearchTask.cancel(false);
}
// search for products
SearchCriteria crit = new SearchCriteria();
crit.strSearchWord = mSearchText.getText().toString().trim();
mSearchTask = null;
mSearchTask = new SearchTask();
mSearchTask.execute(crit);
}
}
});
...
private class SearchTask extends AsyncTask<SearchCriteria, Integer, Boolean> {
protected Boolean doInBackground(SearchCriteria... params) {
SearchCriteria crit = null;
if (params.length > 0) {
crit = params[0];
if (crit != null) {
try {
Thread.sleep(1000L);
if (!isCancelled()) {
// perform search
return true;
}
}
catch(Exception e) {
}
}
}
return false;
}
protected void onPostExecute(Boolean success) {
if (success != null && success == true) {
// do something
}
else {
// do something else
}
}
}
I would be more tempted to launch a thread in x milliseconds and do the check then, as opposed to launching the thread immediately with a sleep in there.
private Handler mMessageHandler = new Handler();
private Runnable mSearchRunnable = new Runnable() {
public void run() {
if (!isCancelled()) {
// perform search
}
}
};
then you can put this in you afterTextChanged:
mMessageHandler.postDelayed(mSearchRunnable, 1000);
you can then cancel the thread if the user enters more data with:
mMessageHandler.removeCallbacks(mSearchRunnable);
You should think about calling cancel(true) to try to shutdown the task while it is waiting or if the call to the webserver is running already. That might save you some process-cycles tho your webserver could be unamused about the broken calls.
If you want to save some gc-cycles you could reuse your SearchCriteria object if that is possible.
Apart from this I can't see any memory leaks. Your objects have short lifecycles and you don't cache them. The only problem that might arise is too many parallel AsyncTasks with running http-requests which will cause an early out of memory. We had that problem once with one app during the monkey-test.
hi this is the link which may be helps you..
http://thinkandroid.wordpress.com/2010/02/08/writing-your-own-autocompletetextview/
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
lv1 = (ListView) findViewById(R.id.ListView01);
ed = (AutoCompleteTextView) findViewById(R.id.EditTextSearch);
// AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.autocomplete_country);
ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(this, R.layout.list_item, countryName);
ed.setAdapter(adapter1);
this.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
final List<HashMap<String, String>> fillMaps = new ArrayList<HashMap<String, String>>();
for (int i = 0; i < countryName.length; i++) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("flag", "" + imageId[i]);
map.put("country", countryName[i].toString());
map.put("capital", capitalName[i].toString());
map.put("countrytime",
convertDateTimeToGMT(GMTplusMinusInMillisecond[i],
plusMinus[i]));
map.put("GMT", GMTplusMinus[i].toString());
fillMaps.add(map);
}
// fill in the grid_item layout
SimpleAdapter adapter = new SimpleAdapter(this, fillMaps,
R.layout.grid_item, from, to);
lv1.setAdapter(adapter);
ed.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
public void onTextChanged(CharSequence s, int start, int before,
int count) {
fillMaps.clear();
textlength = ed.getText().length();
for (int i = 0; i < countryName.length; i++) {
if (textlength <= countryName[i].length()) {
if (ed.getText()
.toString()
.equalsIgnoreCase(
(String) countryName[i].subSequence(0,
textlength))) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("flag", "" + imageId[i]);
map.put("country", countryName[i].toString());
map.put("capital", capitalName[i].toString());
map.put("countrytime",
convertDateTimeToGMT(
GMTplusMinusInMillisecond[i],
plusMinus[i]));
map.put("GMT", GMTplusMinus[i].toString());
fillMaps.add(map);
}
}
}
if(!fillMaps.isEmpty())
{
SimpleAdapter adapter = new SimpleAdapter(
WorldClockActivity.this, fillMaps, R.layout.grid_item,
from, to);
lv1.setAdapter(adapter);
}
else
{ String[] COUNTRIES = new String[] {"No record found"};
lv1.setAdapter(new ArrayAdapter<String>(WorldClockActivity.this,R.layout.list_item, COUNTRIES));
}
// lv1.setAdapter(new
// ArrayAdapter<String>(WorldClockActivity.this,android.R.layout.simple_list_item_1
// , arr_sort));
}
});
}
public static String convertDateTimeToGMT(long millis, int plusMinus) {
Calendar CalGMT;
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
CalGMT = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
CalGMT.get(Calendar.DAY_OF_MONTH);
CalGMT.get(Calendar.MONTH);
CalGMT.get(Calendar.YEAR);
CalGMT.get(Calendar.HOUR_OF_DAY);
CalGMT.get(Calendar.MINUTE);
CalGMT.get(Calendar.SECOND);
if (plusMinus == 1) {
CalGMT.setTimeInMillis(CalGMT.getTimeInMillis() + millis);
} else if (plusMinus == 0) {
CalGMT.setTimeInMillis(CalGMT.getTimeInMillis() - millis);
}
String sendDateTimeInGMT = CalGMT.get(Calendar.HOUR_OF_DAY) + ":"
+ CalGMT.get(Calendar.MINUTE) + ":"
+ CalGMT.get(Calendar.SECOND);
return sendDateTimeInGMT;
}
}
I have done the application using the above code in this application i have use AutoCompleteTextView for provide search facility in list view then list view show the name of all the country and user able to search country by country name when user type in AutoCompleteTextView then related search is show in listview.
Ex if user want to search Canada in the world country list then user only type ca in AutoCompleteTextView then a another list is appear blow the AutoCompleteTextView and show the all country name start ca name then user chose Canada in this list then get the all information of Canada in listview.