The Asyncqueryhandler class is used to provide asynchronous database operations (add-and-scan) functionality. This article view analyzes this class from a source perspective.
1.AsyncQueryHandler
How to use:
Asyncqueryhandler handler = new Asyncqueryhandler (This.getcontentresolver ()) {@Overrideprotected void Onquerycomplete (int token, Object cookie,cursor Cursor) {} @Overrideprotected void Onupdatecomplete (int token, Object cookie, int result) {} @Overrideprotected void Oninsertcomplete (int token, object cookie, Uri uri) {} @Overrideprotected void Ondeletecomplete (int token, object cookie, I NT result) {}};handler.startquery (token, cookie, URI, projection, selection, Selectionargs, as-is); Handler.startdelete (token, cookie, URI, selection, Selectionargs); Handler.startinsert (token, cookie, URI, initialvalues); Handler.startupdate (token, cookie, URI, values, selection, Selectionargs);
2. Source Code Analysis
Before analyzing the source code, grasp this class as a whole: Each Asyncqueryhandler object opens a background thread that interacts with the data from the ContentProvider component in the thread and performs an additional pruning check. When called, The request can be packaged to a background thread through the Asyncqueryhandler.startxxx series method, and when the related processing is complete, the result is asynchronously passed back to the main thread and the Asyncqueryhandler.onxxxcomplete method is called to notify the caller. Each time the caller requests, it is necessary to pass in an integer value token as the identity of the request, and when the request is completed, the token is returned to help the caller determine which request it is.
asyncqueryhandler is an abstract class that cannot be instantiated directly, this should be noted:
Public abstract class Asyncqueryhandler extends Handler
its internal encapsulation of looper and handler, this message loop works on child threads. An additional 4 constants are provided to identify the current operation type. Contentresolver is injected by the constructor.
private static final int event_arg_query = 1; private static final int event_arg_insert = 2; private static final int event_arg_update = 3; private static final int event_arg_delete = 4; /* Package */FINAL weakreference<contentresolver> mresolver; private static Looper slooper = null; Private Handler Mworkerthreadhandler;
the handler of the worker thread, i.e.Mworkthreadhandlerthe Handlemessage method is responsible for manipulating the database:
Protected class Workerhandler extends Handler {public Workerhandler (Looper Looper) {super (Looper); } @Override public void Handlemessage (Message msg) {final Contentresolver resolver = Mreso Lver.get (); if (resolver = = null) return; Workerargs args = (Workerargs) msg.obj; int token = Msg.what; int event = MSG.ARG1; Switch (event) {case Event_arg_query:cursor Cursor; try {cursor = Resolver.query (Args.uri, Args.projection, Args.select Ion, Args.selectionargs, Args.orderby); if (cursor! = NULL) {Cursor.getcount (); }} catch (Exception e) {LOG.W (TAG, "Exception thrown during handling Event_arg _query ", e); Cursor = null; } args.result = cursor; Break Case EVENT_ARG_INSERT:args.result = Resolver.insert (Args.uri, args.values); Break Case EVENT_ARG_UPDATE:args.result = resolver.update (Args.uri, Args.values, Args.selection, Args.selectionargs); Break Case EVENT_ARG_DELETE:args.result = Resolver.delete (Args.uri, args.selection, Args.selectionargs); Break }//Returns the result to Asyncqueryhandler handlemessage processing Message reply = Args.handler.obtainMessage (token); Reply.obj = args; REPLY.ARG1 = MSG.ARG1; if (LOCALLOGV) {log.d (TAG, "workerhandler.handlemsg:msg.arg1=" + Msg.arg1 + ", Rep ly.what= "+ reply.what); } reply.sendtotarget (); } }
Asyncqueryhandler Constructs a handlerthread,start, then acquires its looper and uses its looper to construct a child thread message loop and binds to Mworkthreadhandler:
Public Asyncqueryhandler (Contentresolver CR) { super (); Mresolver = new Weakreference<contentresolver> (CR); Synchronized (asyncqueryhandler.class) { if (Slooper = = null) { Handlerthread thread = new Handlerthread (" Asyncqueryworker "); Thread.Start ();//Start child thread, start child thread message loop Slooper = Thread.getlooper ();} } Mworkerthreadhandler = Createhandler (Slooper); } Protected Handler Createhandler (Looper Looper) { return new Workerhandler (Looper); }
This class provides the request parameters for the Workerargs encapsulated database operation:
Protected static Final class Workerargs {public URI Uri; Public Handler Handler; public string[] projection; public String selection; Public string[] Selectionargs; Public String by-clause; Public Object result; public Object Cookie; public contentvalues values; }
When the Startxxx method is called, the Workerargs object is constructed, and the object is sent as a message to theMworkthreadhandler, the result is sent to asyncqueryhandler itself after processing is complete: startxxx:
public void Startquery (int token, Object cookie, Uri Uri, string[] projection, String selection, string[] Selectionarg S, String by) {//Use the token as what, canceloperations works properly Message msg = Mworkerthreadha Ndler.obtainmessage (token); MSG.ARG1 = Event_arg_query; Workerargs args = new Workerargs (); Args.handler = this;//Note This line has developed handler for itself, i.e. Asyncqueryhandler Args.uri = URI; args.projection = projection; Args.selection = Selection; Args.selectionargs = Selectionargs; Args.orderby = by; Args.cookie = cookie; Msg.obj = args; Mworkerthreadhandler.sendmessage (msg);//Give child threading }
Workerhandler:
Message reply = args.handler.obtainMessage (token); Reply.obj = args; REPLY.ARG1 = MSG.ARG1; ... Reply.sendtotarget ()///In the Startxxx method has already developed the target for Asyncquerthandler itself
Finally, the results of the operation are referred to the Asyncqueryhandler class Handlemessage processing:
@Override public void Handlemessage (Message msg) { Workerargs args = (Workerargs) msg.obj; if (LOCALLOGV) { log.d (TAG, "asyncqueryhandler.handlemessage:msg.what=" + msg.what + ", msg.arg1=" + msg.arg1); } int token = Msg.what; int event = MSG.ARG1; Pass token back to caller on each callback. Switch (event) {case event_arg_query: onquerycomplete (token, Args.cookie, (Cursor) args.result); break; Case Event_arg_insert: oninsertcomplete (token, Args.cookie, (Uri) args.result); break; Case Event_arg_update: onupdatecomplete (token, Args.cookie, (Integer) args.result); break; Case Event_arg_delete: ondeletecomplete (token, Args.cookie, (Integer) args.result); break; } }
andThe Handlemessage method of the Asyncqueryhandler class callback the Onxxxcomplete series method. We rewrite the Onxxxcomplete method to get the results of the database operation.
This design is amazing!!!
"Android Notes" Asyncqueryhandler source analysis