[Android] solves the problem of updating the UI interface for out-of-thread UI control-upgraded version (sufaceview Control)

Source: Internet
Author: User

I. Problem Description

In general, when we play a video through a mobile player, the playback event is triggered through buttons on the UI. Surfaceview, the control for displaying video streams, refreshes the playback screen of each frame following the playback progress.

However, sometimes ...... We need to use the UI thread to replace the button event to control the video playback effect. What should we do? Sometimes there is a sound and no picture. Why?

Ii. Problem Solving

Previous[Android] controls the thread outside the UI interface to refresh the UIThe handler
The method handlemessage (Message MSG) is used to listen to messages sent by other threads and update the UI display. This is still effective for general space updates. However, surfaceview does not seem to work.

Cause:Surfaceview introduction (the following surfacview is from Baidu Library)

Surfaceview is an inherited class of view, which is embedded with a surface dedicated for painting. You can control the format and size of the surface. Surfaceview controls the position of this surface.
Surface is ordered in depth (Z-ordered), which indicates that it is always behind its own window. Surfaceview provides a visible area where only the surface content in the visible area is visible and the area outside the visible area is invisible. The layout display of the surface is affected by the hierarchical view relationship, and its sibling view node is displayed at the top. This means
The content of the surface is blocked by its sibling view, which can be used to place overlays (for example, controls such as text and buttons ). Note: If the surface has a transparent control, every change to it will cause the framework to recalculate its transparency with the top-level control, which will affect the performance.
You can access this surface through the surfaceholder interface. The getholder () method can obtain this interface.
When surfaceview becomes visible, the surface is created. Before surfaceview is hidden, the surface is destroyed. This saves resources. If you want to view
When the surface is created and destroyed, surfacecreated (surfaceholder) and surfacedestroyed (surfaceholder) can be reloaded ).
The core of surfaceview is to provide two threads: the UI thread and the rendering thread. Note:
1> All surfaceview and surfaceholder. Callback methods should be called in the UI thread, which is generally the main thread of the application. Various variables accessed by the rendering thread should be processed synchronously.
2> because the surface may be destroyed, it is only in surfaceholder. Callback. surfacecreated () and
Surfaceholder. Callback. surfacedestroyed () is valid, so make sure that the rendering thread accesses the valid surface.

 

Next, let's talk about our understanding of it.
1. Definition

Image data can be obtained directly from hardware interfaces such as memory or DMA, which is a very important drawing container.

Its feature is that it can be drawn to the screen outside the main thread. In this way, the main thread blocking can be avoided when the drawing task is heavy, thus improving the response speed of the program. Surfaceview is often used in game development. The background, characters, and animations in the game should be drawn in the canvas whenever possible.

2. Implementation

First, we inherit surfaceview and implement the surfaceholder. Callback interface.
The reason for using the interface: Because surfaceview has a principle, all the drawing work must be created after the surface (surface-surface, this concept is often mentioned in graphic programming. Basically, we can use it as a ing of the display to write the content to the surface.
Can be directly copied to the video memory for display, which makes the display speed very fast), and must end before the surface is destroyed. Therefore, surfacecreated and surfacedestroyed in callback form the boundary of the drawing processing code.

Method to be rewritten
Implements surfaceholder. Callback

(1) Public void surfacechanged (surfaceholder holder, int format, int width, int height ){}


// Triggered when the surface size changes

(2) Public void surfacecreated (surfaceholder holder ){}


// Triggered during creation. Generally, the drawing thread is called here.

(3) Public void surfacedestroyed (surfaceholder holder ){}


// Triggered when the image is destroyed. Generally, the painting thread is stopped and released here.

The whole process: inherits surfaceview and implements surfaceholder. callback interface ----> surfaceview. getholder () obtains the surfaceholder object ----> surfaceholder. addcallback (callback) adds the callback function ----> surfaceholder. lockcanvas () Get the canvas object and lock the canvas ---->
Canvas painting ----> surfaceholder. unlockcanvasandpost (canvas) stops locking the drawing, and submits the changes to display the drawing.

