Service (Associate Android Developer Certification)

Service works in background, used for long time operations. It has 3 lifecycle methods: onCreate(), onStartCommand(), onDestroy();
In order to start and stop service: you can use startService() and stopService() methods. Or you can use startSelf() and stopSelf() methods inside service.
If you want to interact with service you can use bindService() and unbindService() methods. When you bindService(), if service is not running, it will start.
If you want to connect to service from another application, you can use following methods:

  • IBinder onBind(Intent intent)
  • onUnbind(Intent intent)
  • onRebind(Intent intent)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return Service.START_STICKY;
}

START_NOT_STICKY – service won’t be restarted after stopped by system
START_STICKY – service will be restarted after stopped by system
START_REDLIVER_INTENT – service wil be restarted after stopped by system. receives all startService calls.

Example:

PlayService.java

public class PlayService extends Service
{
    MediaPlayer mPlayer;
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate()
    {
        Toast.makeText(this, "Служба создана",
            Toast.LENGTH_SHORT).show();
        mPlayer = MediaPlayer.create(this, R.raw.zara);
        mPlayer.setLooping(false);
    }

    @Override
    public void onStart(Intent intent, int startid)
    {
        Toast.makeText(this, "Служба запущена",
            Toast.LENGTH_SHORT).show();
        mPlayer.start();
    }
   
    @Override
    public void onDestroy()
    {
        Toast.makeText(this, "Служба остановлена",
            Toast.LENGTH_SHORT).show();
        mPlayer.stop();
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Button btnStart = (Button) findViewById(R.id.btn_start);
        final Button btnStop = (Button) findViewById(R.id.btn_stop);

        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startService(new Intent(MainActivity.this, PlayService.class));
            }
        });

        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                stopService(new Intent(MainActivity.this, PlayService.class));
            }
        });
    }
}

AndroidManifest.xml

        <service
           android:enabled="true"
           android:name=".PlayService">
        </service>

How to start service on boot completed:

public class BootBroadcast extends BroadcastReceiver {
 
    @Override
    public void onReceive(Context context, Intent intent) {      
        context.startService(new Intent(context, TestService.class));
    }
}
<receiver android:name=".BootBroadcast">  
    <intent-filter >
        <action android:name="android.intent.action.BOOT_COMPLETED"/>              
    </intent-filter>
</receiver>

How to get list of running services?

ActivityManager am = (ActivityManager) this
        .getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> rs = am.getRunningServices(50);

for (int i = 0; i < rs.size(); i++) {
    ActivityManager.RunningServiceInfo rsi = rs.get(i);
    Log.i("Service", "Process " + rsi.process + " with component "
            + rsi.service.getClassName());
}

Source

CursorLoader example (Associate Android Developer Certification)

MyCursorLoader.java

public class MyCursorLoader extends CursorLoader {

    DB db;

    public MyCursorLoader(Context context, DB db) {
        super(context);
        this.db = db;
    }

    @Override
    public Cursor loadInBackground() {
        Cursor cursor = db.getAllData();
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return cursor;
    }

}

MainActivity.java

public class MainActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<Cursor> {

    private static final int CM_DELETE_ID = 1;
    ListView lvData;
    DB db;
    SimpleCursorAdapter scAdapter;

    /** Called when the activity is first created. */
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // открываем подключение к БД
        db = new DB(this);
        db.open();

        // формируем столбцы сопоставления
        String[] from = new String[] { DB.COLUMN_IMG, DB.COLUMN_TXT };
        int[] to = new int[] { R.id.ivImg, R.id.tvText };

        // создааем адаптер и настраиваем список
        scAdapter = new SimpleCursorAdapter(this, R.layout.listitem, null, from, to, 0);
        lvData = (ListView) findViewById(R.id.lvData);
        lvData.setAdapter(scAdapter);

        // добавляем контекстное меню к списку
        registerForContextMenu(lvData);

