我的应用程序通常运行正常,直到我在特定设备上遇到一个奇怪的问题。 App中有2项活动。在ActivityA中启动ActivityB后,ActivityA启动没有问题。但是,在我通过推回硬件按钮或调用finish()返回ActivityA之后;在ActivityB中的closeButton内部,ActivityA重新加载自身。它再次触发onCreate()并重新加载其所有内容。而且我没有改变手机的方向。这种奇怪的行为只出现在超过1.000下载app的15部手机中。
此问题仅发生在Galaxy S3 Android OS 4.1.2上。这也很奇怪。
你知道为什么会这样吗?
当我在按钮监听器中启动一个新的Activity时,如下所示:
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.
}
编辑:不仅这两项活动存在此问题,所有活动在某些手机上的行为也相同。
答案 0 :(得分:42)
检查设置&gt;下是否不要保留活动 系统&gt; 开发人员选项&gt; 应用已启用或未启用。
答案 1 :(得分:10)
活动文档(http://developer.android.com/reference/android/app/Activity.html)说明了关于后台活动生命周期的以下内容:
后台活动(用户看不到并且已暂停的活动)不再重要,因此系统可以安全地终止其进程以回收其他前景或可见进程的内存。如果需要杀死它的进程,当用户导航回活动(再次在屏幕上显示)时,将使用之前在onSaveInstanceState(Bundle)中提供的savedInstanceState调用其onCreate(Bundle)方法,以便它可以在用户上次离开的状态下重启自己。
换句话说,当ActivityB处于活动状态时,ActivityA可能会或可能不会被操作系统销毁,因此必须在代码中处理这种情况。如果ActivityA已被销毁,当用户按下ActivityB中的后退按钮时,将调用onCreate(Bundle)。
答案 2 :(得分:8)
有一个名为“不要保留活动”的Android开发人员设置。此选项的描述是“用户离开时立即销毁每个活动”。这听起来像是对你所看到的内容的一个很好的描述,并且因为你只是在几部手机上看到这个由非默认系统设置引起的想法似乎是合理的。
理想情况下,即使效果不佳,您的应用仍可在此方案中使用。但是,如果此设置对您的应用程序有疑问,您可能希望为您的用户记录此问题。
答案 3 :(得分:7)
您是否尝试更改Android Manifest中的launchmode
?尝试将此添加到您的活动声明中:
android:launchMode="singleTask"
接下来,尝试使用startActivityForResult
,而不是startActivity
。这将强制活动A在活动B完成时调用其onActivityResult(int, int, Intent)
方法 - 这可能会跳过对onCreate
的此(错误)调用。然后,在Activity A中,实现该方法以执行某些操作(例如打印调试语句):
@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?
}
答案 4 :(得分:5)
我认为这种行为没有任何问题。
如果您希望保留ActivityA
的状态,请使用方法onSaveInstanceState
和onRestoreInstanceState
。有关详细信息,请参阅http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle处的活动生命周期。
另请参阅https://stackoverflow.com/a/10492967/332210以获得更深入的了解。
答案 5 :(得分:2)
您可以尝试在onCreate()
中提供一个布局,然后在onStart()
中完成其余的工作?如果有效吗?
LIKE:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.show);
}
和
@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
Log.i(TAG, "On Start .....");
}
答案 6 :(得分:1)
也许你应该使用
Intent startIntent = new Intent(view.getContext(), ActivityB.class);
startActivity(startIntent);
finish() ;
和
Intent startIntent = new Intent(view.getContext(), ActivityA.class);
startActivity(startIntent);
finish() ;
每次你回去或前进。
答案 7 :(得分:1)
在android:launchMode="standard"
的{{1}} activity
中使用manifest
,它也面临着确切的问题并解决了问题。
答案 8 :(得分:1)
覆盖活动A中的onStart()和onResume方法,并检查问题是否仍然存在。如果可能的话,请在此处提供您的活动A和B代码。
答案 9 :(得分:1)
活动A使用布局R.layout.mesajlar_list
活动B使用布局R.layout.mesajdetaylari
但两者都有以下代码行:
kapatButton = (ImageView) findViewById(R.id.kapat_button);
哪个布局是R.id.kapat_button?在不同的布局中使用相同的id是一件非常危险的事情。我不能保证它会导致你所看到的东西,但这可能会导致奇怪的行为。
答案 10 :(得分:1)
我认为这不是因为记忆的极限。
https://www.box.com/s/7pd0as03bb8wwumuc9l9
您应该测试这两个活动,并检查它是否也在这个例子中发生。请分享您的AndroidManifest.xml文件内容,这将有助于调试。
答案 11 :(得分:0)
我最近遇到了这个问题,这让我很生气。我认为这个问题围绕2个选项解决方案来检查但没用。
关于设置&#34;不要保持活动&#34;在这里纠正,我使用此代码检查它是否可选检查(我的测试设备定制基于版本2.3.5并且不显示此选项):
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;
}
}
在我的情况下,结果检查是错误的。我还在运行应用程序时检查内存,但没有任何反应。
答案 12 :(得分:0)
您可以在清单中使用android:launchMode="singleTop"
。
<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>