关于setvisibility的三星G5 nullpointerexception

时间:2015-01-09 14:32:28

标签: java android nullpointerexception

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。相关代码的细分包括:

将启动失败活动的活动(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

的类中的相关方法
  

/ **       *向服务器发送启动任务的请求,返回任何检查点       *在我们开始任务之前需要覆盖的警告。上       *覆盖任何警告(如果有)启动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);
            }

StartTaskActivity - 在Samsung 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,但不是我们可以测试的其他设备/版本。正如注释中所反映的,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。也许即使这个问题尚未解决,但未来可能对其他人有用。

1 个答案:

答案 0 :(得分:2)

花费了大量时间试图找出此问题的原因。除了运行4.4.4的三星G5(Sprint)之外,我们无法在任何其他设备或仿真器上重现NPE例外。尝试对onCreate中启动了后台线程的活动使用setVisible方法时会发生崩溃,然后启动runsOnUiThread。也许这是一种不正当的做法,由于某些原因并没有受到其他系统的困扰,但三星(至少)认为这是不可接受的。

在任何情况下,我们通过显示/隐藏与活动相关联的视图来解决此问题(使用例如v.setVisibility(View.VISIBLE)和一些有价值的重构。如Android文档所示,请谨慎使用Activity #setVisible方法。< / p>