{"id":24501404,"url":"https://github.com/code-mc/servicetask","last_synced_at":"2025-03-15T07:25:54.772Z","repository":{"id":94440304,"uuid":"58268185","full_name":"code-mc/servicetask","owner":"code-mc","description":"The asynchronous Android library that eats configuration changes for breakfast","archived":false,"fork":false,"pushed_at":"2016-05-07T20:18:14.000Z","size":123,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-21T22:35:02.064Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/code-mc.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-05-07T13:55:19.000Z","updated_at":"2016-05-07T17:55:38.000Z","dependencies_parsed_at":"2023-03-08T02:45:15.180Z","dependency_job_id":null,"html_url":"https://github.com/code-mc/servicetask","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/code-mc%2Fservicetask","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/code-mc%2Fservicetask/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/code-mc%2Fservicetask/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/code-mc%2Fservicetask/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/code-mc","download_url":"https://codeload.github.com/code-mc/servicetask/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243698132,"owners_count":20333060,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-21T22:29:20.731Z","updated_at":"2025-03-15T07:25:54.767Z","avatar_url":"https://github.com/code-mc.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Service Task Library\n\nThe asynchronous Android library that eats configuration changes for breakfast.\n\n## What\n\nService Task was build as a reliable replacement for the horrendous AsyncTask. Instead of using an object dependent on the current activity context (that will be recreated on configuration change) Service Task builds upon the robust Service API.\n\nYour asynchronous work will be executed inside an IntentService which runs each task on a thread completely separated from the Activity you call it from. The produced result will be passed on to the main thread.\n\n## Statistics\n\n * API 3+\n * ~10KB in size + ~180KB for the GSON dependency\n * Serializes data passed between threads\n\n## Usage\n\n### Gradle\n\n```groovy\ndependencies {\n    compile 'net.steamcrafted:servicetask:1.0.1'\n}\n```\n\n### API\n\nAPI consists of 3 classes:\n\n#### `ServiceTask\u003cType1, Type2\u003e`\n\nAbstract template class. Extend this to implement your own async `ServiceTask`. You have to specify two types: the former for input data (what you give to the task) and one for the output data (what the task produces as a result). You can use any generic Java type for this. If you want to use your own class read the `ServiceTaskPojo` section.\n\n```java\n// Everything that is executed inside this method will be running inside a separate thread.\n// Has a single argument of the first specified type in your class. This will represent your\n// input data. The return type is of the second specified type in your class.\nType2 onAsync(Type1 data)\n\n\n// Call this to start the task. Returns a String that contains a unique ID which \n// you can use to interact with your running task.\nString execute(Context c, Type1 data)\n\n\n// Call this method to register a callback to a running task. You have to specify the \n// task ID to register a callback. So always hold on to your task ID (see example).\nvoid register(Context c, String task_id, ServiceTaskCallback\u003cType2\u003e callback)\n```\n\nIf you end up nesting your `ServiceTask` implementation inside e.g. your `Activity` class you HAVE to make it `static public` otherwise it won't play nice with the used reflection.\n\n#### `ServiceTaskPojo`\n\nClass you extend when you want to pass in your own Pojo objects to a ServiceTask's onAsync method. This class has the required proguard rules to work nicely with GSON (which serializes/deserializes your data between threads)\n\n#### `ServiceTaskCallback\u003cType2\u003e`\n\nInterface that you override to register as a callback to your `ServiceTask`.\n\n### Example\n\nThe best way to explain the library is by showing you an example. Let's say we want to download an image file. The first thing you do is create a class specific to your task that extends the `ServiceTask` class. We'll call it `ImageDownloader`. The `ServiceTask` class is a templated class requiring 2 types: the type of your input data (which will be passed on to the background thread) and the type of the result produced by the thread.\n\n````java\nclass ImageDownloader extends ServiceTask\u003cString, String\u003e {\n    @Override\n    public String onAsync(String url){\n        // Path where the downloaded image will be saved\n        final String file_path = \"images/image.png\";\n        \n        // Create a synchronous client\n        SyncHttpClient client = new SyncHttpClient();\n        client.get(url, new BinaryHttpResponseHandler() {\n            @Override\n            public void onSuccess(byte[] imageData) {\n                // Save the data to disk\n                Utils::save(file_path, imageData); // Some method that writes to disk\n            }\n\n            @Override\n            public void onFailure(Throwable e, byte[] imageData) {\n                \n            }\n        });\n        // Return the location of the saved file\n        return file_path;\n    }\n}\n```\n\n`ServiceTask` is an abstract class, Android Studio will ask you to implement the `onAsync` method. Everything inside this method will be executed inside a background thread.\n\nTo further expand on our example, let's call the `ImageDownloader` from an `Activity`:\n\n```java\nclass MainActivity extends Activity {\n\n    String getRequestId; // ID of our running task\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        \n        // ...\n        \n        downloadButton.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View view) {\n                // We start the task and save its unique ID for later\n                getRequestId = new ImageDownloader().execute(MainActivity.this,\n                    \"http://example.com/someimage.png\");\n                // Register the callback that will capture the result\n                registerCallback();\n            }\n        });\n        \n        // ...\n    }\n    \n    /*\n     * We use a separate method for registering as it is something you'll\n     * have to do multiple times.\n     */\n    private void registerCallback(){\n        new ImageDownloader().register(MainActivity.this, getRequestId, new ServiceTask.ServiceTaskCallback\u003cString\u003e() {\n            @Override\n            public void afterAsync(String file_path) {\n                // Here we can do something with the result on the UI thread\n            }\n        });\n    }\n\n    @Override\n    protected void onDestroy() {\n        ServiceTaskService.unregisterReceivers(this);\n        super.onDestroy();\n    }\n    \n    @Override\n    protected void onSaveInstanceState(Bundle outState) {\n        super.onSaveInstanceState(outState);\n        // This is important, when the device is rotated we have to save the current\n        // task id so we can re-register in onRestoreInstanceState, that way results\n        // never get lost.\n        outState.putString(\"getRequestId\", getRequestId);\n    }\n\n    @Override\n    protected void onRestoreInstanceState(Bundle savedInstanceState) {\n        super.onRestoreInstanceState(savedInstanceState);\n        // Grab the task id\n        getRequestId = savedInstanceState.getString(\"getRequestId\");\n        // We register again. Because of the device rotation the previously\n        // registered callback got destroyed so it wouldn't be called\n        registerCallback();\n    }\n\n}\n```\n\nThis might look like a lot of code, but sadly there isn't a silver bullet for retaining a value on configuration change. At least this time you only have to retain a string and not a complete object. Or worse: completely restart the request.\n\nAfter you put all this in place you're good to go. The library will handle everything else for you.\n\n#License\n\nReleased under the [Apache 2.0 License](https://github.com/code-mc/servicetask/blob/master/license.md)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcode-mc%2Fservicetask","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcode-mc%2Fservicetask","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcode-mc%2Fservicetask/lists"}