Last active
March 1, 2022 14:27
-
-
Save SelvinPL/eefa88add4fa33f41ca8 to your computer and use it in GitHub Desktop.
Dynamic fragment loading
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package pl.selvin.fragmentloader; | |
| import android.content.Intent; | |
| import android.os.AsyncTask; | |
| import android.os.Bundle; | |
| import android.support.v4.app.Fragment; | |
| import android.support.v7.app.AppCompatActivity; | |
| import android.view.View; | |
| import android.widget.Button; | |
| import android.widget.LinearLayout; | |
| import android.widget.ProgressBar; | |
| import com.squareup.okhttp.OkHttpClient; | |
| import com.squareup.okhttp.Request; | |
| import com.squareup.okhttp.Response; | |
| import java.io.File; | |
| import java.io.IOException; | |
| import java.util.ArrayList; | |
| import dalvik.system.DexClassLoader; | |
| import okio.BufferedSink; | |
| import okio.Okio; | |
| public class Activities { | |
| public static class MainActivity extends AppCompatActivity { | |
| private final static String[][] setupData = new String[][]{ | |
| new String[]{"http://selvin.pl/dynamicfragment.jar", "pl.selvin.dynamicfragment.Fragment1"}, | |
| new String[]{"http://selvin.pl/dynamicfragment.jar", "pl.selvin.dynamicfragment.Fragment2"}, | |
| new String[]{"http://selvin.pl/dynamicfragments2.jar", "pl.selvin.dynamicfragments2.Fragment1"} | |
| }; | |
| @Override | |
| protected void onCreate(Bundle savedInstanceState) { | |
| super.onCreate(savedInstanceState); | |
| final LinearLayout layout = new LinearLayout(this); | |
| layout.setOrientation(LinearLayout.VERTICAL); | |
| final View.OnClickListener buttonClick = (new View.OnClickListener() { | |
| @Override | |
| public void onClick(View v) { | |
| final String[] rowData = (String[]) v.getTag(); | |
| final Intent intent = new Intent(MainActivity.this, GenericActivity.class); | |
| intent.putExtra(GenericActivity.JAR_URL, rowData[0]); | |
| intent.putExtra(GenericActivity.FRAGMENT_CLASS_NAME, rowData[1]); | |
| startActivity(intent); | |
| } | |
| }); | |
| for (int r = 0; r < setupData.length; r++) { | |
| final Button button = new Button(this); | |
| layout.addView(button); | |
| final String[] rowData = setupData[r]; | |
| button.setText(rowData[0] + "\n" + rowData[1]); | |
| button.setTag(rowData); | |
| button.setOnClickListener(buttonClick); | |
| } | |
| setContentView(layout); | |
| } | |
| } | |
| public static class GenericActivity extends AppCompatActivity { | |
| public static String JAR_URL = "JAR_URL"; | |
| public static String FRAGMENT_CLASS_NAME = "FRAGMENT_CLASS_NAME"; | |
| //there should be better way - do not use it in production | |
| private static DexClassLoader loader; | |
| //url that we already loaded | |
| private static ArrayList<String> loadedUris = new ArrayList<>(); | |
| @Override | |
| public ClassLoader getClassLoader() { | |
| if (loader != null) | |
| return loader; | |
| return super.getClassLoader(); | |
| } | |
| @Override | |
| protected void onCreate(Bundle savedInstanceState) { | |
| super.onCreate(savedInstanceState); | |
| if (savedInstanceState == null) { | |
| final ProgressBar progressBar = new ProgressBar(this); | |
| progressBar.setIndeterminate(true); | |
| setContentView(progressBar); | |
| new AsyncTask<Void, Void, Fragment>() { | |
| @Override | |
| protected Fragment doInBackground(Void... params) { | |
| final File outputDir = getCacheDir(); | |
| try { | |
| final String url = getIntent().getStringExtra(JAR_URL); | |
| if (!loadedUris.contains(url)) { | |
| final OkHttpClient client = new OkHttpClient(); | |
| Request request = new Request.Builder().url(url).build(); | |
| Response response = client.newCall(request).execute(); | |
| if (!response.isSuccessful()) | |
| throw new IOException("Unexpected code " + response); | |
| final File downloadedFile = File.createTempFile("temp", ".jar", outputDir); | |
| BufferedSink sink = Okio.buffer(Okio.sink(downloadedFile)); | |
| sink.writeAll(response.body().source()); | |
| sink.close(); | |
| final File tmpDir = getDir("dex", 0); | |
| final String libPath = downloadedFile.getPath(); | |
| loader = new DexClassLoader(libPath, tmpDir.getAbsolutePath(), null, getClassLoader()); | |
| loadedUris.add(url); | |
| } | |
| Class<?> classToLoad = getClassLoader().loadClass(getIntent().getStringExtra(FRAGMENT_CLASS_NAME)); | |
| return (Fragment) classToLoad.newInstance(); | |
| } catch (Exception e) { | |
| e.printStackTrace(); | |
| } | |
| return null; | |
| } | |
| @Override | |
| protected void onPostExecute(Fragment fragment) { | |
| progressBar.setVisibility(View.GONE); | |
| if (fragment != null) { | |
| getSupportFragmentManager().beginTransaction().add(android.R.id.content, fragment, "frag").commit(); | |
| } | |
| } | |
| }.execute(); | |
| } | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="utf-8"?> | |
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
| package="pl.selvin.fragmentloader"> | |
| <uses-permission android:name="android.permission.INTERNET" /> | |
| <application | |
| android:allowBackup="true" | |
| android:label="FragmentLoader" | |
| android:supportsRtl="true" | |
| android:theme="@style/AppTheme"> | |
| <activity android:name=".Activities$MainActivity"> | |
| <intent-filter> | |
| <action android:name="android.intent.action.MAIN" /> | |
| <category android:name="android.intent.category.LAUNCHER" /> | |
| </intent-filter> | |
| </activity> | |
| <activity android:name=".Activities$GenericActivity" /> | |
| </application> | |
| </manifest> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| apply plugin: 'com.android.application' | |
| android { | |
| compileSdkVersion 23 | |
| buildToolsVersion "23.0.1" | |
| defaultConfig { | |
| applicationId "pl.selvin.fragmentloader" | |
| minSdkVersion 10 | |
| targetSdkVersion 23 | |
| versionCode 1 | |
| versionName "1.0" | |
| } | |
| buildTypes { | |
| release { | |
| minifyEnabled false | |
| proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | |
| } | |
| } | |
| } | |
| dependencies { | |
| compile 'com.android.support:appcompat-v7:23.1.0' | |
| compile 'com.squareup.okhttp:okhttp:2.5.0' | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="utf-8"?> | |
| <resources> | |
| <color name="colorPrimary">#3F51B5</color> | |
| <color name="colorPrimaryDark">#303F9F</color> | |
| <color name="colorAccent">#FF4081</color> | |
| </resources> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <resources> | |
| <!-- Base application theme. --> | |
| <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> | |
| <!-- Customize your theme here. --> | |
| <item name="colorPrimary">@color/colorPrimary</item> | |
| <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | |
| <item name="colorAccent">@color/colorAccent</item> | |
| </style> | |
| </resources> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment