Friday 19 December 2014

Android Programming Tips and Tricks


Showing Toast in Android

//Toast shown for  short period of time
Toast.makeText(getApplicationContext(), "Toast Message", Toast.LENGTH_SHORT).show();

//Toast shown for long period of time
Toast.makeText(getApplicationContext(), "Toast Message", Toast.LENGTH_LONG).show();
 
OR using custom layout for your toast

Toast myToast = new Toast(getApplicationContext());
myToast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
myToast.setDuration(Toast.LENGTH_LONG);
myToast.setView(myLayout);
myToast.show();


Getting all running Apps in Android

    private List<String> getRunningApps() {
        ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        PackageManager packageManager = getPackageManager();
        final List<RunningAppProcessInfo> runningProcesses = activityManager.getRunningAppProcesses();
        List<String> runningAppNames = new ArrayList<String>();
        for(RunningAppProcessInfo processInfo : runningProcesses) {
            CharSequence appName = null;
            try {
                appName = packageManager.getApplicationLabel(packageManager.getApplicationInfo(processInfo.processName, PackageManager.GET_META_DATA));
                runningAppNames.add(appName.toString());
            } catch (NameNotFoundException e) {
                Log.e(TAG,"Application info not found for process : " + processInfo.processName,e);
            }
        }
        return runningAppNames;
    }


Above code required permission -

  <uses-permission android:name="android.permission.GET_TASKS" />

Killing Background App

You can use  -

 ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
activityManager.killBackgroundProcesses(packageName);


You can't kill the app in the foreground (your App) by this. You need to finish(). Also note this is for API 8 and above and needs permission KILL_BACKGROUND_PROCESSES.

Dynamically Creating Layout

LinearLayout linearLayout = new LinearLayout(this);
linearLayout.setOrientation(LinearLayout.VERTICAL);
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
Button button = new Button(this);
button.setText(appName);
linearLayout.addView(button, layoutParams);

Adding Scroll bar over a Layout

LinearLayout rootLinearLayout = new LinearLayout(this);
LinearLayout linearLayout = new LinearLayout(this);
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
ScrollView scrollView = new ScrollView(this);
scrollView.addView(linearLayout, layoutParams);
rootLinearLayout.addView(scrollView, layoutParams);

Closing current Activity

finish();
return;

Note : You should put a return statement after that finish, because the method that called finish will be executed completely otherwise.

Getting Resources

getResources().getString(R.string.app_name);
getResources().getLayout(R.layout.myLayout); 
getResources().getColor(R.color.MY_RED);

Resources are under res directory. For example String resources are in res/string.xml  with content like - 

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Simple App Killer</string>
    <string name="about">About</string>

</resources>

Getting View or Activity Content View

findViewById(R.id.myView);
this.getWindow().getDecorView().findViewById(android.R.id.content);
this.findViewById(android.R.id.content);
this.findViewById(android.R.id.content).getRootView(); 

Note : R.layout.* are layouts you provide (in res/layout, for example).android.R.layout.* are layouts that ship with the Android SDK. Infact R.layout is actually shortcut for your.package.R.layout

Creating Menu

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.test_menu, menu);
        return true;
    }

You need to override onCreateOptionsMenu method and use MenuInflater to inflate your menu. You also need to provide menu .Create a file name test_menu.xml under res/menu folder with content like -

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
   
<item android:id="@+id/about"
          android:title="@string/about" />

</menu>

To set onclick on the menu items you need to override onOptionsItemSelected method as follows -

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        switch (item.getItemId()) {
             case R.id.about:
                Toast.makeText(getApplicationContext(), "This App is created by Aniket Thakur", Toast.LENGTH_LONG).show();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    } 

Getting Managers

ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
PackageManager packageManager = getPackageManager();

Note : these manages will not be available before onCreate() method. Also recollect these managers form second layer of Android architecture after application layer. These managers talk to the kernel layer using native libraries and android runtime.

Hiding Action Bar App Icon and App Name

