设置可见性上的三星 G5 空指针异常
Samsung G5 nullpointerexception on setvisibility
Android 应用程序代码可在各种设备上成功运行,包括早至 API 14 到 API 19(目标)。但是,三星 G5 v4.4.4 在尝试为 activity 设置 Visibilty(true) 时抛出 NPE。此错误可能只是在最近通过从 Sprint 下载升级 G5 操作系统后才开始出现。我们审查了多种 NPE 问题和三星特定问题,但 none 似乎适用。
日志:
01-08 20:58:40.122: W/dalvikvm(7972): threadid=1: thread exiting with uncaught exception (group=0x41963da0)
01-08 20:58:40.132: W/System.err(7972): java.lang.NullPointerException
01-08 20:58:40.132: W/System.err(7972): at android.app.Activity.makeVisible(Activity.java:4355)
01-08 20:58:40.142: W/System.err(7972): at android.app.Activity.setVisible(Activity.java:4336)
01-08 20:58:40.142: W/System.err(7972): at com.taskassure.app.StartTaskActivity.setActivityVisible(StartTaskActivity.java:531)
01-08 20:58:40.142: W/System.err(7972): at com.taskassure.app.StartTaskActivity.access(StartTaskActivity.java:529)
01-08 20:58:40.142: W/System.err(7972): at com.taskassure.app.StartTaskActivity.run(StartTaskActivity.java:298)
01-08 20:58:40.142: W/System.err(7972): at android.os.Handler.handleCallback(Handler.java:733)
01-08 20:58:40.142: W/System.err(7972): at android.os.Handler.dispatchMessage(Handler.java:95)
01-08 20:58:40.142: W/System.err(7972): at android.os.Looper.loop(Looper.java:146)
01-08 20:58:40.142: W/System.err(7972): at android.app.ActivityThread.main(ActivityThread.java:5678)
01-08 20:58:40.142: W/System.err(7972): at java.lang.reflect.Method.invokeNative(Native Method)
01-08 20:58:40.152: W/System.err(7972): at java.lang.reflect.Method.invoke(Method.java:515)
01-08 20:58:40.152: W/System.err(7972): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
01-08 20:58:40.152: W/System.err(7972): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
01-08 20:58:40.152: W/System.err(7972): at dalvik.system.NativeStart.main(Native Method)
审查 StartTaskActivity 确认我们正在尝试在抛出异常时将可见性设置为 true。相关代码段包括:
将启动失败的活动 activity (StartTaskActivity):
/**
* The intent to open the task start confirm dialog. Put in globalspace so
* that data can be added to it from anywhere in this class.
*/
public intent confirmActivity = null;
/**
* Sets up the tab view showing the task details and checkpoints, as well as
* setting up the location client to get the most recent location.
*/
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.view_task_activity);
// Set up the action bar.
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
...
// initialize confirmActivity so we can add the necessary
// information from our fragments
confirmActivity = new Intent(getApplicationContext(),
StartTaskActivity.class);
}
将启动 StartTaskActivity
的 class 中的相关方法
/**
* Sends a request to start the task to the server, gets back any checkpoint
* warnings that need to be overridden before we can start the task. Upon
* overriding any warnings (if any) The StartTaskActivity is launched.
*/
private void requestTaskStart()
{
...
try
{
JSONObject JsonResponse = new JSONObject(responseBody);
JSONArray checkpoints = (JSONArray) JsonResponse
.get("chekpoint_status");
JSONObject userData = new JSONObject(getIntent().getExtras()
.getString("user"));
userData = userData.getJSONObject("user");
confirmActivity.putExtra("training_set_size", new JSONObject(
getIntent().getExtras().getString("user"))
.getInt("training_set_size"));
confirmActivity.putExtra("requestStartInfo",
responseBody);
confirmActivity.putExtra("user_id",
Integer.parseInt(userData.getString("id")));
confirmActivity.putExtra("taskId", task.getInt("id"));
mDialog.dismiss();
// show checkpoint override if there are any
if ( checkpoints.length() != 0 )
{
// show first checkpoint dialog
showCheckpointDialog(checkpoints, 0);
}
else
{
startActivityForResult(confirmActivity,
CONFIRM_TASK_START);
}
StartTaskActivity - activity class 在三星 G5 上抛出 NPE
/**
* Activity that is shown after choosing to start a task. Shows the confirmation
* window before a task is started. This activity also handles starting face
* verification if necessary.
*/
public class StartTaskActivity extends Activity
{
...
/**
* Creates the task confirm screen, downloads the users photo from the server.
* Checks the task checkpoints to see if face verification needs to be done
* before starting the task. Keeps the activity invisible until all
* checkpoints are properly met.
*/
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.start_task_confirm_layout);
Intent launchIntent = getIntent();
Bundle args = launchIntent.getExtras();
try
{
requestTaskStartData = new JSONObject(args.getString("requestStartInfo"));
taskCheckpoints = new JSONArray(args.getString("checkpoints"));
taskId = args.getInt("taskId");
((TextView) findViewById(R.id.task_confirm_textview))
.setText(requestTaskStartData.getString("task_summary"));
new Thread(new Runnable()
{
@Override
public void run()
{
...
// code retrieves an image file from server on separate thread
// depending on results, call checkVerifyIdentity for additional processing and to show view
...
checkVerifyIdentity(bmp)
}).start();
((TextView) findViewById(R.id.task_password_content_textview))
.setText(requestTaskStartData.getString("task_password"));
}
catch ( JSONException e )
{
((TextView) findViewById(R.id.task_password_title_textview))
.setVisibility(TextView.INVISIBLE);
e.printStackTrace();
}
findViewById(R.id.task_confirm_button).setOnClickListener(
new View.OnClickListener()
{
@Override
public void onClick(View v)
{
setResult(RESULT_OK);
finish();
}
});
findViewById(R.id.task_deny_button).setOnClickListener(
new View.OnClickListener()
{
@Override
public void onClick(View v)
{
setResult(RESULT_CANCELED);
finish();
}
});
} // end of StartTaskActivity.onCreate
...
// Check some parameters, and finish setting up view for display (runs on UI thread)
private void checkVerifyIdentity(final Bitmap bmp)
{
final Context context = this;
StartTaskActivity.this.runOnUiThread(new Runnable()
{
public void run()
{
if ( bmp != null )
{
((ImageView) findViewById(R.id.task_confirm_imageview))
.setImageBitmap(bmp);
}
if ( taskCheckpoints.length() > 0 )
{
... // do some processing
}
else
{
setActivityVisible();
}
}
});
}
...
/**
* Sets the activity as visible. Should be called once all verifications are
* properly checked.
*/
private void setActivityVisible()
{
this.setVisible(true);
}
上面的 setVisible 行是 StartTaskActivity 的第 531 行,它最终导致三星 G5 的 NPE,但不是我们可以测试的其他 devices/versions。正如评论中所反映的那样,随后在 4.4.4 模拟器上进行的测试无法重现该错误。 到目前为止,仅在 4.4.4 的实际三星 G5 上观察到错误。
更新:
基于 labor intensive debug step process 将良好的源视图(4.4.4 模拟器)与三星不正确的源视图进行映射,我们缩小了 NPE 的原因。应用程序在调用 StartTaskActivity.setActivityVisible 时抛出 NPE,最终遇到空对象。由于跟踪过程的限制,我无法确定那个对象是什么,但我的猜测是它是窗口或视图。抛出它的代码行是“mDecor.setVisibility(View.VISIBLE)”(三星中的第 4355 行 = Activity.java 的模拟器中的第 4143 行)。因此,从技术上讲,mDecor 对象的某些部分是空的。
可能会采取不同的方法来实现我们的目标,因为我们无法确定为什么 Samsung v4.4.4 抛出 NPE 而其他 device/emulator 似乎没有抛出 NPE,包括 Samsung v4.4.2。也许即使这个问题没有得到解决,但它可能对将来的其他人有用。
花费了大量时间试图找出此问题的原因。我们无法在除 Samsung G5 (Sprint) 运行 4.4.4 之外的任何其他设备或模拟器上重现 NPE 异常。当尝试在 activity 上使用 setVisible 方法时发生崩溃,该方法从 onCreate 中启动了后台线程,然后启动了 runsOnUiThread。也许这是一种不正确的做法,出于某种原因没有受到其他系统的困扰,但三星(至少)认为这是不可接受的。
无论如何,我们通过 showing/hiding 与 activity 关联的视图(例如使用 v.setVisibility(View.VISIBLE)
和一些有价值的重构来解决这个问题。如 Android 文档,请谨慎使用 Activity#setVisible 方法。
Android 应用程序代码可在各种设备上成功运行,包括早至 API 14 到 API 19(目标)。但是,三星 G5 v4.4.4 在尝试为 activity 设置 Visibilty(true) 时抛出 NPE。此错误可能只是在最近通过从 Sprint 下载升级 G5 操作系统后才开始出现。我们审查了多种 NPE 问题和三星特定问题,但 none 似乎适用。
日志:
01-08 20:58:40.122: W/dalvikvm(7972): threadid=1: thread exiting with uncaught exception (group=0x41963da0)
01-08 20:58:40.132: W/System.err(7972): java.lang.NullPointerException
01-08 20:58:40.132: W/System.err(7972): at android.app.Activity.makeVisible(Activity.java:4355)
01-08 20:58:40.142: W/System.err(7972): at android.app.Activity.setVisible(Activity.java:4336)
01-08 20:58:40.142: W/System.err(7972): at com.taskassure.app.StartTaskActivity.setActivityVisible(StartTaskActivity.java:531)
01-08 20:58:40.142: W/System.err(7972): at com.taskassure.app.StartTaskActivity.access(StartTaskActivity.java:529)
01-08 20:58:40.142: W/System.err(7972): at com.taskassure.app.StartTaskActivity.run(StartTaskActivity.java:298)
01-08 20:58:40.142: W/System.err(7972): at android.os.Handler.handleCallback(Handler.java:733)
01-08 20:58:40.142: W/System.err(7972): at android.os.Handler.dispatchMessage(Handler.java:95)
01-08 20:58:40.142: W/System.err(7972): at android.os.Looper.loop(Looper.java:146)
01-08 20:58:40.142: W/System.err(7972): at android.app.ActivityThread.main(ActivityThread.java:5678)
01-08 20:58:40.142: W/System.err(7972): at java.lang.reflect.Method.invokeNative(Native Method)
01-08 20:58:40.152: W/System.err(7972): at java.lang.reflect.Method.invoke(Method.java:515)
01-08 20:58:40.152: W/System.err(7972): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
01-08 20:58:40.152: W/System.err(7972): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
01-08 20:58:40.152: W/System.err(7972): at dalvik.system.NativeStart.main(Native Method)
审查 StartTaskActivity 确认我们正在尝试在抛出异常时将可见性设置为 true。相关代码段包括:
将启动失败的活动 activity (StartTaskActivity):
/**
* The intent to open the task start confirm dialog. Put in globalspace so
* that data can be added to it from anywhere in this class.
*/
public intent confirmActivity = null;
/**
* Sets up the tab view showing the task details and checkpoints, as well as
* setting up the location client to get the most recent location.
*/
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.view_task_activity);
// Set up the action bar.
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
...
// initialize confirmActivity so we can add the necessary
// information from our fragments
confirmActivity = new Intent(getApplicationContext(),
StartTaskActivity.class);
}
将启动 StartTaskActivity
的 class 中的相关方法/** * Sends a request to start the task to the server, gets back any checkpoint * warnings that need to be overridden before we can start the task. Upon * overriding any warnings (if any) The StartTaskActivity is launched. */
private void requestTaskStart()
{
...
try
{
JSONObject JsonResponse = new JSONObject(responseBody);
JSONArray checkpoints = (JSONArray) JsonResponse
.get("chekpoint_status");
JSONObject userData = new JSONObject(getIntent().getExtras()
.getString("user"));
userData = userData.getJSONObject("user");
confirmActivity.putExtra("training_set_size", new JSONObject(
getIntent().getExtras().getString("user"))
.getInt("training_set_size"));
confirmActivity.putExtra("requestStartInfo",
responseBody);
confirmActivity.putExtra("user_id",
Integer.parseInt(userData.getString("id")));
confirmActivity.putExtra("taskId", task.getInt("id"));
mDialog.dismiss();
// show checkpoint override if there are any
if ( checkpoints.length() != 0 )
{
// show first checkpoint dialog
showCheckpointDialog(checkpoints, 0);
}
else
{
startActivityForResult(confirmActivity,
CONFIRM_TASK_START);
}
StartTaskActivity - activity class 在三星 G5 上抛出 NPE
/**
* Activity that is shown after choosing to start a task. Shows the confirmation
* window before a task is started. This activity also handles starting face
* verification if necessary.
*/
public class StartTaskActivity extends Activity
{
...
/**
* Creates the task confirm screen, downloads the users photo from the server.
* Checks the task checkpoints to see if face verification needs to be done
* before starting the task. Keeps the activity invisible until all
* checkpoints are properly met.
*/
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.start_task_confirm_layout);
Intent launchIntent = getIntent();
Bundle args = launchIntent.getExtras();
try
{
requestTaskStartData = new JSONObject(args.getString("requestStartInfo"));
taskCheckpoints = new JSONArray(args.getString("checkpoints"));
taskId = args.getInt("taskId");
((TextView) findViewById(R.id.task_confirm_textview))
.setText(requestTaskStartData.getString("task_summary"));
new Thread(new Runnable()
{
@Override
public void run()
{
...
// code retrieves an image file from server on separate thread
// depending on results, call checkVerifyIdentity for additional processing and to show view
...
checkVerifyIdentity(bmp)
}).start();
((TextView) findViewById(R.id.task_password_content_textview))
.setText(requestTaskStartData.getString("task_password"));
}
catch ( JSONException e )
{
((TextView) findViewById(R.id.task_password_title_textview))
.setVisibility(TextView.INVISIBLE);
e.printStackTrace();
}
findViewById(R.id.task_confirm_button).setOnClickListener(
new View.OnClickListener()
{
@Override
public void onClick(View v)
{
setResult(RESULT_OK);
finish();
}
});
findViewById(R.id.task_deny_button).setOnClickListener(
new View.OnClickListener()
{
@Override
public void onClick(View v)
{
setResult(RESULT_CANCELED);
finish();
}
});
} // end of StartTaskActivity.onCreate
...
// Check some parameters, and finish setting up view for display (runs on UI thread)
private void checkVerifyIdentity(final Bitmap bmp)
{
final Context context = this;
StartTaskActivity.this.runOnUiThread(new Runnable()
{
public void run()
{
if ( bmp != null )
{
((ImageView) findViewById(R.id.task_confirm_imageview))
.setImageBitmap(bmp);
}
if ( taskCheckpoints.length() > 0 )
{
... // do some processing
}
else
{
setActivityVisible();
}
}
});
}
...
/**
* Sets the activity as visible. Should be called once all verifications are
* properly checked.
*/
private void setActivityVisible()
{
this.setVisible(true);
}
上面的 setVisible 行是 StartTaskActivity 的第 531 行,它最终导致三星 G5 的 NPE,但不是我们可以测试的其他 devices/versions。正如评论中所反映的那样,随后在 4.4.4 模拟器上进行的测试无法重现该错误。 到目前为止,仅在 4.4.4 的实际三星 G5 上观察到错误。
更新:
基于 labor intensive debug step process 将良好的源视图(4.4.4 模拟器)与三星不正确的源视图进行映射,我们缩小了 NPE 的原因。应用程序在调用 StartTaskActivity.setActivityVisible 时抛出 NPE,最终遇到空对象。由于跟踪过程的限制,我无法确定那个对象是什么,但我的猜测是它是窗口或视图。抛出它的代码行是“mDecor.setVisibility(View.VISIBLE)”(三星中的第 4355 行 = Activity.java 的模拟器中的第 4143 行)。因此,从技术上讲,mDecor 对象的某些部分是空的。
可能会采取不同的方法来实现我们的目标,因为我们无法确定为什么 Samsung v4.4.4 抛出 NPE 而其他 device/emulator 似乎没有抛出 NPE,包括 Samsung v4.4.2。也许即使这个问题没有得到解决,但它可能对将来的其他人有用。
花费了大量时间试图找出此问题的原因。我们无法在除 Samsung G5 (Sprint) 运行 4.4.4 之外的任何其他设备或模拟器上重现 NPE 异常。当尝试在 activity 上使用 setVisible 方法时发生崩溃,该方法从 onCreate 中启动了后台线程,然后启动了 runsOnUiThread。也许这是一种不正确的做法,出于某种原因没有受到其他系统的困扰,但三星(至少)认为这是不可接受的。
无论如何,我们通过 showing/hiding 与 activity 关联的视图(例如使用 v.setVisibility(View.VISIBLE)
和一些有价值的重构来解决这个问题。如 Android 文档,请谨慎使用 Activity#setVisible 方法。