Section II Q-2: Canvas and Paint / Private Preferences (5 Marks)
Question
a) Explain the concept of Canvas and Paint in Android and their usage.
OR
b) How do you create and work with private preferences in Android?
Answer A: Canvas and Paint in Android
Concept of Canvas and Paint
Canvas and Paint are fundamental classes in Android for custom drawing and graphics rendering.
Canvas
- Definition: A 2D drawing surface that provides methods to draw on a bitmap or view
- Purpose: Acts as the drawing board where you can draw shapes, text, images, and paths
- Scope: Handles the "where" and "how" of drawing operations
Paint
- Definition: Holds style and color information for drawing operations
- Purpose: Defines the appearance of drawn elements (color, stroke, fill, etc.)
- Scope: Handles the "what it looks like" aspect of drawing
Key Features and Properties
Canvas Methods
Method | Description | Example |
---|---|---|
drawRect() | Draw rectangle | canvas.drawRect(0, 0, 100, 100, paint) |
drawCircle() | Draw circle | canvas.drawCircle(50, 50, 25, paint) |
drawLine() | Draw line | canvas.drawLine(0, 0, 100, 100, paint) |
drawText() | Draw text | canvas.drawText("Hello", 10, 50, paint) |
drawBitmap() | Draw image | canvas.drawBitmap(bitmap, 0, 0, paint) |
drawPath() | Draw custom path | canvas.drawPath(path, paint) |
Paint Properties
Property | Description | Usage |
---|---|---|
Color | Set drawing color | paint.setColor(Color.RED) |
Style | Fill or stroke | paint.setStyle(Paint.Style.FILL) |
Stroke Width | Line thickness | paint.setStrokeWidth(5) |
Text Size | Font size | paint.setTextSize(24) |
Anti-alias | Smooth edges | paint.setAntiAlias(true) |
Complete Implementation Example
Custom View Class
package com.example.canvaspaintdemo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class CustomDrawingView extends View {
private Paint redPaint, bluePaint, greenPaint, textPaint;
private Path customPath;
public CustomDrawingView(Context context) {
super(context);
initPaints();
}
public CustomDrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaints();
}
private void initPaints() {
// Red paint for filled shapes
redPaint = new Paint();
redPaint.setColor(Color.RED);
redPaint.setStyle(Paint.Style.FILL);
redPaint.setAntiAlias(true);
// Blue paint for strokes
bluePaint = new Paint();
bluePaint.setColor(Color.BLUE);
bluePaint.setStyle(Paint.Style.STROKE);
bluePaint.setStrokeWidth(8);
bluePaint.setAntiAlias(true);
// Green paint for gradients
greenPaint = new Paint();
greenPaint.setColor(Color.GREEN);
greenPaint.setStyle(Paint.Style.FILL);
greenPaint.setAlpha(150); // Semi-transparent
greenPaint.setAntiAlias(true);
// Text paint
textPaint = new Paint();
textPaint.setColor(Color.BLACK);
textPaint.setTextSize(48);
textPaint.setAntiAlias(true);
textPaint.setTextAlign(Paint.Align.CENTER);
// Create custom path
customPath = new Path();
customPath.moveTo(100, 400);
customPath.lineTo(200, 300);
customPath.lineTo(300, 400);
customPath.lineTo(250, 450);
customPath.lineTo(150, 450);
customPath.close();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Set background
canvas.drawColor(Color.WHITE);
// Draw filled rectangle
canvas.drawRect(50, 50, 250, 150, redPaint);
// Draw stroked circle
canvas.drawCircle(400, 100, 75, bluePaint);
// Draw filled circle with transparency
canvas.drawCircle(400, 100, 50, greenPaint);
// Draw lines
canvas.drawLine(50, 200, 250, 200, bluePaint);
canvas.drawLine(50, 220, 250, 220, redPaint);
// Draw text
canvas.drawText("Canvas & Paint Demo", getWidth() / 2, 280, textPaint);
// Draw custom path
canvas.drawPath(customPath, redPaint);
canvas.drawPath(customPath, bluePaint);
// Draw rounded rectangle
RectF roundRect = new RectF(350, 300, 550, 400);
canvas.drawRoundRect(roundRect, 20, 20, greenPaint);
// Draw arc
RectF arcRect = new RectF(50, 500, 200, 650);
canvas.drawArc(arcRect, 0, 270, true, bluePaint);
}
}
Main Activity
package com.example.canvaspaintdemo;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set the custom view as content
CustomDrawingView customView = new CustomDrawingView(this);
setContentView(customView);
}
}
Advanced Paint Features
Gradient Effects
// Linear gradient
LinearGradient linearGradient = new LinearGradient(
0, 0, 200, 200,
Color.RED, Color.BLUE,
Shader.TileMode.CLAMP
);
paint.setShader(linearGradient);
// Radial gradient
RadialGradient radialGradient = new RadialGradient(
100, 100, 50,
Color.YELLOW, Color.RED,
Shader.TileMode.CLAMP
);
paint.setShader(radialGradient);
Text Effects
// Shadow effect
paint.setShadowLayer(5, 3, 3, Color.GRAY);
// Underline text
paint.setUnderlineText(true);
// Strike through text
paint.setStrikeThruText(true);
Answer B: Private Preferences in Android
Understanding Private Preferences
Private Preferences in Android are application-specific key-value storage mechanisms that are accessible only to your application.
Key Characteristics:
- Privacy: Data is private to your application
- Persistence: Data survives application restarts
- Lightweight: Suitable for small amounts of data
- Type Safety: Supports various data types
Creating and Working with Private Preferences
Basic Implementation
package com.example.privatepreferences;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class PreferencesActivity extends Activity {
private static final String PREFS_NAME = "MyAppPreferences";
private static final String KEY_USERNAME = "username";
private static final String KEY_EMAIL = "email";
private static final String KEY_AGE = "age";
private static final String KEY_IS_LOGGED_IN = "is_logged_in";
private SharedPreferences sharedPreferences;
private SharedPreferences.Editor editor;
private EditText etUsername, etEmail, etAge;
private TextView tvDisplayInfo;
private Button btnSave, btnLoad, btnClear;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preferences);
initViews();
initPreferences();
setupClickListeners();
loadSavedData();
}
private void initViews() {
etUsername = findViewById(R.id.etUsername);
etEmail = findViewById(R.id.etEmail);
etAge = findViewById(R.id.etAge);
tvDisplayInfo = findViewById(R.id.tvDisplayInfo);
btnSave = findViewById(R.id.btnSave);
btnLoad = findViewById(R.id.btnLoad);
btnClear = findViewById(R.id.btnClear);
}
private void initPreferences() {
// Initialize SharedPreferences in private mode
sharedPreferences = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
editor = sharedPreferences.edit();
}
private void setupClickListeners() {
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
saveUserData();
}
});
btnLoad.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
loadSavedData();
}
});
btnClear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
clearAllData();
}
});
}
private void saveUserData() {
String username = etUsername.getText().toString().trim();
String email = etEmail.getText().toString().trim();
String ageStr = etAge.getText().toString().trim();
if (username.isEmpty() || email.isEmpty() || ageStr.isEmpty()) {
Toast.makeText(this, "Please fill all fields", Toast.LENGTH_SHORT).show();
return;
}
try {
int age = Integer.parseInt(ageStr);
// Save data to SharedPreferences
editor.putString(KEY_USERNAME, username);
editor.putString(KEY_EMAIL, email);
editor.putInt(KEY_AGE, age);
editor.putBoolean(KEY_IS_LOGGED_IN, true);
editor.putLong("last_login", System.currentTimeMillis());
// Commit changes
editor.apply(); // or editor.commit()
Toast.makeText(this, "Data saved successfully!", Toast.LENGTH_SHORT).show();
displaySavedData();
} catch (NumberFormatException e) {
Toast.makeText(this, "Please enter a valid age", Toast.LENGTH_SHORT).show();
}
}
private void loadSavedData() {
// Retrieve data with default values
String username = sharedPreferences.getString(KEY_USERNAME, "");
String email = sharedPreferences.getString(KEY_EMAIL, "");
int age = sharedPreferences.getInt(KEY_AGE, 0);
boolean isLoggedIn = sharedPreferences.getBoolean(KEY_IS_LOGGED_IN, false);
long lastLogin = sharedPreferences.getLong("last_login", 0);
// Update UI with loaded data
etUsername.setText(username);
etEmail.setText(email);
etAge.setText(age > 0 ? String.valueOf(age) : "");
displaySavedData();
if (!username.isEmpty()) {
Toast.makeText(this, "Data loaded successfully!", Toast.LENGTH_SHORT).show();
}
}
private void displaySavedData() {
String username = sharedPreferences.getString(KEY_USERNAME, "Not set");
String email = sharedPreferences.getString(KEY_EMAIL, "Not set");
int age = sharedPreferences.getInt(KEY_AGE, 0);
boolean isLoggedIn = sharedPreferences.getBoolean(KEY_IS_LOGGED_IN, false);
String displayText = "Saved Information:\n\n" +
"Username: " + username + "\n" +
"Email: " + email + "\n" +
"Age: " + (age > 0 ? age : "Not set") + "\n" +
"Logged In: " + (isLoggedIn ? "Yes" : "No");
tvDisplayInfo.setText(displayText);
}
private void clearAllData() {
editor.clear();
editor.apply();
// Clear input fields
etUsername.setText("");
etEmail.setText("");
etAge.setText("");
displaySavedData();
Toast.makeText(this, "All data cleared!", Toast.LENGTH_SHORT).show();
}
// Additional utility methods
private void removeSpecificKey(String key) {
editor.remove(key);
editor.apply();
}
private boolean containsKey(String key) {
return sharedPreferences.contains(key);
}
private void getAllPreferences() {
Map<String, ?> allPrefs = sharedPreferences.getAll();
for (Map.Entry<String, ?> entry : allPrefs.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
// Process each preference
}
}
}
XML Layout (activity_preferences.xml)
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Private Preferences Demo"
android:textSize="24sp"
android:textStyle="bold"
android:layout_gravity="center"
android:layout_marginBottom="24dp" />
<EditText
android:id="@+id/etUsername"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter username"
android:layout_marginBottom="12dp" />
<EditText
android:id="@+id/etEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter email"
android:inputType="textEmailAddress"
android:layout_marginBottom="12dp" />
<EditText
android:id="@+id/etAge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter age"
android:inputType="number"
android:layout_marginBottom="24dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btnSave"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Save"
android:layout_marginEnd="4dp" />
<Button
android:id="@+id/btnLoad"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Load"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp" />
<Button
android:id="@+id/btnClear"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Clear"
android:layout_marginStart="4dp" />
</LinearLayout>
<TextView
android:id="@+id/tvDisplayInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:background="#F5F5F5"
android:padding="16dp"
android:text="No data saved yet..."
android:textSize="14sp" />
</LinearLayout>
</ScrollView>
Best Practices for Private Preferences
1. Use Constants for Keys
public class PreferenceKeys {
public static final String USER_SETTINGS = "user_settings";
public static final String USERNAME = "username";
public static final String THEME_MODE = "theme_mode";
public static final String NOTIFICATIONS_ENABLED = "notifications_enabled";
}
2. Create Helper Class
public class PreferenceManager {
private SharedPreferences sharedPreferences;
private SharedPreferences.Editor editor;
public PreferenceManager(Context context) {
sharedPreferences = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
editor = sharedPreferences.edit();
}
public void saveString(String key, String value) {
editor.putString(key, value);
editor.apply();
}
public String getString(String key, String defaultValue) {
return sharedPreferences.getString(key, defaultValue);
}
// Add methods for other data types...
}
3. Handle Complex Data
// Storing objects as JSON
public void saveUserObject(User user) {
Gson gson = new Gson();
String userJson = gson.toJson(user);
editor.putString("user_object", userJson);
editor.apply();
}
public User getUserObject() {
String userJson = sharedPreferences.getString("user_object", null);
if (userJson != null) {
Gson gson = new Gson();
return gson.fromJson(userJson, User.class);
}
return null;
}
Summary Comparison
Aspect | Canvas & Paint | Private Preferences |
---|---|---|
Purpose | Custom drawing and graphics | Data storage and retrieval |
Use Case | UI customization, games, charts | Settings, user data, app state |
Complexity | Medium to High | Low to Medium |
Performance | Can be intensive | Fast and lightweight |
Data Types | Graphics primitives | Primitive data types + JSON |