Android service (1)

Service as one of the four components of Android, in every application plays a very important role. It is mainly used in the background to deal with some time-consuming logic, or to perform some of the tasks that require long-term operation. When necessary, we can even exit the program in the case, so that Service in the background to keep running.

Basic usage of Service

Service on the most basic usage is how to start a Service, and start the Service method and start the Activity is very similar, need to use Intent to achieve, the following we through a specific example to look at.

Create a new Android project, the project name is called MyService Project, where I chose to use the 4.0 API.

And then create a new service inherited from the Service, and rewrite the parent class onCreate (), onStartCommand () and onDestroy () method, as follows:

public class MyService extends Service {  
  
    public static final String TAG = "MyService";  
  
    @Override  
    public void onCreate() {  
        super.onCreate();  
        Log.d(TAG, "onCreate() executed");  
    }  
  
    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
        Log.d(TAG, "onStartCommand() executed");  
        return super.onStartCommand(intent, flags, startId);  
    }  
      
    @Override  
    public void onDestroy() {  
        super.onDestroy();  
        Log.d(TAG, "onDestroy() executed");  
    }  
  
    @Override  
    public IBinder onBind(Intent intent) {  
        return null;  
    }  
  
}  

You can see that we just printed a word in the onCreate (), onStartCommand (), and onDestroy () methods, and did nothing else.

And then open or create activity_main.xml as the main layout file for the program, as follows:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:orientation="vertical" >  
  
    <Button  
        android:id="@+id/start_service"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="Start Service" />  
  
    <Button  
        android:id="@+id/stop_service"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="Stop Service" />  
  
</LinearLayout> 

We added two buttons in the layout file, one for starting Service, one for stopping Service. And then open or create a MainActivity as the main activity of the program, in which to join the Start Service and stop the Service logic, the code is as follows:

public class MainActivity extends Activity implements OnClickListener {  
  
    private Button startService;  
  
    private Button stopService;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        startService = (Button) findViewById(R.id.start_service);  
        stopService = (Button) findViewById(R.id.stop_service);  
        startService.setOnClickListener(this);  
        stopService.setOnClickListener(this);  
    }  
  
    @Override  
    public void onClick(View v) {  
        switch (v.getId()) {  
        case R.id.start_service:  
            Intent startIntent = new Intent(this, MyService.class);  
            startService(startIntent);  
            break;  
        case R.id.stop_service:  
            Intent stopIntent = new Intent(this, MyService.class);  
            stopService(stopIntent);  
            break;  
        default:  
            break;  
        }  
    }  
  
}  

You can see that in the click event of the Start Service button, we build an Intent object and call the startService () method to start MyService. Then in the Stop Serivce button’s click event, we also constructed an Intent object and called the stopService () method to stop MyService. Code logic is very simple, I believe I do not need to do more to explain it.

Also note that every service in the project must be registered in the AndroidManifest.xml, so you need to edit the AndroidManifest.xml file, the code is as follows:

<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    package="com.example.servicetest"  
    android:versionCode="1"  
    android:versionName="1.0" >  
  
    <uses-sdk  
        android:minSdkVersion="14"  
        android:targetSdkVersion="17" />  
  
    <application  
        android:allowBackup="true"  
        android:icon="@drawable/ic_launcher"  
        android:label="@string/app_name"  
        android:theme="@style/AppTheme" >  
          
    ……  
  
        <service android:name="com.example.servicetest.MyService" >  
        </service>  
    </application>  
  
</manifest>

In this case, a simple program with Service function is written, and now we will run the program, and click the Start Service button, you can see LogCat print log.

You will see that when you start a Service, it will call the Service onCreate () and onStartCommand () method.

So what if I click on the Start Service button again?

You can see that this time only onStartCommand () method is implemented, onCreate () method is not implemented, why is this? This is because the onCreate () method will only be called when the Service is first created. If the current Service has already been created, the onCreate () method will not be executed anyway, regardless of how the startService () method is called. So you can click on the Start Service button several more times, each time there will only be onStartCommand () method in the print log.

We can also go to the phone’s application management interface to check myService is not running.

Go back to the ServiceTest program and click the Stop Service button to stop MyService.

Service and Activity communication

Above we learned the basic usage of the Service, after starting Service, you can in the onCreate () or onStartCommand () method to perform some specific logic. But then the relationship between Service and Activity is not large, but Activity notice Service about: “You can start.” Then Service to busy their own things. Then there is no way to make the two of them more related to it? For example, in the Activity can be specified to allow Service to perform what task. Of course, only need to make Activity and Service to establish a link just fine.

Observe the code in MyService, you will find that there is always an onBind () method we have not used, this method is used to establish association with the Activity, modify the code in MyService, as follows:

public class MyService extends Service {  
  
    public static final String TAG = "MyService";  
  
    private MyBinder mBinder = new MyBinder();  
  
    @Override  
    public void onCreate() {  
        super.onCreate();  
        Log.d(TAG, "onCreate() executed");  
    }  
  
    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
        Log.d(TAG, "onStartCommand() executed");  
        return super.onStartCommand(intent, flags, startId);  
    }  
  
    @Override  
    public void onDestroy() {  
        super.onDestroy();  
        Log.d(TAG, "onDestroy() executed");  
    }  
  
    @Override  
    public IBinder onBind(Intent intent) {  
        return mBinder;  
    }  
  
    class MyBinder extends Binder {  
  
        public void startDownload() {  
            Log.d("TAG", "startDownload() executed");  
            // Perform a specific download task
        }  
  
    }  
  
}  

Here we add a MyBinder class inherited from the Binder class, and then add a MyBinder startDownload () method used to perform the download task in the background, of course, here is not really to download something, just a test, so The startDownload () method simply prints a row of logs.

And then modify the code in activity_main.xml to add buttons for binding services and unbind services in the layout file:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:orientation="vertical" >  
  
    <Button  
        android:id="@+id/start_service"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="Start Service" />  
  
    <Button  
        android:id="@+id/stop_service"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="Stop Service" />  
  
    <Button  
        android:id="@+id/bind_service"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="Bind Service" />  
      
    <Button   
        android:id="@+id/unbind_service"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="Unbind Service"  
        />  
      
</LinearLayout> 

Next, modify the code in MainActivity to associate the MainActivity and MyService with the following code:

public class MainActivity extends Activity implements OnClickListener {  
  
    private Button startService;  
  
    private Button stopService;  
  
    private Button bindService;  
  
    private Button unbindService;  
  
    private MyService.MyBinder myBinder;  
  
    private ServiceConnection connection = new ServiceConnection() {  
  
        @Override  
        public void onServiceDisconnected(ComponentName name) {  
        }  
  
        @Override  
        public void onServiceConnected(ComponentName name, IBinder service) {  
            myBinder = (MyService.MyBinder) service;  
            myBinder.startDownload();  
        }  
    };  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        startService = (Button) findViewById(R.id.start_service);  
        stopService = (Button) findViewById(R.id.stop_service);  
        bindService = (Button) findViewById(R.id.bind_service);  
        unbindService = (Button) findViewById(R.id.unbind_service);  
        startService.setOnClickListener(this);  
        stopService.setOnClickListener(this);  
        bindService.setOnClickListener(this);  
        unbindService.setOnClickListener(this);  
    }  
  
    @Override  
    public void onClick(View v) {  
        switch (v.getId()) {  
        case R.id.start_service:  
            Intent startIntent = new Intent(this, MyService.class);  
            startService(startIntent);  
            break;  
        case R.id.stop_service:  
            Intent stopIntent = new Intent(this, MyService.class);  
            stopService(stopIntent);  
            break;  
        case R.id.bind_service:  
            Intent bindIntent = new Intent(this, MyService.class);  
            bindService(bindIntent, connection, BIND_AUTO_CREATE);  
            break;  
        case R.id.unbind_service:  
            unbindService(connection);  
            break;  
        default:  
            break;  
        }  
    }  
  
}  

