QQゲームホールの構造について私もいくつか言いたいです
5872 ワード
まずレンガを投げて玉を引いて、次の例で説明します.今の例は実現します.
インストールされたapkの中のactivity Aは、sdカードに置かれているインストールされていないapkの中のactivity Bを呼び出し、ポイントリターンキーは直接終了するのではなく、Activity Aに戻ります.
OK、私のところにはすでに既成の方法があります.まずコードをつけます.
アクティブにロードしたSD上のクラスのactivity
もう1つはsdカードにロードされるactivityです.
上は私が言った例の最も核心的な2つのクラスを実現しています.すべてのコードは詳しく見てください.http://download.csdn.net/detail/androidzhaoxiaogang/4903804
(コードはセグメントにすぎません.実際に応用するには改善が必要です.例えば、戻るときに端末が実行するrunnableは私の別の文章端末が実行するjavaスレッドの方法を参照してください.
ネット上にはQQゲームホールに関する分析や上記のような例がたくさんあるかもしれませんが、さらに分析したいと思います.
1.activityは厳密な意味でのライフサイクルがActivity Threadで作成されなければならないことを知っています.そのため、DexClassLoaderでロードされたActivity Bはライフサイクルがなく、普通のクラスです.
2.なぜActivity Aに直接Activity Aにloadの別のクラス、例えばclassCをロードさせるのではなく、Activity AにActivity Bをロードさせるのかと聞かれることがあります.この問題は簡単です.私たちがAPKにパッケージ化するとき、activityがあればもっと便利で直感的になるからです.簡単なゲームは、往々にして1つのactivityで十分です.Activity Aもクラスインスタンスを1つだけロードする必要があります.
インストールされたapkの中のactivity Aは、sdカードに置かれているインストールされていないapkの中のactivity Bを呼び出し、ポイントリターンキーは直接終了するのではなく、Activity Aに戻ります.
OK、私のところにはすでに既成の方法があります.まずコードをつけます.
アクティブにロードしたSD上のクラスのactivity
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import dalvik.system.DexClassLoader;
public class MainActivity
extends Activity {
private static final String TAG = "MainActivity";
private boolean isJumped = false;
private Class localClass;
private Object instance;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
isJumped = true;
Bundle paramBundle = new Bundle();
paramBundle.putBoolean("KEY_START_FROM_OTHER_ACTIVITY", true);
String dexpath = "/mnt/sdcard/ToolA.apk";
String dexoutputpath = "/mnt/sdcard/";
LoadAPK(paramBundle, dexpath, dexoutputpath);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (isJumped) {
Bundle paramBundle = new Bundle();
paramBundle.putBoolean("KEY_START_FROM_OTHER_ACTIVITY", true);
closeAPK(paramBundle);
isJumped = false;
return true;
}
}
return super.onKeyDown(keyCode, event);
}
public void LoadAPK(Bundle paramBundle, String dexpath, String dexoutputpath) {
ClassLoader localClassLoader = ClassLoader.getSystemClassLoader();
DexClassLoader localDexClassLoader =
new DexClassLoader(dexpath, dexoutputpath, null, localClassLoader);
try {
PackageInfo plocalObject = getPackageManager().getPackageArchiveInfo(dexpath, 1);
if ((plocalObject.activities != null) && (plocalObject.activities.length > 0)) {
String activityname = plocalObject.activities[0].name;
Log.d(TAG, "activityname = " + activityname);
localClass = localDexClassLoader.loadClass(activityname);
Constructor localConstructor = localClass.getConstructor(new Class[] {});
instance = localConstructor.newInstance(new Object[] {});
Log.d(TAG, "instance = " + instance);
Method localMethodSetActivity =
localClass.getDeclaredMethod("setActivity", new Class[] {Activity.class});
localMethodSetActivity.setAccessible(true);
localMethodSetActivity.invoke(instance, new Object[] {this});
Method methodonCreate = localClass.getDeclaredMethod("onCreate", new Class[] {Bundle.class});
methodonCreate.setAccessible(true);
methodonCreate.invoke(instance, new Object[] {paramBundle});
}
return;
}
catch (Exception ex) {
ex.printStackTrace();
}
}
public void closeAPK(Bundle paramBundle) {
try {
Method methodonCreate = localClass.getDeclaredMethod("onGoBack");
methodonCreate.setAccessible(true);
methodonCreate.invoke(instance);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
もう1つはsdカードにロードされるactivityです.
package mobi.thinkchange.android.toola;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;
public class ToolAActivity
extends Activity {
private static final String TAG = "ToolAActivity";
private Activity otherActivity;
@Override
public void onCreate(Bundle savedInstanceState) {
boolean b = false;
if (savedInstanceState != null) {
b = savedInstanceState.getBoolean("KEY_START_FROM_OTHER_ACTIVITY", false);
if (b) {
this.otherActivity.setContentView(new TBSurfaceView(this.otherActivity));
}
}
if (!b) {
super.onCreate(savedInstanceState);
setContentView(new TBSurfaceView(this));
}
}
public void setActivity(Activity paramActivity) {
Log.d(TAG, "setActivity..." + paramActivity);
this.otherActivity = paramActivity;
}
public void onGoBack() {
otherActivity.setContentView(R.layout.main);
}
}
上は私が言った例の最も核心的な2つのクラスを実現しています.すべてのコードは詳しく見てください.http://download.csdn.net/detail/androidzhaoxiaogang/4903804
(コードはセグメントにすぎません.実際に応用するには改善が必要です.例えば、戻るときに端末が実行するrunnableは私の別の文章端末が実行するjavaスレッドの方法を参照してください.
ネット上にはQQゲームホールに関する分析や上記のような例がたくさんあるかもしれませんが、さらに分析したいと思います.
1.activityは厳密な意味でのライフサイクルがActivity Threadで作成されなければならないことを知っています.そのため、DexClassLoaderでロードされたActivity Bはライフサイクルがなく、普通のクラスです.
2.なぜActivity Aに直接Activity Aにloadの別のクラス、例えばclassCをロードさせるのではなく、Activity AにActivity Bをロードさせるのかと聞かれることがあります.この問題は簡単です.私たちがAPKにパッケージ化するとき、activityがあればもっと便利で直感的になるからです.簡単なゲームは、往々にして1つのactivityで十分です.Activity Aもクラスインスタンスを1つだけロードする必要があります.