java - 奇怪的赋值,TextView到Bundle,反编译后,为什么?

标签 java android decompiling

我创建了一个简单的应用程序,一个计数器应用程序,它在按下按钮时将整数加一并更新 TextView 。代码如下:

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 是 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

我绝对不是 smali 专家,只是一个新手。但我也使用 apktool 解码了应用程序并收到了上面的 smali 代码。据我了解,保存的实例(paramBundle)被加载到 p1(=v3)并在 onCreate 中使用,并且在第 20 行或第 21 行中没有以任何方式使用。对我来说,这指向反编译错误?请记住,apktool 允许再次构建应用程序,因此在反编译时不会丢失任何数据。

最佳答案

原因是局部变量的类型发生了变化,但部分反编译器处理不正确。

这是用 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对象的局部变量,aload_1是Bundle对象的局部变量。问题的根源出现在代码 #20,它将刚刚检索到的 TextView 对象的引用存储到本地变量 1 (astore_1) 中,该变量之前存储了 Bundle目的!

这样做是因为 Bundle 对象不用于该方法的其余部分,因此重用其局部变量而不是新变量更有效。然而,这也意味着反编译器需要更加努力地工作才能生成正确的 Java 代码。

关于java - 奇怪的赋值,TextView到Bundle,反编译后,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30226590/

相关文章:

android - 由于seekTo()而丢失了m3u8声音

android - 使用位图的 ListView

java - 如何在 android 中检查 URL 的可用性

美国写的Java反编译器

java - JMH 中这些奇怪的 boolean 值有什么用?

java - 如何用正则表达式匹配 n 行

java - 如何迭代 2D LinkedHashSet 并打印其内容?

java - 操作栏自定义位置

java - 为什么同步的 getter 像 volatile read 一样工作?

java - 如何保护 MySQL 用户名和密码不被反编译?