getActionBar().setDisplayShowTitleEnabled(false);
getActionBar().setDisplayShowHomeEnabled(false)



Note : This requires API level 11 or above.

Saving Persistent Data

When you application needs to save some persistent data you should always do it in onPause() methods. Because if android OS kills your process then onStop() and onDestroy() methods are never called.

Starting new Activity with startActivity() and startActivityForResult() methods

You can start a new activity by creating an intent object and then calling 
  • startActivity(Intent) [Simply starts new Activity]
  • startActivityForResult(Intent, int) [Start new Activity expecting some result from new activity to be sent to the activity from which new activity was started].
You can also send some extra information in the intent using Intent classes putExtra() method. Later you can reference the intent that started the new activity in the new activity as getIntent() and then retrieve the additional information as getStringExtra().

MyActivity :

Intent intent = new Intent(this, MyNewActivity.class);
intent.putExtra("musicEnabled", "yes");
startActivity(intent);



MyNewActivity :

Intent intent = getIntent();
String musicEnabled = intent.getStringExtra("musicEnabled");
//more logic here   

If you use startActivityForResult(Intent, int) method [if you need to activity you are starting to return some data back to the activity that started it] then you need to call -

MyActivity  :

static private final int GET_TEXT_REQUEST_CODE = 1;
Intent intent = new Intent(this, NewActivity.class);
startActivityForResult(intent,GET_TEXT_REQUEST_CODE);


you can then retrieve the returned result in a callback method -

MyActivity  :

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.i("NewActivity", "Entered onActivityResult()");
       
        if(resultCode == Activity.RESULT_OK && requestCode == GET_TEXT_REQUEST_CODE){
            myTextView.setText(data.getStringExtra("MY_VALUE"));
        } 
    } 


and then in your NewActivity class you have to set the result with RESULT_OK code as follows -

MyNewActivity  :

        String input = myEditText.getText().toString();
        Intent intent  = new Intent();
        intent.putExtra("MY_VALUE",input );
        setResult(Activity.RESULT_OK, intent);
        finish();


Showing Notifications

Code is as follows - 

Intent browseIntent = new Intent(Intent.ACTION_VIEW, Uri
        .parse("http://google.com"));
