Android应用程序代码可在各种设备上成功运行,包括早在API 14和API 19(目标)。但是,三星G5 v4.4.4在尝试为活动设置Visibilty(true)时会抛出NPE。此错误可能仅在最近升级G5 OS后才开始,通过从Sprint下载。我们已经审查了很多种NPE问题和三星特定问题,但似乎都没有适用。
日志:
01-08 20:58:40.122:W / dalvikvm(7972):threadid = 1:线程退出时未捕获异常(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):在android.app.Activity.makeVisible(Activity.java:4355)
01-08 20:58:40.142:W / System.err(7972):在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 $ 1(StartTaskActivity.java:529)
01-08 20:58:40.142:W / System.err(7972):at com.taskassure.app.StartTaskActivity $ 4.run(StartTaskActivity.java:298)
01-08 20:58:40.142:W / System.err(7972):在android.os.Handler.handleCallback(Handler.java:733)
01-08 20:58:40.142:W / System.err(7972):在android.os.Handler.dispatchMessage(Handler.java:95)
01-08 20:58:40.142:W / System.err(7972):在android.os.Looper.loop(Looper.java:146)
01-08 20:58:40.142:W / System.err(7972):在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。相关代码的细分包括:
/**
* 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。 * /
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);
}
/**
* 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,但不是我们可以测试的其他设备/版本。正如注释中所反映的,4.4.4仿真器上的后续测试无法复制错误。 到目前为止,仅在实际的三星G5 4.4.4上观察到错误。
基于labor intensive debug step process映射好的源视图(4.4.4仿真器)和三星不正确的源视图,我们已经缩小了NPE的原因。当应用程序调用StartTaskActivity.setActivityVisible时,它会抛出一个NPE,最终会运行到一个null对象。由于跟踪过程的限制,我不能肯定地确定该对象是什么,但我的猜测是它是窗口或视图。抛出它的代码行是“mDecor.setVisibility(View.VISIBLE)”(Samsung中的第4355行= Activity.java的Emulator中的第4143行)。因此,从技术上讲,mDecor对象的某些部分为空。
可能采取不同的方法来实现我们的目标,因为我们无法确定为什么三星v4.4.4在没有其他设备/仿真器时会抛出NPE,包括三星v4.4.2。也许即使这个问题尚未解决,但未来可能对其他人有用。
答案 0 :(得分:2)
花费了大量时间试图找出此问题的原因。除了运行4.4.4的三星G5(Sprint)之外,我们无法在任何其他设备或仿真器上重现NPE例外。尝试对onCreate中启动了后台线程的活动使用setVisible方法时会发生崩溃,然后启动runsOnUiThread。也许这是一种不正当的做法,由于某些原因并没有受到其他系统的困扰,但三星(至少)认为这是不可接受的。
在任何情况下,我们通过显示/隐藏与活动相关联的视图来解决此问题(使用例如v.setVisibility(View.VISIBLE)
和一些有价值的重构。如Android文档所示,请谨慎使用Activity #setVisible方法。< / p>