Past Papers
Past Papers
from an activity and the activity is showing an animation indicating progress, you might
encounter the following issue:
### Issue:
The service could potentially run in the background, even if the associated activity is no longer
visible or has been destroyed. If the activity is destroyed, and the animation is tied to it, there
may be a situation where the animation continues to run even if the user is no longer interacting
with the application or the progress animation is no longer relevant.
1. **Use IntentService:**
```java
Intent service = new Intent(context, MyIntentService.class);
context.startService(service);
```
```java
public class YourActivity extends AppCompatActivity {
// ...
// ...
}
```
By using `IntentService`, you ensure that the background task is performed efficiently and does
not unnecessarily keep running after completion. Additionally, you have more control over
managing the UI components (like progress animations) within the activity, which helps in
providing a better user experience.
What is an Intent? Can it be used to provide data to a ContentProvider? Why or
why not? (2.5)
In Android, an `Intent` is a messaging object that is used to request an action from another
component of the application (or from another application). It is a fundamental building block of
Android's inter-component communication system.
Instead of using an `Intent` to provide data to a `ContentProvider`, you typically use other
mechanisms, such as:
```java
// Example query using ContentResolver
ContentResolver contentResolver = getContentResolver();
Uri uri = Uri.parse("content://com.example.provider/data");
Cursor cursor = contentResolver.query(uri, null, null, null, null);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
@Override
protected Boolean doInBackground(Void... params) {
String filePath = filePathEditText.getText().toString();
String courseCode = courseCodeEditText.getText().toString();
String courseTitle = courseTitleEditText.getText().toString();
try {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String line;
String[] header = null;
if (header == null) {
// Skip the header line
header = data;
continue;
}
reader.close();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
Toast.makeText(getApplicationContext(), "Data loaded successfully",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Failed to load data",
Toast.LENGTH_SHORT).show();
}
}
}
// Iterate over date columns starting from index 2 (skipping roll no. and name)
for (int i = 2; i < header.length; i++) {
String dateString = header[i];
String status = data[i];
// Convert the date string to a format compatible with your database
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy",
Locale.ENGLISH);
Date date;
try {
date = dateFormat.parse(dateString);
} catch (java.text.ParseException e) {
e.printStackTrace();
continue;
}
What are the benefits of using a Layered Architecture for developing an Android
Application?
1. **Separation of Concerns:**
- **Clear Division of Responsibilities:** Layers (such as presentation, business logic, and data
access) have distinct responsibilities, making it easier to understand, maintain, and modify the
code.
- **Modularity:** Each layer is modular and can be developed, tested, and maintained
independently, allowing for easier updates and enhancements.
2. **Maintainability:**
- **Ease of Maintenance:** Changes to one layer do not necessarily impact other layers,
making it easier to maintain and update specific components without affecting the entire
application.
- **Readability:** Code is more readable and comprehensible since each layer focuses on
specific functionalities.
3. **Scalability:**
- **Vertical Scalability:** It's easier to scale the application vertically by improving or extending
functionality within a specific layer without affecting the entire application.
- **Horizontal Scalability:** Different layers can be distributed across multiple modules or
services, allowing for horizontal scalability.
4. **Testability:**
- **Isolation of Components:** Layers provide a natural separation that enables the isolation of
components for testing. Unit testing, integration testing, and end-to-end testing can be
performed more effectively.
5. **Reusability:**
- **Component Reusability:** Components within each layer can be reused across different
parts of the application or even in different projects, enhancing the overall reusability of the
codebase.
7. **Collaborative Development:**
- **Parallel Development:** Different teams or developers can work on different layers
concurrently without significant interference, allowing for parallel development efforts.
- **Separation of Roles:** Different roles (UI designers, backend developers, etc.) can focus
on their respective areas of expertise.
8. **Security:**
- **Enforcement of Security Policies:** Layers can help enforce security policies by isolating
sensitive operations or data access within the appropriate layers, reducing the risk of security
vulnerabilities.
What is the benefit of using Fragments for implementing Responsive Design?
How multiple Fragments communicate with each other?
Using Fragments in Android for implementing responsive design provides several benefits,
especially when dealing with different screen sizes and orientations. Here are some advantages
of using Fragments for responsive design:
1. **Dynamic UI Composition:**
- Fragments allow for the dynamic composition of user interfaces. You can define UI
components within a fragment and reuse them across different layouts, adapting to various
screen sizes and orientations.
5. **Separation of Concerns:**
- Fragments support the separation of concerns in UI design. Each fragment can encapsulate
a specific piece of functionality or user interface, making the codebase more modular and
maintainable.
2. **Interface Callbacks:**
- Fragments can define interfaces that the hosting activity implements. This allows the
fragments to communicate directly with the activity, and the activity can then relay information
between fragments.
4. **FragmentManager:**
- Fragments can communicate directly through the `FragmentManager`. One fragment can
find another fragment by ID or tag and then call methods on that fragment to exchange data or
trigger actions.
5. **Arguments Bundle:**
- Fragments can pass data to each other using the `setArguments` method, where one
fragment sets arguments for another before it is attached. This is useful for initializing fragments
with specific data.
Creating a content provider in Kotlin involves several steps, including defining a contract,
implementing the database helper, and the content provider itself. I'll provide you with a basic
example for a discussion forum application. In a real-world scenario, you might want to add
more features, error handling, and optimizations.
```kotlin
import android.net.Uri
import android.provider.BaseColumns
object ForumContract {
const val AUTHORITY = "com.example.forumprovider"
const val PATH_QUESTIONS = "questions"
const val CONTENT_URI = "content://$AUTHORITY/$PATH_QUESTIONS"
```kotlin
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
db.execSQL(SQL_CREATE_QUESTIONS_TABLE)
}
companion object {
const val DATABASE_NAME = "forum.db"
const val DATABASE_VERSION = 1
}
}
```
```kotlin
import android.content.ContentProvider
import android.content.ContentValues
import android.content.UriMatcher
import android.database.Cursor
import android.net.Uri
import android.os.Bundle
companion object {
private const val QUESTIONS = 1
private const val QUESTION_ID = 2
when (sUriMatcher.match(uri)) {
QUESTIONS -> cursor = db.query(
ForumContract.QuestionEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder
)
QUESTION_ID -> {
val whereClause = "${ForumContract.QuestionEntry._ID} = ${uri.lastPathSegment}"
cursor = db.query(
ForumContract.QuestionEntry.TABLE_NAME,
projection,
whereClause,
selectionArgs,
null,
null,
sortOrder
)
}
else -> throw IllegalArgumentException("Unknown URI: $uri")
}
cursor?.setNotificationUri(context!!.contentResolver, uri)
return cursor
}
context!!.contentResolver.notifyChange(uri, null)
return Uri.withAppendedPath(uri, id.toString())
}
when (sUriMatcher.match(uri)) {
QUESTIONS -> rowsUpdated = db.update(
ForumContract.QuestionEntry.TABLE_NAME,
values,
selection,
selectionArgs
)
QUESTION_ID -> {
val whereClause = "${ForumContract.QuestionEntry._ID} = ${uri.lastPathSegment}"
rowsUpdated = db.update(
ForumContract.QuestionEntry.TABLE_NAME,
values,
whereClause,
selectionArgs
)
}
else -> throw IllegalArgumentException("Unknown URI: $uri")
}
if (rowsUpdated > 0) {
context!!.contentResolver.notifyChange(uri, null)
}
return rowsUpdated
}
when (sUriMatcher.match(uri)) {
QUESTIONS -> rowsDeleted = db.delete(
ForumContract.QuestionEntry.TABLE_NAME,
selection,
selectionArgs
)
QUESTION_ID -> {
val whereClause = "${ForumContract.QuestionEntry._ID} = ${uri.lastPathSegment}"
rowsDeleted = db.delete(
ForumContract.QuestionEntry.TABLE_NAME,
whereClause,
selectionArgs
)
}
else -> throw IllegalArgumentException("Unknown URI: $uri")
}
if (rowsDeleted > 0) {
context!!.contentResolver.notifyChange(uri, null)
}
return rowsDeleted
}
}
```
```kotlin
import android.content.ContentValues
import android.database.Cursor
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
// Inserting a question
val questionUri: Uri? = insertQuestion("How to use Fragments in Android?", "Android",
In Android, you cannot update UI elements directly from the `doInBackground` method of
`AsyncTask` because this method runs on a background thread, and UI updates must be
performed on the main (UI) thread. Attempting to modify UI elements directly from
`doInBackground` can lead to runtime exceptions.
To fix this, you should update the UI in the `onPostExecute` method, which runs on the main
(UI) thread after the background task is completed.
```java
public class MidtermAsyncTask extends AsyncTask<Void, Void, String> {
private TextView txtName;
MidtermAsyncTask(TextView txt) {
txtName = txt;
}
@Override
protected String doInBackground(Void... voids) {
return downloadData();
}
@Override
protected void onPostExecute(String myName) {
txtName.setText(myName);
}
Changes made:
```java
// Example usage in an Activity
MidtermAsyncTask asyncTask = new MidtermAsyncTask(txtName);
asyncTask.execute();
```
Make sure to replace the placeholder data (`"John Doe"`) in the `downloadData` method with
your actual data download logic.
1 – You are developing an application which stores data in its database. You want
that data in the
database to be accessible to other 3rd party applications as well.
What is the most appropriate way to do this, how do we do this and why would
we use this
approach? (3 marks)
What:
Why:
How:
### What:
The most appropriate way to make data in your application's database accessible to other 3rd
party applications is by using a **Content Provider**.
### Why:
Content Providers offer a standardized and secure way for different applications to access and
share data. Here are some reasons for using Content Providers:
1. **Data Sharing:** Content Providers facilitate data sharing between different applications in a
controlled and secure manner.
2. **Abstraction:** They provide a level of abstraction, allowing other applications to interact with
the data without knowing the underlying database structure.
3. **Security:** Content Providers can be configured to enforce permissions, ensuring that only
authorized applications can access certain data.
### How:
```kotlin
class MyContentProvider : ContentProvider() {
// Implementation of ContentProvider methods
}
```
2. **Declare Permissions:**
- In the manifest file, declare permissions to control access to your Content Provider.
```xml
<provider
android:name=".MyContentProvider"
android:authorities="com.example.myapp.provider"
android:exported="true"
android:readPermission="com.example.myapp.READ_DATA"
android:writePermission="com.example.myapp.WRITE_DATA" />
```
```kotlin
override fun query(uri: Uri, projection: Array<String>?, selection: String?, selectionArgs:
Array<String>?, sortOrder: String?): Cursor? {
// Implement query logic
return null
}
4. **Handle Permissions:**
- In the Content Provider, enforce necessary permissions to control which applications can
access data.
```kotlin
override fun onCreate(): Boolean {
// Check permissions before allowing access
val permission =
context?.checkCallingOrSelfPermission("com.example.myapp.READ_DATA")
return permission == PackageManager.PERMISSION_GRANTED
}
```
```kotlin
val providerUri = Uri.parse("content://com.example.myapp.provider/data")
val contentResolver: ContentResolver = getContentResolver()
val cursor: Cursor? = contentResolver.query(providerUri, projection, selection, selectionArgs,
sortOrder)
```
2 – You are required to make a service that needs to share some data to other
services or activities. What is the most appropriate service to handle this? Why is
this the most appropriate and how would you do this? (6 Marks)
What:
Why:
How (Pseudo Code):
### What:
The most appropriate service to handle sharing data to other services or activities in Android is
a **Bound Service**.
### Why:
A Bound Service is well-suited for scenarios where components (such as activities or other
services) need to interact with a service and share data. Here are the reasons for using a Bound
Service:
3. **Lifecycle Awareness:** Bound Services are aware of the lifecycle of the components bound
to them. This ensures that data can be shared when the components are actively interacting
with the service.
4. **Efficiency:** Bound Services are efficient for scenarios where data needs to be shared
temporarily, and direct method calls are preferable over other forms of inter-process
communication.
3- What is implicit broadcast and explicit broadcast, tell the difference too. Give 1
example of each.
(4 Marks)
Implicit and Example:
Explicit and Example:
**Definition:**
Implicit broadcasts are system-wide messages that allow the system to notify interested
components about various events. They don't specify a particular target component, and any
component that has registered to listen for that type of broadcast can receive and respond to it.
**Difference:**
- Implicit broadcasts are broadcast to the entire system without specifying a target component.
- Multiple components can respond to an implicit broadcast.
**Example:**
Sending a broadcast to indicate that the device's connectivity status has changed.
```kotlin
val intent = Intent("android.net.conn.CONNECTIVITY_CHANGE")
context.sendBroadcast(intent)
```
**Definition:**
Explicit broadcasts are directed to a specific component within an application or between
applications. The sender specifies the exact component that should receive the broadcast.
**Difference:**
- Explicit broadcasts target a specific component.
- Typically used for communication within an app or between specific apps.
**Example:**
Sending a custom broadcast to a specific BroadcastReceiver within the same app.
```kotlin
val intent = Intent("com.example.myapp.CUSTOM_ACTION")
context.sendBroadcast(intent)
```
@OptIn(ExperimentalComposeUiApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApp {
ContactInfoScreen()
}
}
}
@OptIn(ExperimentalComposeUiApi::class)
override fun onStart() {
super.onStart()
if (isBound) {
unbindService(connection)
isBound = false
}
}
@Composable
fun ContactInfoScreen() {
var email by remember { mutableStateOf("") }
var vCardResult by remember { mutableStateOf("") }
val context = LocalContext.current
val keyboardController = LocalSoftwareKeyboardController.current
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center
){
OutlinedTextField(
value = email,
onValueChange = { email = it },
label = { Text("Enter Email") },
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = {
keyboardController?.hide()
if (isBound) {
vCardResult = vCardService?.convert(email) ?: "Service not bound"
}
}
),
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp)
)
Button(
onClick = {
if (isBound) {
vCardResult = vCardService?.convert(email) ?: "Service not bound"
}
},
modifier = Modifier.align(Alignment.CenterHorizontally)
){
Text("Get vCard")
}
Spacer(modifier = Modifier.height(16.dp))
Text(
text = vCardResult,
color = Color.Black,
style = MaterialTheme.typography.body1,
modifier = Modifier.fillMaxWidth()
)
}
}
@Composable
fun MyApp(content: @Composable () -> Unit) {
FeatherAndroidTasksTheme {
// A surface container using the 'background' color from the theme
Surface(
color = MaterialTheme.colorScheme.background,
modifier = Modifier.fillMaxSize()
){
content()
}
}
}
}