        // создаем лоадер для чтения данных
        getSupportLoaderManager().initLoader(0, null, this);
    }

    // обработка нажатия кнопки
    public void onButtonClick(View view) {
        // добавляем запись
        db.addRec("sometext " + (scAdapter.getCount() + 1), R.mipmap.ic_launcher);
        // получаем новый курсор с данными
        getSupportLoaderManager().getLoader(0).forceLoad();
    }

    public void onCreateContextMenu(ContextMenu menu, View v,
                                    ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        menu.add(0, CM_DELETE_ID, 0, R.string.delete_record);
    }

    public boolean onContextItemSelected(MenuItem item) {
        if (item.getItemId() == CM_DELETE_ID) {
            // получаем из пункта контекстного меню данные по пункту списка
            AdapterView.AdapterContextMenuInfo acmi = (AdapterView.AdapterContextMenuInfo) item
                    .getMenuInfo();
            // извлекаем id записи и удаляем соответствующую запись в БД
            db.delRec(acmi.id);
            // получаем новый курсор с данными
            getSupportLoaderManager().getLoader(0).forceLoad();
            return true;
        }
        return super.onContextItemSelected(item);
    }

    protected void onDestroy() {
        super.onDestroy();
        // закрываем подключение при выходе
        db.close();
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle bndl) {
        return new MyCursorLoader(this, db);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        scAdapter.swapCursor(cursor);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
    }

}

Android – Take picture intent

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, REQUEST_CAMERA);

 @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == REQUEST_CAMERA)}
            onCaptureImageResult(data);
        }
    }
}

 private void onCaptureImageResult(Intent data) {
    Bitmap bitmap = (Bitmap) data.getExtras().get("data");
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
    File destination = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg");
    FileOutputStream fo;
    try {
        destination.createNewFile();
        fo = new FileOutputStream(destination);
        fo.write(bytes.toByteArray());
        fo.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    img_upload_pic.setImageBitmap(bitmap);
}

Android – How to ask permission without Dexter?

Check permission

        int rc = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
        if (rc == PackageManager.PERMISSION_GRANTED) {
            createCameraSource();
        } else {
            requestCameraPermission();
        }

Request permission:

    private void requestCameraPermission() {
        Log.w(TAG, "Camera permission is not granted. Requesting permission");

        final String[] permissions = new String[]{Manifest.permission.CAMERA};

        if (!ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.CAMERA)) {
            ActivityCompat.requestPermissions(this, permissions, RC_HANDLE_CAMERA_PERM);
            return;
        }

        final Activity thisActivity = this;

        View.OnClickListener listener = new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ActivityCompat.requestPermissions(thisActivity, permissions,
                        RC_HANDLE_CAMERA_PERM);
            }
        };

        Snackbar.make(mGraphicOverlay, R.string.permission_camera_rationale,
                Snackbar.LENGTH_INDEFINITE)
                .setAction(R.string.ok, listener)
                .show();
    }

AsyncLoaderTask example (Associate Android Developer Certification)

RandomLoader.java

public class RandomLoader extends AsyncTaskLoader<String> {

    public final String TAG = getClass().getSimpleName();
    public static final String ARG_WORD = "word";
    public static final int RANDOM_STRING_LENGTH = 100;
    private String mWord;

    public RandomLoader(Context context, Bundle args) {
        super(context);
        if (args != null)
            mWord = args.getString(ARG_WORD);
    }

    @Override
    public String loadInBackground() {
        if (mWord == null) {
            return null;
        }
        Log.d(TAG, "loadInBackground");
        return generateString(mWord);
    }

    @Override
    public void forceLoad() {
        Log.d(TAG, "forceLoad");
        super.forceLoad();
    }

    @Override
    protected void onStartLoading() {
        super.onStartLoading();
        Log.d(TAG, "onStartLoading");
        forceLoad();
    }

    @Override
    protected void onStopLoading() {
        super.onStopLoading();
        Log.d(TAG, "onStopLoading");
    }