You can see that here we first create an anonymous class of ServiceConnection, which rewrites the onServiceConnected () method and the onServiceDisconnected () method, which are invoked when the Activity is associated with the service and associated with the service. In the onServiceConnected () method, we have passed down to get an instance of MyBinder. With this example, the relationship between Activity and Service becomes very tight. Now we can in the Activity in accordance with the specific scene to call MyBinder in any public method, that is, to achieve the Activity Command Service Service What to do what function.

Of course, now Activity and Service is not linked to it, this feature is in the Bind Service button to complete the click event. You can see that here we are still building an Intent object, and then call the bindService () method to bind the Activity and Service. BindService () method to receive three parameters, the first parameter is just to build the Intent object, the second parameter is created in front of the ServiceConnection instance, the third parameter is a flag, where the incoming BIND_AUTO_CREATE said in the Activity And Service established after the association automatically create Service, which will make MyService onCreate () method to be implemented, but onStartCommand () method will not be implemented.

And then how do we want to relieve the association between Activity and Service? Call the unbindService () method on it, this is the Unbind Service button click event to achieve the logic.

Now let’s run the program again, click on the Bind Service button in MainActivity.

Also note that any Service is generic across the entire application, that is, MyService can not only be associated with MainActivity, but also can be associated with any of the activities, and in the establishment of the association they can get to the same MyBinder instance.

How to destroy Service

In this part of the basic usage of Service, we introduced the simplest case of Destroy Service, click the Start Service button to start Service, and then click the Stop Service button to stop Service, so MyService was destroyed.

So if we are clicking on the Bind Service button? Because the binding service when the designated bit is BIND_AUTO_CREATE, indicating that the Bind Service button when the Service will be created, then how should destroy the Service? In fact, it is very simple, click on the Unbind Service button, the association between the Activity and Service can be lifted.

The above two kinds of destruction methods are well understood. So what if we both clicked the Start Service button and clicked on the Bind Service button? This time you will find that, whether you are a single click on the Stop Service button or Unbind Service button, Service will not be destroyed, the need to click the two buttons, Service will be destroyed. In other words, click the Stop Service button will only stop the Service, click the Unbind Service button will only let Service and Activity release association, a Service must be in any and no association and deal with the stop state will be destroyed.

To confirm that we add a line of print log to the Stop Service and Bindservice button’s click event:

public void onClick(View v) {  
    switch (v.getId()) {  
    case R.id.start_service:  
        Intent startIntent = new Intent(this, MyService.class);  
        startService(startIntent);  
        break;  
    case R.id.stop_service:  
        Log.d("MyService", "click Stop Service button");  
        Intent stopIntent = new Intent(this, MyService.class);  
        stopService(stopIntent);  
        break;  
    case R.id.bind_service:  
        Intent bindIntent = new Intent(this, MyService.class);  
        bindService(bindIntent, connection, BIND_AUTO_CREATE);  
        break;  
    case R.id.unbind_service:  
        Log.d("MyService", "click Unbind Service button");  
        unbindService(connection);  
        break;  
    default:  
        break;  
    }  
}  

And then re-run the program, first click the Start Service button, and then click the Bind Service button, so the service will start up, and the establishment of an association with the Activity. And then click the Stop Service button Service will not be destroyed, and then click the Unbind Service button, Service will be destroyed.

We should always remember in the Service’s onDestroy () method to clean up those no longer use the resources to prevent the Service is destroyed after some of the objects are no longer occupied by the memory.

The relationship between Service and Thread

Many Android beginners may have such doubts, Service and Thread in the end what is the relationship? When should I use Service, when should I use Thread? The answer may be a bit surprised you, because there is no relationship between Service and Thread!

The reason why many people will link them up, mainly because the background of Service background. Thread we all know that is used to open a sub-thread, here to perform some time-consuming operation will not block the main thread of the operation. And Service we initially understand, always think it is used to deal with some background tasks, some of the more time-consuming operation can also be placed here to run, which will make people confused. But if i tell you that Service is actually running in the main thread, do you think it has anything to do with Thread? Let’s take a look at this cruel fact.

In the MainActivity onCreate () method to add a line to print the current thread id statement:

Log.d("MyService", "MainActivity thread id is " + Thread.currentThread().getId());  

And then in the MyService onCreate () method also joined a line to print the current thread id statement:

Log.d("MyService", "MyService thread id is " + Thread.currentThread().getId());  

Now re-run the program and click the Start Service button.

You can see that their thread id is exactly the same, which confirmed that the service is indeed running in the main thread, that is, if you are in the Service prepared a very time-consuming code, the program will appear ANR.

Can you exclaim, is not that kidding? What time do I have to use Service? In fact, we should not background and sub-thread together on the line, this is two completely different concepts. Android background means that it’s running is completely dependent on the UI. Even if Activity is destroyed, or the program is closed, as long as the process is still, Service can continue to run. For example, some applications, always need to always maintain a heartbeat connection with the server, you can use Service to achieve. You may ask, the front is not just verified Service is running in the main thread Lane? Where the implementation of the heartbeat has been connected, do not block the main thread of the operation? Of course, but we can create a sub-thread in the service, and then here to deal with time-consuming logic no problem.

Create Front Service

The amount, since in the service also to create a sub-thread, then why not directly created in the Activity? This is because the Activity is difficult to control the Thread, when the Activity is destroyed, there is no other way to re-get to the previously created sub-thread instance. But also in an Activity to create a sub-thread, another Activity can not operate on it. But the Service is different, all the Activity can be associated with the Service, and then can be very convenient to operate the method, even if the Activity was destroyed, and then as long as the re-established with the Service, they can get to the original Service Example of Binder. Therefore, the use of Service to deal with background tasks, Activity can be assured to finish, do not need to worry about the background tasks can not control the situation.

A more standard service can be written as:

@Override  
public int onStartCommand(Intent intent, int flags, int startId) {  
    new Thread(new Runnable() {  
        @Override  
        public void run() {  
            // Start performing background tasks
        }  
    }).start();  
    return super.onStartCommand(intent, flags, startId);  
}  
  
class MyBinder extends Binder {  
  
    public void startDownload() {  
        new Thread(new Runnable() {  
            @Override  
            public void run() {  
                // Perform a specific download task
            }  
        }).start();  
    }  
  
}  

Then we look at how to create a front desk Service it, in fact, not complicated, modify the code in MyService, as follows:

public class MyService extends Service {  
  
    public static final String TAG = "MyService";  
  
    private MyBinder mBinder = new MyBinder();  
  
    @Override  
    public void onCreate() {  
        super.onCreate();  
        Notification notification = new Notification(R.drawable.ic_launcher,  
                "There is a notice coming", System.currentTimeMillis());  
        Intent notificationIntent = new Intent(this, MainActivity.class);  
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,  
                notificationIntent, 0);  
        notification.setLatestEventInfo(this, "This is the title of the notification", "This is the content of the notice",  
                pendingIntent);  
        startForeground(1, notification);  
        Log.d(TAG, "onCreate() executed");  
    }  
  
    .........  
  
}  

Here is only modify the MyService onCreate () method code. You can see that we first created a Notification object and then called its setLatestEventInfo () method to initialize the layout and data for the notification, and set the click notification to open the MainActivity. And then call the startForeground () method can make MyService into a front service, and will notify the image displayed.

Now run the program again, and click the Start Service or Bind Service button, MyService will be the front service mode to start, and the system status bar will pop up a bar icon, drop the status bar can see the details of the notice.