3. surfaceholder
Surfaceholder is used as a surface controller to manipulate the surface. It processes effects and animations drawn on its canvas, controls the surface, size, pixels, and so on.
Several Methods to note:
(1) Abstract void addcallback (surfaceholder. Callback callback );
// Send a callback object to the current owner of surfaceview.
(2) Abstract canvas lockcanvas ();
// Lock the canvas. After locking the canvas, you can use its returned canvas object to draw a picture on it.
(3) Abstract canvas lockcanvas (rect dirty );
// Draw a picture in a certain area of the canvas. After the painting, the unlockcanvasandpost file is called to change the display content.
// For games with relatively high memory requirements, you do not need to redraw pixels in other regions outside dirty to increase the speed.
(4) Abstract void unlockcanvasandpost (canvas );
// Stop the locked drawing and submit the changes.

3. Have you been impatient with such nonsense? I can't help solving this problem. This is because it is difficult to find information on the Internet.

To achieve audio and video synchronization, you must create a surfaceview to play the audio and video files normally. So you need to start the thread that controls the video playback and stop signal in the method: Public void surfacecreated (surfaceholder holder ){}

IV,

 

5. Sample Code

Import Java. util. timer; import Java. util. timertask; import android. app. activity; import android. graphics. pixelformat; import android. OS. bundle; import android. util. *; import android. view. surfaceholder; import android. view. surfaceview; import android. view. view; import android. widget. imagebutton; import android. widget. seekbar; import android. widget. textview; import android. widget. toast; import android. media. audio Manager; import android. media. mediaplayer; import android. OS. handler; import android. OS. message; import android. widget. button; public class Hello extends activity implements surfaceholder. callback {private textview mtextview; private mediaplayer mmediaplayer; private surfaceview msurfaceview; private surfaceholder msurfaceholder01; private imagebutton mplay; private imagebutton mpause; private imagebu Tton mreset; private imagebutton mstop; private button all_release; private Boolean bisplay = false; private Boolean bispaused = false; private Boolean bisreleased = false; private string strvideopath = ""; public seekbar = NULL; private timer mtimer; private timertask mtimertask; private Boolean ischanging = false; string java_string = "/sdcard/a.3gp? Formatid = 784444 "; int alltime, currenttime; public static int action = 1; // 1: Play, 2: Stop, 3: pause, 4: resume, 5: seek, handler handler; void addtime () {mtimer = new timer (); mtimertask = new timertask () {public void run () {If (ischanging = true) // return; else seekbar when dragging the button. setprogress (mmediaplayer. getcurrentposition () ;}};}@ override public void oncreate (bundle savedinstancestate) {super. oncreate (SA Vedinstancestate); setcontentview (R. layout. main); mtextview = (textview) findviewbyid (R. id. mytextview1); getwindow (). setformat (pixelformat. unknown); msurfaceview = (surfaceview) findviewbyid (R. id. msurfaceview1); msurfaceholder01 = msurfaceview. getholder (); msurfaceholder01.addcallback (this); msurfaceholder01.setfixedsize (176,144); msurfaceholder01.settype (surfaceholder. surface_type_push_buffers); s Eekbar = (seekbar) findviewbyid (R. id. seekbar); seekbar. setonseekbarchangelistener (New seekbarchangeevent (); mplay = (imagebutton) findviewbyid (R. id. play); mpause = (imagebutton) findviewbyid (R. id. pause); mreset = (imagebutton) findviewbyid (R. id. reset); mstop = (imagebutton) findviewbyid (R. id. stop); all_release = (button) findviewbyid (R. id. all_release); strvideopath = java_string.substring (0, java_strin G. lastindexof ('? ')); /********************************/Handler = new handler () {@ override public void handlemessage (Message MSG) {Switch (MSG. what) {Case 1: mplay. optional mclick (); break; Case 2: mstop. optional mclick (); break; Case 3: mpause. optional mclick (); break; Case 4: mreset. optional mclick (); break; Case 5: break; default: Break ;}}}; /*********************************/mplay. setonclicklistener (New imagebutton. onclickl Istener () {public void onclick (view) {If (! Bisplay) // returns the value of {bisplay = true; mplay. setenabled (false); // #####playvideo (strvideopath); seekbar. setmax (mmediaplayer. getduration (); toast. maketext (hello. this, "Total time:" + mmediaplayer. get duration (), 5000 ). show (); addtime (); mtimer. schedule (mtimertask, 0,500); // dmr_update_message ("play", 0); // fig); mpause. setonclicklistener (New imagebutton. onclicklistener () {public void onclick (View view) {// bisplay =! Bisplay; If (mmediaplayer! = NULL) {If (bisreleased = false) {If (bispaused = false) {mmediaplayer. pause (); bispaused = true; mtextview. settext (R. string. str_pause);} else if (bispaused = true) {mmediaplayer. start (); bispaused = false; mtextview. settext (R. string. str_play) ;}}}}); mreset. setonclicklistener (New imagebutton. onclicklistener () {public void onclick (view) {If (bisreleased = false) {If (mmediaplayer! = NULL) {mmediaplayer. seekto (0) ;}}}); mstop. setonclicklistener (New imagebutton. onclicklistener () {public void onclick (view) {If (mmediaplayer! = NULL) {If (bisreleased = false) {mtimer. cancel (); // specifies the seekbar. setprogress (0); mmediaplayer. stop (); mmediaplayer. release (); bisreleased = true; mplay. setenabled (true); bisplay = false; mtextview. settext (R. string. str_stop) ;}}}); all_release.setonclicklistener (New button. onclicklistener () {public void onclick (view arg0) {}});} public void playvideo (string strpath) {mmediaplayer = new mediaplayer (); mmediaplayer. setaudiostreamtype (audiomanager. stream_music); mmediaplayer. setdisplay (msurfaceholder01); try {mmediaplayer. setdatasource (strpath);} catch (exception e) {mtextview. settext ("setdatasource exceeption:" + E. tostring ();} Try {mmediaplayer. prepare ();} catch (exception e) {mtextview. settext ("Prepare exceeption:" + E. tostring ();} mmediaplayer. start (); bisreleased = false; mtextview. settext (R. string. str_play); mmediaplayer. setoncompletionlistener (New mediaplayer. oncompletionlistener () {@ override public void oncompletion (mediaplayer arg0) {mtextview. settext (R. string. str_stop) ;}}) ;}@ overridepublic void surfacechanged (surfaceholder, int format, int W, int h) {log. I (TAG, "Surface Changed") ;}@ overridepublic void surfacecreated (surfaceholder) {/*********************************/New thread () {@ overridepublic void run () {Switch (Action) {Case 1: Handler. sendemptymessage (1); break; Case 2: Handler. sendemptymessage (2); break; Case 3: Handler. sendemptymessage (3); break; Case 4: Handler. sendemptymessage (4); break; Case 5: Handler. sendemptymessage (5); break; default: Break ;}}}. start (); /********************************/} @ overridepublic void surfacedestroyed (surfaceholder) {log. I (TAG, "surface destroyed");} class seekbarchangeevent implements seekbar. onseekbarchangelistener {@ override public void onprogresschanged (seekbar, int progress, Boolean fromuser) {}@ override public void onstarttrackingtouch (seekbar) {ischanging = true ;} @ override public void onstoptrackingtouch (seekbar) {mmediaplayer. seekto (seekbar. getprogress (); ischanging = false ;}}}

6. Explanation: some useful parts in this example are marked in red. The function is to control video playback by changing the value of the global signal action. Here there is no improvement on how the action changes, some code of the action that has been listened to cyclically. I just hope you can understand how to solve the problem of audio and video synchronization.

 

 

Limited by the level of the author, please point out any improper points.

 

 

 

 

 

 

 

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.