奇怪的分配,TextView到Bundle,反编译后,为什么?

我创build了一个简单的应用程序,一个计数器应用程序,按下一个button递增一个整数,并更新一个文本视图。 代码如下:

public class MainActivity extends Activity { public static int count = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final TextView textView = (TextView) findViewById(R.id.count); textView.setText(Integer.toString(count)); final Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { count++; textView.setText(Integer.toString(count)); } }); } ... } 

使用dex2jar和jd-gui反编译相同的应用后,我收到了以下代码:

 public class MainActivity extends Activity { public static int count = 0; protected void onCreate(final Bundle paramBundle) { super.onCreate(paramBundle); setContentView(2130903040); paramBundle = (TextView)findViewById(2131296257); paramBundle.setText(Integer.toString(count)); ((Button)findViewById(2131296256)).setOnClickListener(new View.OnClickListener() { public void onClick(View paramAnonymousView) { MainActivity.count += 1; paramBundle.setText(Integer.toString(MainActivity.count)); } }); } ... } 

在以下行上:

  paramBundle = (TextView)findViewById(2131296257); paramBundle.setText(Integer.toString(count)); 

系统如何将textview设置为paramBundle? 为什么会这样呢? paramBundle的types是Bundle,而TextView不是Bundle的子类,根据反编译的版本,更多的Bundle是最终的。 反编译出错了吗? 来自反编译器的信息是错误的,或者我们为什么得到这个结果?


编辑:

 # virtual methods .method protected onCreate(Landroid/os/Bundle;)V .locals 3 .param p1, "savedInstanceState" # Landroid/os/Bundle; .prologue .line 17 invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V .line 18 const/high16 v2, 0x7f030000 invoke-virtual {p0, v2}, Lcom/example/rawa/helloworld/MainActivity;->setContentView(I)V .line 20 const v2, 0x7f090001 invoke-virtual {p0, v2}, Lcom/example/rawa/helloworld/MainActivity;->findViewById(I)Landroid/view/View; move-result-object v1 check-cast v1, Landroid/widget/TextView; .line 21 .local v1, "textView":Landroid/widget/TextView; sget v2, Lcom/example/rawa/helloworld/MainActivity;->count:I invoke-static {v2}, Ljava/lang/Integer;->toString(I)Ljava/lang/String; move-result-object v2 invoke-virtual {v1, v2}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V .line 22 const/high16 v2, 0x7f090000 invoke-virtual {p0, v2}, Lcom/example/rawa/helloworld/MainActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/Button; .line 23 .local v0, "button":Landroid/widget/Button; new-instance v2, Lcom/example/rawa/helloworld/MainActivity$1; invoke-direct {v2, p0, v1}, Lcom/example/rawa/helloworld/MainActivity$1;-><init>(Lcom/example/rawa/helloworld/MainActivity;Landroid/widget/TextView;)V invoke-virtual {v0, v2}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V .line 30 return-void .end method 

我绝对不是小专家,只有新手。 但我使用apktool解码应用程序,并收到上述smali代码。 根据我的理解,savedinstance(paramBundle)被加载到p1(= v3)中并用于onCreate,并且在第20行或第21行中不会以任何方式使用。对于我来说,这是否意味着一个分解错误? 请记住,apktool允许再次构build应用程序,因此在反编译时不会丢失任何数据。

Solutions Collecting From Web of "奇怪的分配,TextView到Bundle,反编译后,为什么?"

原因是局部variables的types已经改变,但是一些反编译器无法正确处理它。

这里是你用dex2jar + javap反编译的onCreate代码:

  protected void onCreate(android.os.Bundle); Code: 0: aload_0 1: aload_1 2: invokespecial #20 // Method android/app/Activity.onCreate:(Landroid/os/Bundle;)V 5: aload_0 6: ldc #21 // int 2130903040 8: invokevirtual #25 // Method setContentView:(I)V 11: aload_0 12: ldc #26 // int 2131230720 14: invokevirtual #30 // Method findViewById:(I)Landroid/view/View; 17: checkcast #32 // class android/widget/TextView 20: astore_1 21: aload_1 22: getstatic #12 // Field count:I 25: invokestatic #38 // Method java/lang/Integer.toString:(I)Ljava/lang/String; 28: invokevirtual #42 // Method android/widget/TextView.setText:(Ljava/lang/CharSequence;)V 31: aload_0 32: ldc #43 // int 2131230721 34: invokevirtual #30 // Method findViewById:(I)Landroid/view/View; 37: checkcast #45 // class android/widget/Button 40: new #6 // class com/example/test/MainActivity$1 43: dup 44: aload_0 45: aload_1 46: invokespecial #48 // Method com/example/test/MainActivity$1."<init>":(Lcom/example/test/MainActivity;Landroid/widget/TextView;)V 49: invokevirtual #52 // Method android/widget/Button.setOnClickListener:(Landroid/view/View$OnClickListener;)V 52: return 

这里aload_0是MainActivity对象的局部variables, aload_1是Bundle对象的局部variables。 问题的根源是代码#20, 它将刚刚检索的TextView对象的引用存储到本地variables1astore_1 )中,该variables先前存储了Bundle对象!

这是因为Bundle对象不用于其余的方法,因此重用局部variables而不是新variables会更有效率。 但是这也意味着反编译器需要花费更多的精力来生成正确的Java代码。

你提供的smali代码看起来是正确的。 运行该应用程序也适用于原始的源代码。 但是,由jd-gui提供的代码甚至没有编译

我好奇,并用dex2jar反编译你的应用程序。 我把由此产生的MainActivity.class上传到这个网站 。

有趣的部分:一些反编译器( Procyon和Fernflower )生成了正确的代码,并为Bundle和TextView分别创build了variables。 然而, JAD和CFR 与jd-gui犯了同样的错误。 他们都使用TextView的Bundlevariables。


看起来你可以责怪jd-gui的错误。 可悲的是,我不能告诉你为什么会发生。