PendingIntent pendingIntent = PendingIntent.getActivity(
        MainActivity.this, 0, browseIntent,
        PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Builder notificationBuilder = null;
notificationBuilder = new Notification.Builder(
        MainActivity.this)
        .setSmallIcon(android.R.drawable.stat_sys_warning)
        .setAutoCancel(true).setContentIntent(pendingIntent)
        .setContentTitle("Notification Title")
        .setContentText("Notification Content Text")
        .setTicker("Ticker Text");

NotificationManager notificationManager = (NotificationManager) MainActivity.this
        .getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(12345, notificationBuilder.build());


Ticker Text will be seen as -



and you can see the actual notification on pulling down the notification bar



You can also set your own layout as view for the notification. For that you can do -

RemoteViews mContentView = new RemoteViews(MainActivity.this

        .getPackageName(), R.layout.activity_main);

notificationBuilder = new Notification.Builder(

        MainActivity.this).setContent(mContentView); 



Note: PendingIntent is a special type of intent that allows 3rd party code (in this case Notification Manager) to execute application code with the same permission as the application. When you click on above notification browser should open and display google.com.

More to Come....
PS : This list will keep updating. If you want me to add something in above list please provide it in the comments.

Good Read

Difference between Running Task and Running Process in Android

Background

Tasks and processes are different in Android. I am going to discuss the same in this post. I ran into this question when I was trying to figure out the difference between the calls

final List<RunningTaskInfo> runningTasks = activityManager.getRunningTasks(Integer.MAX_VALUE);

and

final List<RunningAppProcessInfo> runningProcesses = activityManager.getRunningAppProcesses();

So lets see the difference.


Running Task and Running Process in Android

Android has Linux kernel. So process is similar to processes in Linux. Each process can have multiple threads. When a process starts it is single thread execution by default. This thread is called the main thread or UI thread. You may have other worker or asynchronous threads running in a process.

Task or Application on the other hand can be visualized as set of activities in an application. It is possible that each activity in the task is configured to run in different processes. Same goes for other entitles of Android - services, providers etc. Infact components of different tasks/applications can run in same process (provided that the applications share the same Linux user ID and are signed with the same certificates).

When System memory is low of running application an older process is killed. Again note this may have components of different application.

activityManager.getRunningTasks(Integer.MAX_VALUE)


Above will give you Running tasks or rather lets call it application consisting of set of activities. (List of RunningTaskInfo objects). This in turn will have two main things.
  1. baseActivity : component launched as the first activity in the task
  2. topActivity : activity component at the top of the history stack of the task

and

activityManager.getRunningAppProcesses()


Above will give all running processes in the System. Since it is a process it will have associated pid (processId) and `uid (userId). Some of the important fields here are -
  1. processName : The name of the process that this object is associated with
  2. pid : The pid of this process; 0 if none
  3. uid : The user id of this process.
  4. pkgList : All packages that have been loaded into the process.

To get all running app name we do something like - 

    public List<String> getRunningApps() {
        ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        PackageManager packageManager = getPackageManager();
        final List<RunningAppProcessInfo> runningProcesses = activityManager.getRunningAppProcesses();
        List<String> runningAppNames = new ArrayList<String>();
        for(RunningAppProcessInfo processInfo : runningProcesses) {
            CharSequence appName = null;
            try {
                appName = packageManager.getApplicationLabel(packageManager.getApplicationInfo(processInfo.processName, PackageManager.GET_META_DATA));
                runningAppNames.add(appName.toString());
            } catch (NameNotFoundException e) {
                Log.e(TAG,"Application info not found for process : " + processInfo.processName,e);
            }
        }
        return runningAppNames;
    }

 In above code we are essentially getting information about all running processes. Then with the help of process name of each such process we are getting corresponding application package.


Interesting Read

First of all you need to understand what you can kill and what not. By android's point of view an application is not like other OSes. An android application consists of many components (activities, broadcast receivers, services, most important tasks etc) which are packed in a package. A package can have more that one processes running depending on its components running. 

Now the interesting part is that an android package isn't considered (by android) "killed" or "stopped" if any or all of its processes have killed, in fact a package can still running even with no processes running at all. 

You can see this effect if you start an emulator start a program (i.e. Browser) and then kill its process via DDMS, after that go to the application's package settings (Settings --> Applications --> Manage Applications --> All --> Browser), you can see the "Force Stop" button enabled, this means that the application is still running (from android's point of view). 

What happened here is that the application has one or more tasks "frozen". That is, android has saved the state of the application's activities (task or tasks) and so the package is still running or better if the user returns to it he will land on the last thing he was doing. Now if you click the "Force Stop" button, android will discard all of these "frozen" tasks and when the user returns to the application he will see the first activity. 

A Task is something you cannot kill (since froyo) only the user (from "Force Stop" button), the system or a third party application which is signed with the same key of the system can do that (and maybe a root capable application but I have not confirmed this). On the other hand a Process is something you can kill and reclaim the memory it uses, as long as you follow some restrictions:
  1. You have the "android.permission.KILL_BACKGROUND_PROCESSES" permission.
  2. The processes are not system or root processes.
  3. The process is not belonging to a component which is persistent.
  4. The process is not a critical for the system to operate by any other means.

Besides the no 1 rule you do not have to do something about them, android will take care of this.

ActivityManager has a handy function you can use in order to kill all of the processes a package has at once. When you invoke it android will kill any process can be killed and thus freeing up some memory. However the state of the tasks for this package will be saved and when the user returns to the application he will see the last thing he was doing unless the system itself has killed them. This can occur either because it needs resources or the state was saved long time ago (about 30 minutes). The side-effect is that because users are thinking that all applications are like in desktop operating systems, they do not believe that the application is really closed but this is the life with android.

(Source - SO)

Related Links

t> UA-39527780-1 back to top