I've got an app that makes API calls when the user logs in, I've got two classes, one that Pushes to the API and one that Pulls from it. I've also got an asyncTask on my LogIn Activity which handles the network connection. When the network connection starts I have a view switcher to switch the view to a progress loader and a textview, the textview is used to display stuff like "Connecting", "Downloading Data", ect.
The problem is my API Push and Pull methods are stored in different classes and the LogIn AsyncTask simply calls them, it all works except for updating the TextView to let the user know the progress.
In the LogIn activity, I have this method, which changes the textview info to whichever number is passed to it.
public void updateProgress(int i) {
switch (i) {
case 0:
loadInfo.setText(R.string.log_in_thread_Connecting);
break;
case 1:
loadInfo.setText(R.string.log_in_thread_Connected);
break;
case 2:
loadInfo.setText(R.string.log_in_Thread_Sending_Data);
break;
case 3:
loadInfo.setText(R.string.log_in_thread_Response);
break;
case 4:
loadInfo.setText(R.string.log_in_web_connecting);
break;
case 5:
loadInfo.setText(R.string.log_in_web_connected);
break;
case 6:
loadInfo.setText(R.string.log_in_web_user_data_download);
break;
case 7:
loadInfo.setText(R.string.log_in_web_user_data_downloaded);
break;
case 8:
loadInfo.setText(R.string.log_in_web_device_data_upload);
break;
}
}
This works if i'm calling it from the AsyncTask from the LogIn Activity but not from the API classes.
I have found a method called .runOnUiThread so I tried to implement that.
private void publishProgress(final int i){
logInActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
logInActivity.updateProgress(i);
Log.d("UI THREAD","HIT");
}
});
}
This is what I have come up with, but it doesn't seem to be hitting, I don't even see the Log post.
I did also have an error implementing this but it was resolved when I added Looper.prepare(); to the Log in AsyncTask
AsyncTask
private class RegistrationWeb extends AsyncTask<Void,Void,Void>{
private static final String tag = "API_LogIn";
private String APIKey = null
#Override
protected void onPreExecute() {
super.onPreExecute();
viewFlipper.showNext();
APIKey = getAPIKey();
}
#Override
protected Void doInBackground(Void... voids) {
try{
Looper.prepare();
GetAPIData get = new GetAPIData();
URL url = new URL(API_Register_User+APIKey);
String response = get.GetData(url);
JSONArray jsonArray = new JSONArray(response);
JSONObject jsonObject = jsonArray.getJSONObject(0);
//If the user is accepted
if(jsonObject.getString("_Code").equals("0")){
PublishProgress(8);
PostAPIData post = new PostAPIData();
url = new URL(API_Register_Device);
response = post.PostData(url);
jsonArray = new JSONArray(response);
jsonObject = jsonArray.getJSONObject(0);
} else if(jsonObject.getString("_Code").equals("2")){
}
} catch (MalformedURLException e) {
Log.e(tag,e.toString());
} catch (JSONException e) {
Log.e(tag,e.toString());
} catch (IOException e) {
Log.e(tag,e.toString());
}
return null;
}
private void PublishProgress(final int i){
runOnUiThread(new Runnable() {
#Override
public void run() {
updateProgress(i);
}
});
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
}
}
You can not directly access string that are present in resource, you will have to to acquire resources first to use its content. You need to call getResources() from your Activity, then you can get the string you are looking for.
YourActivity.context.getResources().getString(R.string.id_name);
Override onProgressUpdate() and then call publishProgress()
public void publishProgress(Integer v) {
Message message = new Message();
message.what = v;
YourActivity.handler.sendMessage(message);
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
publishProgress(values[0);
}
And change your AsyncTask parameter during its creation from Void to Integer
class RegistrationWeb extends AsyncTask<Integer,Integer,Integer> {
}
In your Activity where your TextView resides on which you want update, make Handler to listen the messages from outer class and in that Handler update your TextView.
Activity:
public static Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
//update your text view on the basis of msg.what
}
}
};
Note : Make your TextView loadInfo as static
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.
One of my app's activities has ran into an issue; the problem seems to be an asynk-task, which get information from the server and generate a list of n elements in a view using that data, this, get the activity stuck in the white load screen instead of rendering the view.
No crashes or errors.
I can press back button and return to previous activity(Not freeze).
Android monitor show no cpu usage.
Here is the code.Is called at the end of onCreate()
new AsyncTask() {
#Override
protected void onPreExecute() {
mProgressDialog.show();
}
#Override
protected Object doInBackground(Object[] params) {
Document dom = null;
Detalle detalle= getIntent().getParcelableExtra("pedido");
try {
dom=DetalleToXml.getDom(detalle);
} catch (Exception e) {
e.printStackTrace();
}
return dom;
}
protected void onPostExecute(Object o) {
Document dom = (Document)o;
mProgressDialog.dismiss();
TableLayout t = (TableLayout) contentView.findViewById(R.id.grid_layout_pedido);
t.removeAllViewsInLayout();
final NodeList rows = dom.getElementsByTagName("row");
if(rows.getLength() == 0) {
Toast.makeText(DetallesPedido.this, "La búsqueda no ha tenido resultados.", Toast.LENGTH_SHORT).show();
}else{
for(int i = 0; i < rows.getLength(); i++){
Element e = (Element)rows.item(i);
LayoutInflater inflater = LayoutInflater.from(getBaseContext());
String rowid = UtilesDom.getValue(e, "rowid");
String articulo = UtilesDom.getValue(e, "articulo");
String precio_venta = UtilesDom.getValue(e, "precio_venta");
String cantidad = UtilesDom.getValue(e, "cantidad");
String descripcion = UtilesDom.getValue(e, "descripcion");
LinearLayout bigRow=(LinearLayout)inflater.inflate(R.layout.pedido_detalle,null);
TextView tv=(TextView) bigRow.findViewById(R.id.detalle_row_textView1);
tv.setText(articulo);
tv=(TextView) bigRow.findViewById(R.id.detalle_row_textView3);
tv.setText(precio_venta);
tv=(TextView) bigRow.findViewById(R.id.detalle_row_textView2);
tv.setText(cantidad);
tv=(TextView) bigRow.findViewById(R.id.detalle_row_textView4);
tv.setText(descripcion);
try {
bigRow.setId(Integer.parseInt(rowid));
} catch (Exception e2) {
e2.printStackTrace();
}
bigRow.setTag(articulo);
bigRow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String codigo = (String) v.getTag();
final Context context = v.getContext();
final int rowid = v.getId();
Intent intent = new Intent(context, DetalleFicha.class);
Bundle b = new Bundle(3);
b.putInt("rowid", rowid);
b.putInt("operation",UtilesABM.UPDATE);
b.putString("caller","DetallesPedido");
intent.putExtras(b);
intent.putExtra("pedido",getIntent().getParcelableExtra("pedido"));
loaded = false;
startActivity(intent);
}
}
);
//UtilesViews.setDefaultPadding(tv);
t.addView(bigRow);
}
}
super.onPostExecute(o);
}
}.execute(query);
By debugging i can reach the Loop.java class right after execute() and there is where gets stuck.
Any ideas of how to fix it or the cause of the problem?
You are performing very performance costly call
LinearLayout bigRow=(LinearLayout)inflater.inflate(R.layout.pedido_detalle,null);
which can take too much time, and since you are doing it in onPostExecute call, which is being called on main thread, so main thread will gets blocked if number of rows are huge and app becomes unresponsive
Solution to this is, you can use recycler view
My program crashs after doInBackground and doesn't come to onPostExecute.
My activity code's related parts are like this:
public static class News {
private String title;
private String content;
private Bitmap image;
public News(String nTitle, String nContent, Bitmap nImage){
title = nTitle;
content = nContent;
image = nImage;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_news);
final AsyncTask task = new DatabaseConnection(this, Method.GET_ALL_NEWS).execute();
try {
task.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public final void fillListView(List<News> news){
recentNews = news;
if(recentNews != null && !recentNews.isEmpty()){
((ListView)findViewById(R.id.lvNews)).setOnItemClickListener(this);
final int size = recentNews.size();
final String newsTitles[] = new String[size];
for(int i=0; i<size; ++i)
newsTitles[i] = recentNews.get(i).title;
((ListView)findViewById(R.id.lvNews)).setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, newsTitles));
}
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final News selectedNews = recentNews.get(position);
startActivity(new Intent(this, ANewsActivity.class)
.putExtra("title", selectedNews.title)
.putExtra("content", selectedNews.content)
.putExtra("image", BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)));
}
My AsyncTask code's related parts are like this:
public DatabaseConnection(Context nContext, Method nMethod){
method = nMethod;
context = nContext;
}
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(context);
progressDialog.setMessage(context.getString(R.string.database_connection_wait_message));
progressDialog.setTitle(R.string.database_connection_wait_title);
progressDialog.show();
}
#SuppressWarnings("incomplete-switch")
#Override
protected Void doInBackground(String... params) {
if(method != Method.NONE){
open();
try{
switch(method){
case GET_ALL_NEWS:
final ResultSet rs = conn.createStatement().executeQuery("select baslik, metin, resim from haberler");
news = new ArrayList<News>();
while(rs.next())
news.add(new News(rs.getString(1), rs.getString(2), BitmapFactory.decodeStream(rs.getBlob(3).getBinaryStream())));
break;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close();
}
}
return null;
}
#SuppressWarnings("incomplete-switch")
#Override
protected void onPostExecute(Void temp) {
if (progressDialog.isShowing()){
progressDialog.dismiss();
switch(method){
case GET_ALL_NEWS:
((NewsActivity)context).fillListView(news);
break;
}
method = Method.NONE;
}
}
I want UI thread waits until database operations finishes.
By the way there is no initialization problem at variables etc and database returns proper infos and my "news" variable is filled normally.
By the way again I realized it is WORKING on PHONE, STUCKS on EMULATOR interestingly (if I remove wait() method and its try-catch block on main thread code).
It's difficult to say what is crashing without the logcat output, but it would most likely be the main thread of the app because of the .wait() method you are calling in onCreate(). Your onCreate() cannot wait - it must initialize and exit, otherwise you are blocking the main thread of your app and defeating the purpose of the AsyncTask.
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>