    @Override
    public void deliverResult(String data) {
        Log.d(TAG, "deliverResult");
        super.deliverResult(data);
    }


    private String generateString(String characters) {
        Random rand = new Random();
        char[] text = new char[RANDOM_STRING_LENGTH];
        for (int i = 0; i < RANDOM_STRING_LENGTH; i++) {
            text[i] = characters.charAt(rand.nextInt(characters.length()));
        }
        return new String(text);
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity implements
        LoaderManager.LoaderCallbacks<String> {

    public final String TAG = this.getClass().getSimpleName();
    private TextView mResultTextView;
    public static final int LOADER_ID = 1;
    private Loader<String> mLoader;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mResultTextView = (TextView) findViewById(R.id.resultTxt);

        Bundle bundle = new Bundle();
        bundle.putString(RandomLoader.ARG_WORD, "test");
        // Инициализируем загрузчик с идентификатором
        // Если загрузчик не существует, то он будет создан,
        // иначе он будет перезапущен.
        mLoader = getSupportLoaderManager().initLoader(LOADER_ID, bundle, this);
    }

    // Будет вызван, если до этого не существовал
    // Это значит, что при повороте не будет вызываться
    // так как предыдущий загрузчик с данным ID уже был создан ранее
    // Будет также вызван при рестарте через метод LoaderManager.restartLoader()
    @Override
    public Loader<String> onCreateLoader(int id, Bundle args) {
        // Создаем новый CursorLoader с нужными параметрами
        Loader<String> mLoader = null;
        // условие можно убрать, если вы используете только один загрузчик
        if (id == LOADER_ID) {
            mLoader = new RandomLoader(this, args);
            Log.d(TAG, "onCreateLoader");
        }
        return mLoader;
    }

    // Вызовется, когда загрузчик закончит свою работу. Вызывается в основном потоке
    // Может вызываться несколько раз при изменении данных
    // Также вызывается при поворотах
    @Override
    public void onLoadFinished(Loader<String> loader, String data) {
        Log.d(TAG, "onLoadFinished");
        mResultTextView.setText(data);

        // Если используется несколько загрузчиков, то удобнее через оператор switch-case
//        switch (loader.getId()) {
//            case LOADER_ID:
//                // Данные загружены и готовы к использованию
//
//                break;
//        }
        // список теперь содержит данные на экране
    }

    // Вызовется при уничтожении активности
    @Override
    public void onLoaderReset(Loader<String> loader) {
        Log.d(TAG, "onLoaderReset");
    }

    public void onClick(View view) {
        Log.d(TAG, "startLoad");
        mLoader.onContentChanged();
    }
}

Source

Loader (Associate Android Developer Certification)

LoaderManager controls all loaders. LoaderCallbacks interface has 3 methods.

1. OnCreateLoader – here loader is created
2. OnLoadFinished – loader loaded data
3. OnLoaderReset – loader relodes data

Following is order of method calls when Activity created:

Application.onCreate()
Activity.onCreate()
LoaderManager.LoaderCallbacks.onCreateLoader()
Activity.onStart()
Activity.onResume()
LoaderManager.LoaderCallbacks.onLoadFinished()

Following is order of method calls when configuration change happens:

Application:config changed
Activity.onCreate
Activity.onStart
[No call to the onCreateLoader]
LoaderManager.LoaderCallbacks.onLoadFinished
[optionally if searchview has text in it]
SearchView.onQueryChangeText()
RestartLoader
LoaderManager.LoaderCallbacks.onCreateLoader
LoaderManager.LoaderCallbacks.onLoadFinished

Following is order of method calls when activity destroys:

Activity.onStop()
Activity.onDestroy()
LoaderManager.LoaderCallbacks.onLoaderReset()

Loader is dedicated to load data from disk, database, content provider, network or other process asyncroniously.
There are 3 types of Loader: Loader, AsyncTaskLoader and CursorLoader.Base Loader class is not much useful.