2013-05-08 1 views
1

Android 애플리케이션을 처리 할 때 문제가 발생했습니다. 앱에서 .zip 또는 .dex 클래스를로드하는 것입니다. Classloader 문제는 해결할 수 없습니다. 고마워. 고마워. Zip에서 클래스를로드하려고하는데 프로그램이 시작될 때 클래스 (예 : Android 공급자 또는 이와 비슷한 클래스)를로드해야합니다. 그래서, 예를 들어, 패키지 com.example.androidprovider 및 파일 TestProvider.java를 사용하여 프로그램에 파일을 남겨 두어야합니다.Android 애플리케이션에 사용되는 클래스 로더

내 .zip 파일에서
package com.example.androidprovider; 
public class TestProvider extends ContentProvider { 
public static final String AUTHORY="com.lcz.tst"; 
     DBHelper dbHelp; 
     SQLiteDatabase sq; 
     @Override 
     public int delete(Uri uri, String selection, String[] selectionArgs) { 
       sq.delete(DBHelper.TABLE, selection, selectionArgs); 
       return 0; 
     } 
     ... 
     @Override 
     public boolean onCreate() { 
       dbHelp=new DBHelper(getContext(),null, null, 1); 
       sq=dbHelp.getWritableDatabase(); 
       Log.i("TestProvider", "text"); 
       return true; 
     } 
} 

, 나는 패키지 com.example.androidprovider 및 클래스 이름 TestProvider와 클래스를 패키지. (두 클래스는 서로 다른이고, 두 번째 클래스는 내가 정말 필요로하는 클래스입니다.)

package com.example.androidprovider; 
public class TestProvider extends ContentProvider { 
     public static final String AUTHORY="com.lcz.tst"; 
     DBHelper dbHelp; 
     SQLiteDatabase sq; 
     @Override 
     public int delete(Uri uri, String selection, String[] selectionArgs) { 
       sq.delete(DBHelper.TABLE, selection, selectionArgs); 
       return 0; 
     } 
     ... 
     @Override 
     public boolean onCreate() { 
       dbHelp=new DBHelper(getContext(),null, null, 1); 
       sq=dbHelp.getWritableDatabase(); 
       Log.i("Original Provider", "This is the original!!!"); 
       return true; 
     } 
} 

이제 내 로더 코드입니다.

public void loadDex(String strActivity){ 
     final File optimizedDexOutputPath = oriActivity.getDir("outdex", Context.MODE_PRIVATE); 
     // Initialize the class loader with the secondary dex file. 
     //dexInternalStoragePath.getAbsolutePath() is the path there the .zip is, 
     DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(), 
       optimizedDexOutputPath.getAbsolutePath(), 
       libPath, 
       this.getClass().getClassLoader()); 
     Class<?> cls; 
     try { 
       cls = cl.loadClass("com.example.androidprovider.TestProvider"); 
       Object instant = cls.newInstance(); 
       Method method = cls.getDeclaredMethod("onCreate"); 
       method.invoke(instant); 
     }catch (Exception e) { 
       e.printStackTrace(); 
     } 

는 내가 로그 캣을 확인하지만, 로그는 항상 "TestProvider 텍스트"을 보여줍니다. 따라서 로더 코드가 실패했다는 의미입니다. 그 이유는 내 응용 프로그램 이니셜 com.example.androidprovider.TestProvider (코드의 첫 번째 부분) 클래스, 그리고 로더가 동일한 패키지와 이름으로 다른 클래스를로드하므로 두 번째 클래스를 성공적으로로드 할 수 없다고 생각합니다.

하지만 실제로 두 번째 클래스를로드해야합니다. 두 번째 수업을 시작하는 데 몇 가지 방법을 사용할 수 있습니까? 감사합니다 ...

답변

0

어째서 원본을로드하지 않는 이유는 모르겠습니다. "원본"클래스에 대한 메서드 호출을 분류하는 응용 프로그램에 Proxy 클래스를 배치 할 수 있습니다. 하지만 당신은 반사를 사용해야합니다!

package com.example.androidprovider; 
public class TestProviderProxy extends ContentProvider { 
    public boolean onCreate() { 
      // use reflections here -> GOOGLE IT 
      // something with clazz = context.getClassloader().loadClass(
      // "com.example.androidprovider.TestProvider"); 
      // method = clazz.getMethod("onCreate") 
      return method.invoke(); 
    } 
} 

package com.example.androidprovider; 
public class TestProvider extends ContentProvider { 
    public boolean onCreate() { 
      dbHelp=new DBHelper(getContext(),null, null, 1); 
      sq=dbHelp.getWritableDatabase(); 
      Log.i("Original Provider", "This is the original!!!"); 
      return true; 
    } 
} 
+0

감사합니다. 아마도 이것이 잘 작동 할 수 있습니다. 제 예제에서는 첫 번째 TestProviderProxy가 가능한 한 적게 변경되어야합니다. 이 코드는 테스트 코드 일뿐입니다. 실제로는 첫 번째 TestProviderProxy의 소스 코드를 얻을 수 없습니다. 하지만 안드로이드 응용 프로그램의 AndroidMenifest.xml 파일 때문에 초기화해야합니다. 그래서 나는 대체 TestProviderProxy (두 번째)를 써서 실제 TestProviderProxy (첫 번째)를로드해야한다. 나는 대체 TestProviderProxy를 다시 쓰려고 생각하지 않았다. 고마워요! –

+0

그건 그렇고, 반성이 정말로 강력하다는 것을 나는 안다. 그렇다면 런타임 실행 중에 두 번째 클래스를 사용하여 첫 번째 클래스를 다룰 수있는 몇 가지 방법이 있습니까? 리플렉션을 사용하여 시스템 계층의 일부 데이터를 수정하여이 작업을 수행 할 수도 있지만 수정해야 할 데이터의 종류를 알지 못했습니다. 감사. –

+0

나는 아직도 성취하려는 것을 확신하지 못한다. 그러나 그것이 당신을 도왔기를 바란다. 예 반사는 "강력"하지만 시스템 자체가 원시 코드로 실행되고 응용 프로그램이 SandBox에서 실행됩니다. 당신은 단지 "어떤 데이터"를 바꿔서 모든 일을 할 수는 없습니다. – cwin

1

응용 프로그램 클래스 attachBaseContext()를 재정 의하여 기본 컨텍스트의 클래스 로더를 수정하는 것이 할 수있는 청소기 방법.

protected void attachBaseContext(Context base) 
{ 
    Log.i(loggerName, "Attaching base context"); 
    super.attachBaseContext(base); 

    // Modify base.getClassLoader() via reflection. 
    // Load classes as normal without having to tinker around with loadClass etc. 

}