Advertisements

Android Custom Camera(2)

Through the introduction of an Android custom Camera (一), we have been able to complete a camera based on the demo, of course, there are a lot of attention to the details of the problem, such as the preview direction, set the preview ratio and return the proportion of pictures and so on , The details can see previous blog, this time I will enrich the camera’s function to join the flash mode, square shooting, delay shooting and front and rear camera switching function, then one by one to start it. (There will be a complete source address below).

Flash mode

The camera’s flash mode there are three, automatic, close, open, the code is also better understand, before the camera can switch calls. Note I added a note in code below:

/**
     * turnLightOff
     *
     * @param mCamera
     */
    public void turnLightOff(Camera mCamera) {
        if (mCamera == null) {
            return;
        }
        Camera.Parameters parameters = mCamera.getParameters();
        if (parameters == null) {
            return;
        }
        List<String> flashModes = parameters.getSupportedFlashModes();
        String flashMode = parameters.getFlashMode();
        // Check if camera flash exists
        if (flashModes == null) {
            return;
        }
        if (!Camera.Parameters.FLASH_MODE_OFF.equals(flashMode)) {
            // Turn off the flash
            if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {
                parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                mCamera.setParameters(parameters);
            } else {
            }
        }
    }

2 automatic mode:

/**
     * turnLightAuto
     *
     * @param mCamera
     */
    public void turnLightAuto(Camera mCamera) {
        if (mCamera == null) {
            return;
        }
        Camera.Parameters parameters = mCamera.getParameters();
        if (parameters == null) {
            return;
        }
        List<String> flashModes = parameters.getSupportedFlashModes();
        // Check if camera flash exists
        if (flashModes == null) {
            // Use the screen as a flashlight (next best thing)
            return;
        }
        String flashMode = parameters.getFlashMode();
        if (!Camera.Parameters.FLASH_MODE_AUTO.equals(flashMode)) {
            // Turn on the flash
            if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {
                parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                mCamera.setParameters(parameters);
            } else {
            }
        }
    }

3 open

 @param mCamera
     */
    public void turnLightOn(Camera mCamera) {
        if (mCamera == null) {
            return;
        }
        Camera.Parameters parameters = mCamera.getParameters();
        if (parameters == null) {
            return;
        }
        List<String> flashModes = parameters.getSupportedFlashModes();
        // Check if camera flash exists
        if (flashModes == null) {
            // Use the screen as a flashlight (next best thing)
            return;
        }
        String flashMode = parameters.getFlashMode();
        if (!Camera.Parameters.FLASH_MODE_ON.equals(flashMode)) {
            // Turn on the flash
            if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {
                parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                mCamera.setParameters(parameters);
            } else {
            }
        }
    }

Square shot

Here I want to talk about how I do, at present I think because we look at the proportion of framing frames must meet the size of mobile phone support, there are surfaceView and preview the proportion of the same size, so that we can not determine the size of the frame is specific How many, so I achieved a square shot with the way to cover the viewfinder frame, shooting time frame will be covered into a square, in the back of the picture and then cut it into a square can be, in the current project I also In this way, because many mobile phones are directly supporting the square size, where I used two attribute animation to cover the viewfinder, the code is as follows, here is to calculate the height to cover.

/**
     * camera_square
     */
    public void camera_square_0() {
        camera_square.setImageResource(R.drawable.btn_camera_size1_n);

        ValueAnimator anim = ValueAnimator.ofInt(0, animHeight);
        anim.setDuration(300);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int currentValue = Integer.parseInt(animation.getAnimatedValue().toString());
                RelativeLayout.LayoutParams Params = new RelativeLayout.LayoutParams(screenWidth, currentValue);
                Params.setMargins(0, SystemUtils.dp2px(context, 44), 0, 0);
                homeCustom_cover_top_view.setLayoutParams(Params);

                RelativeLayout.LayoutParams bottomParams = new RelativeLayout.LayoutParams(screenWidth, currentValue);
                bottomParams.setMargins(0, screenHeight - menuPopviewHeight - currentValue, 0, 0);
                homeCustom_cover_bottom_view.setLayoutParams(bottomParams);
            }

        });
        anim.start();

        homeCustom_cover_top_view.bringToFront();
        home_custom_top_relative.bringToFront();
        homeCustom_cover_bottom_view.bringToFront();
        index++;
    }

    public void camera_square_1() {
        camera_square.setImageResource(R.drawable.btn_camera_size2_n);

        ValueAnimator anim = ValueAnimator.ofInt(animHeight, 0);
        anim.setDuration(300);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int currentValue = Integer.parseInt(animation.getAnimatedValue().toString());
                RelativeLayout.LayoutParams Params = new RelativeLayout.LayoutParams(screenWidth, currentValue);
                Params.setMargins(0, SystemUtils.dp2px(context, 44), 0, 0);
                homeCustom_cover_top_view.setLayoutParams(Params);

                RelativeLayout.LayoutParams bottomParams = new RelativeLayout.LayoutParams(screenWidth, currentValue);
                bottomParams.setMargins(0, screenHeight - menuPopviewHeight - currentValue, 0, 0);
                homeCustom_cover_bottom_view.setLayoutParams(bottomParams);
            }
        });
        anim.start();
        index = 0;
    }

Delayed shooting

First of all, say the principle of delay shooting, in fact, more than one way to achieve, where I use the thread plus the way the main code is as follows, first recorded a delay time, and then decrement this time every 1s, and finally it is equal to 0 When the implementation of the shooting code, the effect I will not paste it, you can download the code to run to see, that is, a large number of seconds on the screen

new Thread(new Runnable() {
                            @Override
                            public void run() {
                                while (delay_time > 0) {
                                    //Count in seconds
                                    try {
                                        Thread.sleep(1000);
                                    } catch (InterruptedException e) {
                                        mHandler.sendEmptyMessage(AppConstant.WHAT.ERROR);
                                        return;
                                    }
                                    delay_time--;
                                    mHandler.sendEmptyMessage(AppConstant.WHAT.SUCCESS);
                                }
                            }
                        }).start();

Switch the front rear camera

Almost all of the camera program needs this function, must be able to front and rear ah, that in fact, this is also relatively simple to achieve, when the camera is in the process of previewing before and after the switch must first release the camera resources, and then And then open the preview, switch the camera is nothing more than switch cameraId, here look at the next code:

 public void  switchCamera() {
        releaseCamera();
        //This method getNumberOfCameras () is introduced from the API Level 9, get the number of cameras in the normal normal mobile phone only one camera, here I also follow a camera to deal with the
        mCameraId = (mCameraId + 1) % mCamera.getNumberOfCameras();
        mCamera = getCamera(mCameraId);
        if (mHolder != null) {
            startPreview(mCamera, mHolder);
        }
    }

Add watermark

The way to say that the function of the watermark it, plus watermark function is not difficult to achieve, it is rare to draw a good watermark, in fact, watermark is also in the camera to return to the bitmap to join, in fact, is painted with Canvas class, the core The code is as follows, assuming the camera returns the picture shown as bitmap:

Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(tempbitmap, left, top, paint);

Code is generally the case, through the canvas.drawBitmap method to draw up, of course, I am free to draw the position. But you record the location of the watermark when previewing, and then painted up properly.

The following is the source address:

https://github.com/jinguangyue/CustomCamera

Android custom Camera (1)

Get the camera and release the camera

First of all, there can only be a camera instance, after the camera must be released, then it also has its own life cycle, first get the camera, where an ID, this id can be set before the camera and rear camera, behind the blog I will join Code.

/**
     * getCamera
     * @return
     */
    private Camera getCamera(int id){
        Camera camera = null;
        try{
            camera = Camera.open(id);
        }catch (Exception e){

        }
        return camera;
    }

/**
     * releaseCamera
     */
    private void releaseCamera(){
        if(mCamera != null){
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }

Use the release of the camera after the use of resources, here is a reason to write, one step can not be less, I sometimes forget to write mCamera.setPreviewCallback (null);

Because the camera to real-time preview, that ordinary View can not meet the requirements of the drawing, and here to use a double buffer mechanism SurfaceView, the following we have to do is to Camera and SurfaceView binding, it needs another class The SurfaceHolder.

Here is a special mention of CameraUtil.getInstance (). SetCameraDisplayOrientation (this, mCameraId, camera);

I will write the source address, because the default preview of the Android system are horizontal, the basic operation is camera.setDisplayOrientation (90); direct rotation 90 degrees correction, but I was in the development of some mobile phones on the preview Came, and finally use this method to solve, and its basic principle is that some of the bottom of the mobile phone system on the preview of the preview, and some did not, that can be judged by the cameraInfo. SO this perfect solution to my problem, hope can help you:

/**
     * Preview
     */
    private void startPreview(Camera camera, SurfaceHolder holder){
        try {
      
            setupCamera(camera);
            camera.setPreviewDisplay(holder);
           
            CameraUtil.getInstance().setCameraDisplayOrientation(this, mCameraId, camera);
//            camera.setDisplayOrientation(90);
            camera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Set the SurfaceHolder

surfaceView = (SurfaceView)findViewById(R.id.surfaceView);
        mHolder = surfaceView.getHolder();
        mHolder.addCallback(this);

Where SurfaceHolder wants to add a callback method to see the comment:

@Override
    public void surfaceCreated(SurfaceHolder holder) {
    //Open the camera preview when the surface is created
        startPreview(mCamera, holder);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    //Call this method when the camera changes, at which point you should stop previewing and then restart
        mCamera.stopPreview();
        startPreview(mCamera, holder);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    //Release the camera resources when destroy
        releaseCamera();
    }

Here to elaborate on the setCamera method, without this method can also be a normal preview, but this method to set the camera’s preview size, return to the picture size, in particular, note that the preview size returns the size of the picture and the size of the surfaceView ratio Must be the same, or else the program crashes, see the code below

/**
     * Setting
     */
    private void setupCamera(Camera camera) {
        Camera.Parameters parameters = camera.getParameters();

        List<String> focusModes = parameters.getSupportedFocusModes();
        if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            // Autofocus mode is supported auto focus
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        }

        //Where the third parameter is the smallest size getPropPreviewSize Method will remove the minimum size of all supported sizes from the minimum size to the ascending order
        Camera.Size previewSize = CameraUtil.getInstance().getPropPreviewSize(parameters.getSupportedPreviewSizes(), 1000);
        parameters.setPreviewSize(previewSize.width, previewSize.height);

        Camera.Size pictrueSize = CameraUtil.getInstance().getPropPictureSize(parameters.getSupportedPictureSizes(), 1000);
        parameters.setPictureSize(pictrueSize.width, pictrueSize.height);

        camera.setParameters(parameters);

        Log.d("previewSize.width===", previewSize.width + "");
        Log.d("previewSize.height===", previewSize.height + "");

        /**
         * Set the size of the surfaceView Because the camera default is horizontal screen, so get the support size are also horizontal screen size
         * We in the startPreview method inside it correction over, but here we set the size of the surfaceView to pay attention to the time previewSize.height<previewSize.width
       
         * The general camera is the width of the screen here set to the screen width height adaptive you can also set the size you want
         */
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(screenWidth, screenWidth * previewSize.width/previewSize.height);
        //Here, of course, you can set the camera position, such as the center of the top here
        //params.gravity = Gravity.CENTER;
        surfaceView.setLayoutParams(params);
    }

There is also a place to pay special attention to is that you set the preview size and return the image size must be the current size of the phone support.

Here through getPropPictureSize and getPropPreviewSize get all the phone support the size of .the default camera preview are horizontal screen.
Here you can set a minimum preview width of 1000, as long as more than 1000 support size can be. Here is the last step is also very important, that is, Camera’s life cycle must be bound with the current Activity, so we do so:

@Override
    protected void onResume() {
        super.onResume();
        if(mCamera == null){
            mCamera = getCamera(mCameraId);
            if(mHolder != null){
                startPreview(mCamera, mHolder);
            }
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        releaseCamera();
    }

Here in the Activity to display when you start the camera preview, in the Activity onPause when the release of the camera resources on it. It can now preview can also take pictures wow, then take a camera method.

private void captrue() {
        mCamera.takePicture(null, null, new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
                //Convert data to a bitmap or you can save it directly as a file FileOutputStream
                //Here I believe that most of the other useful to add a watermark, such as follow-up and then explain
               Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
               CameraUtil.getInstance().setTakePicktrueOrientation(mCameraId, bitmap);
                //Where you can see the width of the print CameraUtil.getInstance().getPropPictureSize(parameters.getSupportedPictureSizes(), 200);
                // The minimum width of this setting affects the size of the returned picture so it is generally here that is around 1000
                Log.d("bitmapWidth==", bitmap.getWidth() + "");
                Log.d("bitmapHeight==", bitmap.getHeight() + "");
            }
        });
    }

Here we have a place to say that the above we have made a preview of the preview, that generated the picture we have to correct back ah, the implementation of CameraUtil.getInstance (). SetTakePicktrueOrientation (mCameraId, bitmap); of course, through Android.hardware.Camera. CameraInfo to operate.

The following is the source address:

https://github.com/jinguangyue/CustomCamera

Android Event distribution(2)

I remember in the previous article, I took everyone from Android Event distribution(一), I believe that read friends on the View event distribution has a more profound understanding.

Have not read the friends, please refer to the Android Event distribution(一), take you from Android Event distribution().

So today we will continue the last unfinished topic, from the perspective of source analysis ViewGroup event distribution.

First of all, let’s explore what is ViewGroup? What is the difference between it and ordinary View?

As the name suggests, ViewGroup is a collection of View, which contains a lot of sub-view and sub-ViewGroup, Android is the layout of all the parent or indirect parent class, such as LinearLayout, RelativeLayout are inherited from ViewGroup. But ViewGroup is actually a View, but compared to View, it can contain more sub-view and define the layout parameters of the function. ViewGroup inheritance diagram is as follows:

1

You can see that we usually use the various layouts of the project, all belong to the subclass of ViewGroup.

A brief introduction to the ViewGroup, we now through a Demo to demonstrate the Android VewGroup event distribution process it.

First we come from defining a layout, named MyLayout, inherited from LinearLayout, as follows:

public class MyLayout extends LinearLayout {  
  
    public MyLayout(Context context, AttributeSet attrs) {  
        super(context, attrs);  
    }  
  
}  

Then, open the main layout file activity_main.xml, where we add our custom layout:

<com.example.viewgrouptouchevent.MyLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:id="@+id/my_layout"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:orientation="vertical" >  
  
    <Button  
        android:id="@+id/button1"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="Button1" />  
  
    <Button  
        android:id="@+id/button2"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="Button2" />  
  
</com.example.viewgrouptouchevent.MyLayout> 

You can see that we have added two buttons in MyLayout, and then register the listener for both of the buttons and MyLayout in the MainActivity:

myLayout.setOnTouchListener(new OnTouchListener() {  
    @Override  
    public boolean onTouch(View v, MotionEvent event) {  
        Log.d("TAG", "myLayout on touch");  
        return false;  
    }  
});  
button1.setOnClickListener(new OnClickListener() {  
    @Override  
    public void onClick(View v) {  
        Log.d("TAG", "You clicked button1");  
    }  
});  
button2.setOnClickListener(new OnClickListener() {  
    @Override  
    public void onClick(View v) {  
        Log.d("TAG", "You clicked button2");  
    }  
});  

We are in MyLayout onTouch method, and Button1, Button2 onClick method are printed in a word. Now run the project, the effect is as follows:

2

Click Button1, Button2 and blank area, the print results are as follows:

3

You will find that when clicking the button, MyLayout registered onTouch method will not be implemented, only when the blank area will be implemented when the method. You can first understand the Button onClick method to consume the event, so the event will not continue to pass down.

It shows that the touch event in Android is first passed to View, and then passed to the ViewGroup? Now the conclusion is still too early, let us do an experiment again.

Look at the document you can see, ViewGroup has a onInterceptTouchEvent method, we look at the source of this method:

/** 
 * Implement this method to intercept all touch screen motion events.  This 
 * allows you to watch events as they are dispatched to your children, and 
 * take ownership of the current gesture at any point. 
 * 
 * <p>Using this function takes some care, as it has a fairly complicated 
 * interaction with {@link View#onTouchEvent(MotionEvent) 
 * View.onTouchEvent(MotionEvent)}, and using it requires implementing 
 * that method as well as this one in the correct way.  Events will be 
 * received in the following order: 
 * 
 * <ol> 
 * <li> You will receive the down event here. 
 * <li> The down event will be handled either by a child of this view 
 * group, or given to your own onTouchEvent() method to handle; this means 
 * you should implement onTouchEvent() to return true, so you will 
 * continue to see the rest of the gesture (instead of looking for 
 * a parent view to handle it).  Also, by returning true from 
 * onTouchEvent(), you will not receive any following 
 * events in onInterceptTouchEvent() and all touch processing must 
 * happen in onTouchEvent() like normal. 
 * <li> For as long as you return false from this function, each following 
 * event (up to and including the final up) will be delivered first here 
 * and then to the target's onTouchEvent(). 
 * <li> If you return true from here, you will not receive any 
 * following events: the target view will receive the same event but 
 * with the action {@link MotionEvent#ACTION_CANCEL}, and all further 
 * events will be delivered to your onTouchEvent() method and no longer 
 * appear here. 
 * </ol> 
 * 
 * @param ev The motion event being dispatched down the hierarchy. 
 * @return Return true to steal motion events from the children and have 
 * them dispatched to this ViewGroup through onTouchEvent(). 
 * The current target will receive an ACTION_CANCEL event, and no further 
 * messages will be delivered here. 
 */  
public boolean onInterceptTouchEvent(MotionEvent ev) {  
    return false;  
}  

If you do not see the source you really may be scared of this note, so long English comments see the head are big. But the source is so simple! Only one line of code, returned a false!

Well, since it is a boolean return, then there are only two possibilities, we rewrite this method in MyLayout, and then return a true try, the code is as follows:

public class MyLayout extends LinearLayout {  
  
    public MyLayout(Context context, AttributeSet attrs) {  
        super(context, attrs);  
    }  
      
    @Override  
    public boolean onInterceptTouchEvent(MotionEvent ev) {  
        return true;  
    }  
      
}  

Now run the project again, then Button1, Button2 and blank area, the print results are as follows:

4

You will find that no matter where you click, will only trigger the MyLayout touch event, the button click event completely blocked! Why is this? If the touch event in Android is passed to View and passed to ViewGroup, how can MyLayout block the Button’s click event?

It seems that only through reading the source code, find out the Android Event distribution(一) in order to solve our hearts doubts, but here I would like to tell you first, Android touch event delivery, is definitely passed to ViewGroup, and then Passed to View.

I remember in the Android Event distribution(一) I have explained that as long as you touch any control, it will call the control of the dispatchTouchEvent metho.。This is true, but not yet complete. The actual situation is that when you click on a control, you will first call the deployment of the control dispatchTouchEvent method, and then in the layout of the dispatchTouchEvent method to find the corresponding control click, and then call the control of the dispatchTouchEvent method. If we click on the button in MyLayout, we will call MyLayout’s dispatchTouchEvent method, but you will find that MyLayout does not have this method. Then it is to find it in the parent class LinearLayout find that there is no such method. It would have to continue to find LinearLayout the parent class ViewGroup, you finally see in the ViewGroup this method, the button dispatchTouchEvent method is called here.

What are you waiting for? Let’s take a look at the source of the dispatchTouchEvent method in ViewGroup! The code looks like this:

public boolean dispatchTouchEvent(MotionEvent ev) {  
    final int action = ev.getAction();  
    final float xf = ev.getX();  
    final float yf = ev.getY();  
    final float scrolledXFloat = xf + mScrollX;  
    final float scrolledYFloat = yf + mScrollY;  
    final Rect frame = mTempRect;  
    boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;  
    if (action == MotionEvent.ACTION_DOWN) {  
        if (mMotionTarget != null) {  
            mMotionTarget = null;  
        }  
        if (disallowIntercept || !onInterceptTouchEvent(ev)) {  
            ev.setAction(MotionEvent.ACTION_DOWN);  
            final int scrolledXInt = (int) scrolledXFloat;  
            final int scrolledYInt = (int) scrolledYFloat;  
            final View[] children = mChildren;  
            final int count = mChildrenCount;  
            for (int i = count - 1; i >= 0; i--) {  
                final View child = children[i];  
                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE  
                        || child.getAnimation() != null) {  
                    child.getHitRect(frame);  
                    if (frame.contains(scrolledXInt, scrolledYInt)) {  
                        final float xc = scrolledXFloat - child.mLeft;  
                        final float yc = scrolledYFloat - child.mTop;  
                        ev.setLocation(xc, yc);  
                        child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;  
                        if (child.dispatchTouchEvent(ev))  {  
                            mMotionTarget = child;  
                            return true;  
                        }  
                    }  
                }  
            }  
        }  
    }  
    boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||  
            (action == MotionEvent.ACTION_CANCEL);  
    if (isUpOrCancel) {  
        mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;  
    }  
    final View target = mMotionTarget;  
    if (target == null) {  
        ev.setLocation(xf, yf);  
        if ((mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {  
            ev.setAction(MotionEvent.ACTION_CANCEL);  
            mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;  
        }  
        return super.dispatchTouchEvent(ev);  
    }  
    if (!disallowIntercept && onInterceptTouchEvent(ev)) {  
        final float xc = scrolledXFloat - (float) target.mLeft;  
        final float yc = scrolledYFloat - (float) target.mTop;  
        mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;  
        ev.setAction(MotionEvent.ACTION_CANCEL);  
        ev.setLocation(xc, yc);  
        if (!target.dispatchTouchEvent(ev)) {  
        }  
        mMotionTarget = null;  
        return true;  
    }  
    if (isUpOrCancel) {  
        mMotionTarget = null;  
    }  
    final float xc = scrolledXFloat - (float) target.mLeft;  
    final float yc = scrolledYFloat - (float) target.mTop;  
    ev.setLocation(xc, yc);  
    if ((target.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {  
        ev.setAction(MotionEvent.ACTION_CANCEL);  
        target.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;  
        mMotionTarget = null;  
    }  
    return target.dispatchTouchEvent(ev);  
}  

This method code is relatively long, we only pick the point of view. First in the line 13 can see a condition to judge, if disallowIntercept and! OnInterceptTouchEvent (ev) both have a true, it will enter into the conditional judgment.DisallowIntercept is whether to disable the event blocking function, the default is false, you can also call the requestDisallowInterceptTouchEvent method to modify this value. Then when the first value is false, it will rely entirely on the second value to determine whether it can enter the condition to determine the internal, the second value is what? It is on the onInterceptTouchEvent method of the return value of the reverse! That is, if we return false in the onInterceptTouchEvent method, we will let the second value be true and enter the interior of the conditional judgment. If we return true in the onInterceptTouchEvent method, the second value will be false, so that Out of this condition to judge.

This time you can think about it, because we have just rewritten in MyLayout onInterceptTouchEvent method, so that this method returns true, resulting in all the button click events are blocked, then we have every reason to believe that the button click event Processing is in the 13th line of conditions to determine the internal!

Then we focus on the conditions to judge the internal is how to achieve. On the 19th line through a for loop, traverse the current ViewGroup under all the sub View, and then in the 24th line to determine the current traversal of the View is not click on the View, if it will enter the conditions to determine the internal, and then In the 29th line call the View dispatchTouchEvent, after the process and the Android event distribution mechanism completely resolved, take you from Android Event distribution(一) to explain the same. We also confirmed that the button click event processing is indeed carried out here.

And then need to pay attention to, call the Sub View dispatchTouchEvent after the return value. We already know that if a control is clickable, then click on the control, dispatchTouchEvent the return value must be true. So that the conditional judgment on line 29 is made, and true is returned directly to the dispatchTouchEvent method of ViewGroup on line 31. This will lead to the implementation of the code can not be followed, but also confirms the results of our previous Demo print, if the button click event is implemented, will be MyLayout touch events intercepted.

That if we click on the button, but the blank area? This situation will not return true on line 31, but will continue to implement the following code. Then we continue to look back, in line 44, if the target is equal to null, will enter the condition to determine the internal, where the target will be in general null, so in the first 50 lines call super.dispatchTouchEvent (ev). Where will this code call? Of course, View is the dispatchTouchEvent method, because ViewGroup’s parent class is View. After the processing logic and the above is the same, and therefore MyLayout registered onTouch method will be implemented. After the code in the general case is not accessible, and we will not continue to analyze down.

Now the entire ViewGroup event distribution process analysis is over, we finally come to a simple comb it now:

  1. Android event distribution is passed to ViewGroup, and then passed by ViewGroup to View.
  2. In the ViewGroup can be through the onInterceptTouchEvent method to intercept the event transfer, onInterceptTouchEvent method returns true that does not allow the event to continue to pass to the child View, return false on behalf of the event does not intercept, the default return false.
  3. If the event is consumed in the View, the ViewGroup will not be able to receive any events.

Android Event distribution(1)

Do you have such a question? What is the difference between onTouch and onTouchEvent and how should it be used? Why does the ListView introduce a sliding menu function, and the ListView can not scroll? Why is the picture in the picture carousel using the button instead of ImageView? And so on … for these questions. I did not give a very detailed answer. Because I know that if you want to completely understand these issues, master Android event distribution mechanism is essential, and Android event distribution mechanism is absolutely not a few words can be clear.

I am ready to take everyone from the source point of view of the analysis, I believe we can more profound understanding of the Android event distribution mechanism.

Read the source code from shallow to deep, step by step, so we also from the simple start, this first with everyone to explore the View event distribution, the next chapter to explore the more difficult ViewGroup event distribution.

Let’s start now! For example, you currently have a very simple project, only one Activity, and Activity only one button. You may already know that if you want to register a click event for this button, just call:

This is done in the onClick method, which can be executed when the button is clicked. You may already know that if you want to add a touch event to this button, just call:

button.setOnClickListener(new OnClickListener() {  
    @Override  
    public void onClick(View v) {  
        Log.d("TAG", "onClick execute");  
    }  
}); 

This is done in the onClick method, which can be executed when the button is clicked. You may already know that if you want to add a touch event to this button, just call:

button.setOnTouchListener(new OnTouchListener() {  
    @Override  
    public boolean onTouch(View v, MotionEvent event) {  
        Log.d("TAG", "onTouch execute, action " + event.getAction());  
        return false;  
    }  
});  

OnTouch method can do more things than onClick, such as judging finger press, lift, move and other events. So if both of my events are registered, which one will be executed first? We have to try to know, run the program click button, You can see the results.

You can see that onTouch takes precedence over onClick, and onTouch is executed twice, once is ACTION_DOWN, once ACTION_UP (you may have multiple ACTION_MOVE executions if you shake it). So the order of event delivery is first passed onTouch, and then passed to onClick

Careful friends should be able to note that the onTouch method has a return value, where we return is false, if we try to onTouch method in the return value into true, and then run once, the results are as follows:

2

We found that the onClick method is no longer executed! Why is this so? You can first understand that the onTouch method returns true to think that the event was consumed by the onTouch and that it will not continue to be passed down.

If so far, all the above knowledge points you are clear, then that your basic usage of the Android event should be mastered. But do not be satisfied with the status quo, let us from the source point of view, what is the principle of the above phenomenon.

First of all you need to know that, as long as you touch any of the controls, it will call the control of the dispatchTouchEvent method. That when we go to the button, it will call the Button class in the dispatchTouchEvent method, but you will find the Button class does not have this method, then go to its parent class TextView to find, you will find TextView There is no such method, it was no way, had no choice but to continue in the TextView Father search find, this time you finally found in the View this method.

Then let’s look at the source of the dispatchTouchEvent method in View:

public boolean dispatchTouchEvent(MotionEvent event) {  
    if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&  
            mOnTouchListener.onTouch(this, event)) {  
        return true;  
    }  
    return onTouchEvent(event);  
}  

This method is very simple, only a few lines of code! We can see that in this method, the first is to make a judgment, if mOnTouchListener! = Null, (mViewFlags & ENABLED_MASK) == ENABLED and mOnTouchListener.onTouch (this, event) these three conditions are true, return True, otherwise it will execute the onTouchEvent (event) method and return.

Look at the first condition, mOnTouchListener this variable is where the assignment? We found in the View after the discovery of the following methods:

public void setOnTouchListener(OnTouchListener l) {  
    mOnTouchListener = l;  
} 

Bingo! Found, mOnTouchListener is setOnTouchListener method in the assignment, that is, as long as we have registered to the control of the touch event, mOnTouchListener must be assigned.

The second condition (mViewFlags & ENABLED_MASK) == ENABLED is to determine whether the current click of the control is enabled, the button is enabled by default, so this condition is constant to true.

The third condition is more critical, mOnTouchListener.onTouch (this, event), in fact, is to callback control registration touch event onTouch method. That is, if we return true in the onTouch method, all three conditions are set, so that the entire method returns true directly. If we return false in the onTouch method, we will go to the onTouchEvent (event) method.

Now we can combine the previous examples to analyze, first of all in the dispatchTouchEvent is the first implementation of the onTouch method, so onTouch certainly have to take precedence over onClick implementation, but also confirms the just print results. And if it returns true in the onTouch method, the dispatchTouchEvent method returns true and does not continue. The print results also confirmed that if onTouch returns true, onClick will not be executed again.

According to the above analysis of the source code, the principle of our previous example to explain the results of the operation. The above analysis also revealed an important message, that is, onClick call is certainly in the onTouchEvent (event) method! Then we immediately look at the source code onTouchEvent, as follows:

public boolean onTouchEvent(MotionEvent event) {  
    final int viewFlags = mViewFlags;  
    if ((viewFlags & ENABLED_MASK) == DISABLED) {  
        // A disabled view that is clickable still consumes the touch  
        // events, it just doesn't respond to them.  
        return (((viewFlags & CLICKABLE) == CLICKABLE ||  
                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));  
    }  
    if (mTouchDelegate != null) {  
        if (mTouchDelegate.onTouchEvent(event)) {  
            return true;  
        }  
    }  
    if (((viewFlags & CLICKABLE) == CLICKABLE ||  
            (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {  
        switch (event.getAction()) {  
            case MotionEvent.ACTION_UP:  
                boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;  
                if ((mPrivateFlags & PRESSED) != 0 || prepressed) {  
                    // take focus if we don't have it already and we should in  
                    // touch mode.  
                    boolean focusTaken = false;  
                    if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {  
                        focusTaken = requestFocus();  
                    }  
                    if (!mHasPerformedLongPress) {  
                        // This is a tap, so remove the longpress check  
                        removeLongPressCallback();  
                        // Only perform take click actions if we were in the pressed state  
                        if (!focusTaken) {  
                            // Use a Runnable and post this rather than calling  
                            // performClick directly. This lets other visual state  
                            // of the view update before click actions start.  
                            if (mPerformClick == null) {  
                                mPerformClick = new PerformClick();  
                            }  
                            if (!post(mPerformClick)) {  
                                performClick();  
                            }  
                        }  
                    }  
                    if (mUnsetPressedState == null) {  
                        mUnsetPressedState = new UnsetPressedState();  
                    }  
                    if (prepressed) {  
                        mPrivateFlags |= PRESSED;  
                        refreshDrawableState();  
                        postDelayed(mUnsetPressedState,  
                                ViewConfiguration.getPressedStateDuration());  
                    } else if (!post(mUnsetPressedState)) {  
                        // If the post failed, unpress right now  
                        mUnsetPressedState.run();  
                    }  
                    removeTapCallback();  
                }  
                break;  
            case MotionEvent.ACTION_DOWN:  
                if (mPendingCheckForTap == null) {  
                    mPendingCheckForTap = new CheckForTap();  
                }  
                mPrivateFlags |= PREPRESSED;  
                mHasPerformedLongPress = false;  
                postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());  
                break;  
            case MotionEvent.ACTION_CANCEL:  
                mPrivateFlags &= ~PRESSED;  
                refreshDrawableState();  
                removeTapCallback();  
                break;  
            case MotionEvent.ACTION_MOVE:  
                final int x = (int) event.getX();  
                final int y = (int) event.getY();  
                // Be lenient about moving outside of buttons  
                int slop = mTouchSlop;  
                if ((x < 0 - slop) || (x >= getWidth() + slop) ||  
                        (y < 0 - slop) || (y >= getHeight() + slop)) {  
                    // Outside button  
                    removeTapCallback();  
                    if ((mPrivateFlags & PRESSED) != 0) {  
                        // Remove any future long press/tap checks  
                        removeLongPressCallback();  
                        // Need to switch from pressed to not pressed  
                        mPrivateFlags &= ~PRESSED;  
                        refreshDrawableState();  
                    }  
                }  
                break;  
        }  
        return true;  
    }  
    return false;  
}  

Compared to just the dispatchTouchEvent method, the onTouchEvent method is a lot more complicated, but it does not matter, we can only pick it.

First in the 14th line we can see that if the control is clickable will enter the 16th line of the switch to judge, and if the current event is raised fingers, will enter into the MotionEvent.ACTION_UP this case The After all the judgments, the implementation of the 38th of the performClick () method, then we enter into this method to see:

public boolean performClick() {  
    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);  
    if (mOnClickListener != null) {  
        playSoundEffect(SoundEffectConstants.CLICK);  
        mOnClickListener.onClick(this);  
        return true;  
    }  
    return false;  
}  

You can see, as long as mOnClickListener is not null, it will call it onClick method, that mOnClickListener is where the assignment? After finding the following method to find:

public void setOnClickListener(OnClickListener l) {  
    if (!isClickable()) {  
        setClickable(true);  
    }  
    mOnClickListener = l;  
}  

Everything is so clear! When we call the setOnClickListener method to register a click event to the control, it will assign a value to mOnClickListener. And then whenever the control is clicked, will be in the performClick () method callback control in the onClick method.

So that the whole process of distribution of View let us find out! But do not happy too early, now not the end, there is a very important point of knowledge need to explain, is the touch event level delivery. We all know that if a control to register a touch event, each time you click on it will trigger a series of ACTION_DOWN, ACTION_MOVE, ACTION_UP and other events. It is important to note that if you return false after executing ACTION_DOWN, the latter series of other actions will no longer be executed. Simply put, that is, when dispatchTouchEvent in the event distribution, only the previous action returns true, will trigger the next action.

Speaking of which, a lot of friends must have a huge question. Is this not contradictory? In the previous example, obviously in the onTouch event which returned false, ACTION_DOWN and ACTION_UP not have been implemented? In fact, you are only confused by the false impression, let us carefully analyze, in the previous example, we in the end what is the return.
Reference to the analysis of the source code in front of us, first in the onTouch event returns false, it will enter the onTouchEvent method, and then we look at the details of the onTouchEvent method. Because we click on the button, it will enter the 14th line of this if the judge inside, and then you will find that no matter what the current action, and ultimately will go to the first 89 lines, return a true.

Is there a feeling of being deceived? Obviously in the onTouch event returned to false, the system or in the onTouchEvent method to help you return true. For this reason, in the previous example, ACTION_UP can be executed.

Then we can change a control, replace the button with ImageView, and then register it with a touch event and return false. As follows:

imageView.setOnTouchListener(new OnTouchListener() {  
    @Override  
    public boolean onTouch(View v, MotionEvent event) {  
        Log.d("TAG", "onTouch execute, action " + event.getAction());  
        return false;  
    }  
}); 

Run the program, click on ImageView, you will find the results are as follows:

3

After ACTION_DOWN execution, the latter series of actions will not be implemented. This is why? Because the ImageView and the button is different, it is the default can not click, so in the onTouchEvent line 14 judgment can not enter into the inside. Directly jump to the first 91 to return to false. This will lead to the subsequent other actions can not be implemented.

Well, about the event distribution of View, all the things I want to say are here. Now let’s take a look at the three questions mentioned at the beginning of the day, believing that everyone will have a deeper understanding.

What is the difference between onTouch and onTouchEvent, and how to use it?

As you can see from the source, both methods are called in the View dispatchTouchEvent of the View, and onTouch takes precedence over onTouchEvent. If the event is consumed by returning true in the onTouch method, the onTouchEvent will no longer be executed.

Also note that onTouch is able to get implementation requires two prerequisites, the first mOnTouchListener value can not be empty, and the second current click control must be enabled. So if you have a control that is non-enabled, then registering it onTouch events will never be executed. For this type of control, if we want to listen to its touch event, it must be done by overriding the onTouchEvent method in the control.

Why does the ListView introduce a sliding menu function, and the ListView can not scroll?

The use of the Button in the picture carousel is mainly because the Button is clickable and the ImageView is not clickable. If you want to use ImageView, you can have two ways to change. First, in the ImageView onTouch method to return true, this can ensure that ACTION_DOWN after the other actions can be implemented in order to achieve the effect of picture scroll. Second, in the layout file inside to add an imageView android: clickable = “true” attribute, so that ImageView into a click, even in the onTouch returned false, ACTION_DOWN after the other action can also be implemented.

Today’s explanation to here, I believe we are now on the Android event distribution mechanism has a further understanding, in the back of the article I will take you to explore the Android ViewGroup event distribution mechanism

How to learn Android to earn 10 thousand salary monthly

My first job

Graduation through the school to find a traditional software company, is to do government software.I am a Java engineer, most of the time during the job is doing debug-style work, and occasionally do some small needs.Every day nine to five days really is leisurely.in school during the already know Android and always wanted to learn.Unfortunately, I did not stick to it in the school , only to learn a little bit of Android, and now regret the late carry on. My heart has been thinking about, this time I must stick to it, so began to learn the road of Android.

Began a three-month self-study road

Before the school self-taught some of the basic knowledge of java, but also through the back of some common interview questions to find a job, but also considered a certain self-learning ability, but the basis of java is not strong, basically from scratch began to learn Andrews, Look at the mars teacher recommended video, mars really talk about very detailed, but also easier to understand, I was from the first quarter to see the third quarter or so, I feel a general understanding of Android.

During the online query the problem when the search for some big cattle blog, I see more of Guo Lin’s blog that time he just wrote a book – “the first line of code”, I did not hesitate to buy Down, so I began to work during the day (and occasionally look at his blog), go home to read the code to write the day, that time my parents and friends to communicate that I want to change jobs, and now the job is not I want, I want not to learn, when parents and friends are also strongly discouraged me, because it is a big company, stable, not very tired, but I know clearly that I will not be too long, I do not want to make a screw in a big company, I want to go to a smaller company to expand my knowledge and technical skills, the first line of code in the comparison of the basis, and there are many solutions, but also taught me to use Git , Had to say great influence on me. I saw two books after the feeling and solid foundation, but I also know that this is far from enough, the company is hard to have a practical experience of the development of the programmer (fresh may be), SO I want to learn some slightly Advanced knowledge, occasionally in a foreign business trip in the process of browsing the forum when I found a certain impact on the programming thinking of cattle people, he summed up his years of experience and thinking mode through the video out, Most of his video is paid, and every one of his videos I want to see , but for the time I was also a small sum of money, I saw him talk about a few free chapters after I decided But I was very sure that I could learn a lot through these videos, he called Stay, taught me a lot of thinking and Thinking, so I am very useful, I still see his video. To the current position, I almost learned for three months, I can not wait to find a job.

Interview job

And finally to find a job time, and I thought first to vote a few look Well, first up some interview experience, remember to go to a lot of company interviews, large companies have cheetah mobile, 58 city, some fast-growing companies such as Move, music power, but also to the law firm interview I was drunk, there are a few I can not remember the name, summed up to see everything I asked my technology I think I answered the bad, not solid ah Not a solid, people asked the actual question when I do not know how to solve, can be described as running around, dejected ah, that time interview for nearly three or three weeks, and a reply are not, I also understand that they have a lot of deficiencies, the lack of reality Experience, to solve the problem of lack of ability, through the interview feedback I also continue to make up, and finally hard work, I found the ideal job, a start-up company, just started, but also the threshold of the interview, give me An effect, let us do two days, this effect:

1479839-40b6c30f36318624

I was a look at this is  Guo Lin speak of the property animation, well, he helped me, I learned a little bit of his blog with two days plus night more research will finally made a demo , To achieve the effect of the four buttons, my heart is very excited and excited, and then sent to the company to see, feedback is not bad, evaluation I have a certain self-learning ability, and then again the problem, that let the package look, you can set the number and radius of the button , Of course, I was very easy to complete him! My company’s products are Funny, is a very fun photo Editer tools, you can add very sticky stickers and do a lot of cool pictures of the camera, welcome to download! So I started my Android development road, but my heart also know that this is just the beginning!

Began to work overtime the development of the road

The company boss is doing iOS, So ios side of the product progress has been far more than Android side, to the company I am a person doing Android , and ios has Fast progress, I can imagine the progress and can not fall off the new features Of the progress, But I did not have practical experience, so that time I basically every day from 9 am to 10 pm rhythm, and sometimes the function did not finish home to continue, and even time to 5 am ,I kept telling myself, I can!  I met a question of a next, there is no chance of breathing, then I will one by one to solve it, here to thank my classmates, my good buddy, is  a Android engineer, but also I learn Android leader, the weekend when I took him in my house to help me look at the code, usually always ask him questions, and sometimes he did not go home (girlfriend is still home)! At that time the time has been very fast, but also to my skill level constantly improved, to enhance the fastest time is to force their own learning time, is the problem I must solve the mentality! When writing code is sometimes developed in order to complete the function, and my heart is really anxious, do not want to very slow to complete the task, but also because there are many hidden bugs generated so that each update version will have a bug, where I generous The boss is also hard and soft, and sometimes will ask me, but more is to encourage, which gave me a lot of confidence, every day or as much as possible to enhance the technology, constantly sum up, during this period I search the problem when many are Stackoverflow on the people to answer, and this also let the English is not very good I feel very difficult, but also bite the bullet and see, do not read on the investigation, I hope that beginners really do not be afraid of the problem, Slow look, look for a long time to understand, both to enhance the English ability and understand the knowledge, a lot of innovative things are really foreigners put forward! To enhance the ability to solve the problem is the most important, not afraid of difficulties and difficulties are essential for each engineer skills, during which I know github each engineer should have a github account, and write their own The code submitted to the above, I started every day with github above the shopping, a lot of good open source project , such as android-open-project, which a variety of controls inside the realization of various functions, really thank the author’s collection And finishing! , Of course, I also opened my own github account, I will learn these days to share the knowledge, summed up the knowledge I have, here is strongly recommended that beginners should learn their own Record, * write out the feeling is not the same *, this time because the performance of the company can also, up wages, rose to 10 thousand salary, the inner excitement is self-evident, like their own efforts have been affirmed, I really can!

Create the feeling of the code

From the beginning to enter the company has been doing ios already have the function, that white basically imitate, copy the function to the Android above, no packaging, the code is messy, it also let me now have time Refactoring the code before, but recently made a need for me to feel the feeling of creating a code to achieve a vertical and horizontal switchover of the Textview, the specific can see Android TextView horizontal and horizontal switch (word direction unchanged), I wrote this article , There are effects show, github above and other sites above the data are not a good solution and code.so I passed my own analysis to determine their own to write a heart as action, that night to get a little around to complete a Simple demo, the heart has long been surging, this is my own written custom View, before the download from github, this time with their own write! In general, although the custom view to write slowly, need to pay attention to the details of a lot, but after writing out of the feeling is self-evident, a strong package of their own products! Like climb the feeling of the top of the mountain do not have to mention the cool it, wrote here basically summed up a year I am a year of Android engineers mentality and experience, I am not smart, I can only in a period of time Focus on doing one thing, I believe that than I am smart you want to do one thing certainly more than I am easy! Do Android engineers to the present, although the time is not very long, but there are many words to tell you just getting started beginners.

Suggestions for beginners of Android developer

Here I combine my own experience to give you some suggestions, hoping to be inspired by you:

  1. Look at more powerful people’s blog, and must have your own blog, record the knowledge , write your own and let others understand, a lot of benefits, you write to know!
  2. to register a github account of your own, to submit your own code, the benefits are a lot, while looking for a job interview when your blog and github is also useful
  3. to write the code can think of the packaging and decoupling must be done, no matter how long you need, do not sacrifice their own off-day time to package, after the time you will know it’s convenient
  4. strongly recommended to use google search, search accuracy and problem positioning much stronger than the domestic, not on the Google search can not do excellent development, over the wall has become an essential skill! Strongly recommended to do application development friends every day to see google official documents, great benefit
  5. in the development process continue to refactor your own code, reconstruction as early as possible, bug ruins, each re-creation you can benefit from
  6. when you feel your lack of basic knowledge, such as watching others to write the code can not read, there are generic reflection, etc., at this time to return to the foundation, understand the technical principles, it is recommended to see java programming ideas, encapsulated integrated polymorphism And so on basic knowledge, only from the basic technical principles you have one day can write the ultimate scalability of the code
  7. What do you mean by Stay I mentioned here, What, How, Why, why do you want it to do whatever you want to do, how to do it,  why do you do it? With this idea to solve the problem

The above experiences and suggestions hope to inspire and help you!

Article on here, the above is my Android development experience, bit by bit, harvest a lot, I am also a primary Android development engineers, almost a year, after the road is still very long, we work together!