/*
3月26日
Android异步消息机制
Handler的常规使用方式
*/
/**
* 测试Activity,主要用于测试异步消息(Handler)的使用方式
*/
public class MainActivity extends AppCompatActivity {
public static final String TAG = MainActivity.class.getSimpleName();
private TextView texttitle = null;
/**
* 在主线程中定义Handler,并实现对应的handleMessage方法
* 一般handler的使用方式都是在主线程中定义Handler,然后在子线程中调用mHandler.sendEmptyMessage();方法
*/
public static Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 101) {
Log.i(TAG, "接收到handler消息...");
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
texttitle = (TextView) findViewById(R.id.texttitle);
texttitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
// 在子线程中发送异步消息
mHandler.sendEmptyMessage(101);
}
}.start();
}
});
}
}
/*
3月27日
Android异步消息机制
在子线程中定义Handler
*/
/**
* 定义texttitle的点击事件处理
* 在初始化Handler对象之前需要调用Looper.prepare()方法
*/
texttitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
Looper.prepare();
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 101) {
Log.i(TAG, "在子线程中定义Handler,并接收到消息。。。");
}
}
};
}
}.start();
}
});
/*
3月28日
Android异步消息机制
App初始化的时候执行ActivityThread的main方法
*/
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
CloseGuard defaults to true and can be quite spammy. We
disable it here, but selectively enable it later (via
StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
AndroidKeyStoreProvider.install();
//Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
/*
3月29日
Android异步消息机制
Handler的标准写法
*/
Looper.prepare();
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 101) {
Log.i(TAG, "在子线程中定义Handler,并接收到消息。。。");
}
}
};
Looper.loop();
/*
3月30日
Android异步消息机制
查看Looper.prepare()方法
*/
sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
//Looper对象的构造方法,可以看到在其构造方法中初始化了一个MessageQueue对象
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
/*
3月31日
Android异步消息机制
查看Handler对象的构造方法
*/
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
//查看handler.sendMessage(msg)方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
/*
4月1日
Android异步消息机制
查看messagequeue对象的enqueueMessage方法
*/
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
/*
4月2日
Android异步消息机制
查看Looper.Loop()方法
*/
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
/Make sure the identity of this thread is that of the local process,
and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
Make sure that during the course of dispatching the
identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
/*
4月3日
Android异步消息机制
Looper.loop()方法里起了一个死循环,不断的判断MessageQueue中的消息是否为空,如果为空则直接return掉,然后执行queue.next()方法:
*/
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
/*
4月4日
Android异步消息机制
Looper.loop()方法里起了一个死循环,不断的判断MessageQueue中的消息是否为空,如果为空则直接return掉,然后执行queue.next()方法:
*/
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
/*
4月5日
Android异步消息机制
Looper.loop()方法里起了一个死循环,不断的判断MessageQueue中的消息是否为空,如果为空则直接return掉,然后执行queue.next()方法:
*/
Run the idle handlers.
We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
/*
4月6日
Android异步消息机制
查看Handler类的dispatchMessage方法
*/
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
/*
4月7日
Android异步消息机制
总结
*/
主线程中定义Handler,直接执行:
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
在子线程中定义Handler,则标准的写法为:
// 初始化该线程Looper,MessageQueue,执行且只能执行一次
Looper.prepare();
// 初始化Handler对象,内部关联Looper对象
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
// 启动消息队列出栈死循环
Looper.loop();
Handler的post方法:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
view的post方法:
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().post(action);
return true;
activity的runOnUiThread方法:
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
/*
4月10日
异步任务AsyncTask
AsyncTask的基本使用
*/
/**
* 自定义AsyncTask对象
*/
class MAsyncTask extends AsyncTask<Integer, Integer, Integer> {
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.i(TAG, "onPreExecute...(开始执行后台任务之前)");
}
@Override
protected void onPostExecute(Integer i) {
super.onPostExecute(i);
Log.i("TAG", "onPostExecute...(开始执行后台任务之后)");
}
@Override
protected Integer doInBackground(Integer... params) {
Log.i(TAG, "doInBackground...(开始执行后台任务)");
return 0;
}
}
/*
4月11日
异步任务AsyncTask
查看异步任务的构造方法
*/
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
/*
4月13日
异步任务AsyncTask
测试在子线程中通过MAsyncTask执行异步操作
*/
/**
* 测试代码,测试在子线程中通过MAsyncTask执行异步操作
*/
new Thread(new Runnable() {
@Override
public void run() {
Log.i("tag", Thread.currentThread().getId() + "");
new MAsyncTask().execute();
}
}).start();
Log.i("tag", "mainThread:" + Thread.currentThread().getId() + "");
/*
4月14日
异步任务AsyncTask
execute方法内部调用了executeOnExecutor方法
*/
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
/*
4月14日
异步任务AsyncTask
执行了execute方法之后,如果再次执行就会进入这里的if条件判断并抛出异常
*/
final MAsyncTask mAsyncTask = new MAsyncTask();
title.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/*MLog.e("you have clicked the title textview!!!");
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivityForResult(intent, 101);*/
new Thread(new Runnable() {
@Override
public void run() {
Log.i("tag", Thread.currentThread().getId() + "");
mAsyncTask
.execute();
}
}).start();
Log.i("tag", "mainThread:" + Thread.currentThread().getId() + "");
}
});
/*
4月15日
异步任务AsyncTask
查看SerialExecutor的具体实现
*/
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
/*
4月16日
异步任务AsyncTask
AsyncTask内部定义了一个Handler对象
*/
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
/*
4月17日
异步任务AsyncTask
异步任务完成的消息会调用finish方法
*/
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
/*
4月18日
HandlerThread
HandlerThread的基本用法
*/
/**
* 测试HandlerThread的基本使用
*/
HandlerThread mHandlerThread = new HandlerThread("myHandlerThreand");
mHandlerThread.start();
// 创建的Handler将会在mHandlerThread线程中执行
final Handler mHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
Log.i("tag", "接收到消息:" + msg.obj.toString());
}
};
title = (TextView) findViewById(R.id.title);
title.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message msg = new Message();
msg.obj = "11111";
mHandler.sendMessage(msg);
msg = new Message();
msg.obj = "2222";
mHandler.sendMessage(msg);
}
});
/*
4月19日
HandlerThread
Thread的run方法
*/
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/*
4月20日
IntentService
自身含有消息循环的Service
定义一个IntentService
*/
/**
* 自定义IntentService
*/
public class MIntentService extends IntentService{
public MIntentService() {
super("");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.i("tag", intent.getStringExtra("params") + " " + Thread.currentThread().getId());
}
}
/*
4月21日
IntentService
自身含有消息循环的Service
启动service
*/
/**
* 定义TextView点击事件,启动IntentService服务
*/
title.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MIntentService.class);
intent.putExtra("params", "ceshi");
startService(intent);
}
});
点击title组件的时候,service接收到了消息并打印出了传递过去的intent参数,同时显示onHandlerIntent方法执行的线程ID并非主线程
/*
4月22日
IntentService
自身含有消息循环的Service
service源码
*/
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(Intent intent);
}
/*
4月23日
IntentService
自身含有消息循环的Service
消息队列的处理逻辑
*/
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
/*
4月24日
SystemServer进程启动流程
SystemServer.run方法的实现
*/
private void run() {
...
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
Slog.w(TAG, "System clock is before 1970; setting to 1970.");
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}
...
if (!SystemProperties.get("persist.sys.language").isEmpty()) {
final String languageTag = Locale.getDefault().toLanguageTag();
SystemProperties.set("persist.sys.locale", languageTag);
SystemProperties.set("persist.sys.language", "");
SystemProperties.set("persist.sys.country", "");
SystemProperties.set("persist.sys.localevar", "");
}
// Here we go!
Slog.i(TAG, "Entered the Android system server!");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis())
...
SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
// Enable the sampling profiler.
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
mProfilerSnapshotTimer = new Timer();
mProfilerSnapshotTimer.schedule(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegration.writeSnapshot("system_server", null);
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}
/*
4月25日
SystemServer进程启动流程
SystemServer.run方法的实现
*/
VMRuntime.getRuntime().clearGrowthLimit();
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
// Some devices rely on runtime fingerprint generation, so make sure
// we've defined it before booting further.
Build.ensureFingerprintProperty();
// Within the system server, it is an error to access Environment paths without
// explicitly specifying a user.
Environment.setUserRequired(true);
// Ensure binder calls into the system always run at foreground priority.
BinderInternal.disableBackgroundScheduling(true);
// Prepare the main looper thread (this thread).
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
Looper.prepareMainLooper();
// Initialize native services.
System.loadLibrary("android_servers");
// Check whether we failed to shut down last time we tried.
// This call may not return.
performPendingShutdown();
// Initialize the system context.
createSystemContext();
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Start services.
try {
startBootstrapServices();
startCoreServices();
startOtherServices();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
}
// For debug builds, log event loop stalls to dropbox for analysis.
if (StrictMode.conditionallyEnableDebugLogging()) {
Slog.i(TAG, "Enabled StrictMode for system server main thread.");
}
// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
/*
4月26日
SystemServer进程启动流程
startBootstrapServices() 主要用于启动系统Boot级服务
startBootstrapServices方法
*/
private void startBootstrapServices() {
Installer installer = mSystemServiceManager.startService(Installer.class);
// Activity manager runs the show.
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
// Now that the power manager has been started, let the activity manager
// initialize power management features.
mActivityManagerService.initPowerManagement();
// Manages LEDs and display backlight so we need it to bring up the display.
mSystemServiceManager.startService(LightsService.class);
// Display manager is needed to provide display metrics before package manager
// starts up.
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
// We need the default display before we can initialize the package manager.
mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
// Only run "core" apps if we're encrypting the device.
String cryptState = SystemProperties.get("vold.decrypt");
if (ENCRYPTING_STATE.equals(cryptState)) {
Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
mOnlyCore = true;
} else if (ENCRYPTED_STATE.equals(cryptState)) {
Slog.w(TAG, "Device encrypted - only parsing core apps");
mOnlyCore = true;
Slog.i(TAG, "Package Manager");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
Slog.i(TAG, "User Service");
ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());
// Initialize attribute cache used to cache resources from packages.
AttributeCache.init(mSystemContext);
// Set up the Application instance for the system process and get started.
mActivityManagerService.setSystemProcess();
// The sensor service needs access to package manager service, app ops
// service, and permissions service, therefore we start it after them.
startSensorService();
}
/*
4月28日
SystemServer进程启动流程
startCoreServices() 主要用于启动系统核心的服务
startService方法的具体实现
*/
public <T extends SystemService> T startService(Class<T> serviceClass) {
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);
// Create the service.
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service could not be instantiated", ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (NoSuchMethodException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service constructor threw an exception", ex);
}
// Register it.
mServices.add(service);
// Start it.
try {
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + name
+ ": onStart threw an exception", ex);
}
return service;
}
//通过反射器构造方法创建出服务类,然后添加到SystemServiceManager的服务列表数据中,最后调用了service.onStart()方法
/*
4月29日
SystemServer进程启动流程
Lifecycle类的定义
*/
public static final class Lifecycle extends SystemService {
private final ActivityManagerService mService;
public Lifecycle(Context context) {
super(context);
mService = new ActivityManagerService(context);
}
@Override
public void onStart() {
mService.start();
}
public ActivityManagerService getService() {
return mService;
}
}
/*
4月30日
SystemServer进程启动流程
ActivityManagerService的start方法的实现
*/
private void start() {
Process.removeAllProcessGroups();
mProcessCpuThread.start()
mBatteryStatsService.publish(mContext);
mAppOpsService.publish(mContext);
Slog.d("AppOps", "AppOpsService published");
LocalServices.addService(ActivityManagerInternal.class, new LocalService());
}
/*
5月1日
SystemServer进程启动流程
startCoreServices方法
*/
private void startCoreServices() {
// Tracks the battery level. Requires LightService.
mSystemServiceManager.startService(BatteryService.class);
// Tracks application usage stats.
mSystemServiceManager.startService(UsageStatsService.class);
mActivityManagerService.setUsageStatsManager(
LocalServices.getService(UsageStatsManagerInternal.class));
// Update after UsageStatsService is available, needed before performBootDexOpt.
mPackageManagerService.getUsageStatsIfNoPackageUsageInfo()
// Tracks whether the updatable WebView is in a ready state and watches for update installs.
mSystemServiceManager.startService(WebViewUpdateService.class);
}
/*
5月3日
断点续传-音乐播放器
主框架
private static final String URL = "http://10.81.36.193:8080/";
// 固定存放下载的音乐的路径:SD卡目录下
private static final String SD_PATH = "/mnt/sdcard/";
// 存放各个下载器
private Map<String, Downloader> downloaders = new HashMap<String, Downloader>();
// 存放与下载器对应的进度条
private Map<String, ProgressBar> ProgressBars = new HashMap<String, ProgressBar>();
/**
* 利用消息处理机制适时更新进度条
*/
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 1) {
String url = (String) msg.obj;
int length = msg.arg1;
ProgressBar bar = ProgressBars.get(url);
if (bar != null) {
// 设置进度条按读取的length长度更新
bar.incrementProgressBy(length);
if (bar.getProgress() == bar.getMax()) {
Toast.makeText(MainActivity.this, "下载完成!", 0).show();
// 下载完成后清除进度条并将map中的数据清空
/*
5月4日
断点续传-音乐播放器
主框架
*/
LinearLayout layout = (LinearLayout) bar.getParent();
layout.removeView(bar);
ProgressBars.remove(url);
downloaders.get(url).delete(url);
downloaders.get(url).reset();
downloaders.remove(url);
}
}
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showListView();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());
}
/*
5月5日
断点续传-音乐播放器
主框架
*/
// 显示listView,这里可以随便添加音乐
private void showListView() {
List<Map<String, String>> data = new ArrayList<Map<String, String>>();
Map<String, String> map = new HashMap<String, String>();
map.put("name", "mm.mp3");
data.add(map);
map = new HashMap<String, String>();
map.put("name", "pp.mp3");
data.add(map);
map = new HashMap<String, String>();
map.put("name", "tt.mp3");
data.add(map);
map = new HashMap<String, String>();
map.put("name", "ou.mp3");
data.add(map);
SimpleAdapter adapter = new SimpleAdapter(this, data, R.layout.list_item, new String[] { "name" },
new int[] { R.id.tv_resouce_name });
setListAdapter(adapter);
}
/**
* 响应开始下载按钮的点击事件
*/
public void startDownload(View v) {
// 得到textView的内容
LinearLayout layout = (LinearLayout) v.getParent();
String musicName = ((TextView) layout.findViewById(R.id.tv_resouce_name)).getText().toString();
String urlstr = URL + musicName;
String localfile = SD_PATH + musicName;
/*
5月6日
断点续传-音乐播放器
主框架
*/
public void startDownload(View v) {
// 得到textView的内容
LinearLayout layout = (LinearLayout) v.getParent();
String musicName = ((TextView) layout.findViewById(R.id.tv_resouce_name)).getText().toString();
String urlstr = URL + musicName;
String localfile = SD_PATH + musicName;
//设置下载线程数为4,这里是我为了方便随便固定的
int threadcount = 4;
// 初始化一个downloader下载器
Downloader downloader = downloaders.get(urlstr);
if (downloader == null) {
downloader = new Downloader(urlstr, localfile, threadcount, this, mHandler);
downloaders.put(urlstr, downloader);
}
if (downloader.isdownloading())
return;
// 得到下载信息类的个数组成集合
LoadInfo loadInfo = downloader.getDownloaderInfors();
// 显示进度条
showProgress(loadInfo, urlstr, v);
// 调用方法开始下载
downloader.download();
}
/*
5月7日
断点续传-音乐播放器
主框架
*/
/**
* 显示进度条
*/
private void showProgress(LoadInfo loadInfo, String url, View v) {
ProgressBar bar = ProgressBars.get(url);
if (bar == null) {
bar = new ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal);
bar.setMax(loadInfo.getFileSize());
bar.setProgress(loadInfo.getComplete());
ProgressBars.put(url, bar);
LinearLayout.LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, 5);
((LinearLayout) ((LinearLayout) v.getParent()).getParent()).addView(bar, params);
}
}
/**
* 响应暂停下载按钮的点击事件
*/
public void pauseDownload(View v) {
LinearLayout layout = (LinearLayout) v.getParent();
String musicName = ((TextView) layout.findViewById(R.id.tv_resouce_name)).getText().toString();
String urlstr = URL + musicName;
downloaders.get(urlstr).pause();
}
}
/*
5月8日
断点续传-音乐播放器
DownloadInfo
*/
package com.example.downloaderstopsart;
public class DownloadInfo {
private int threadId;// 下载器id
private int startPos;// 开始点
private int endPos;// 结束点
private int compeleteSize;// 完成度
private String url;// 下载器网络标识
public DownloadInfo(int threadId, int startPos, int endPos,
int compeleteSize, String url) {
this.threadId = threadId;
this.startPos = startPos;
this.endPos = endPos;
this.compeleteSize = compeleteSize;
this.url = url;
}
public DownloadInfo() {
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getThreadId() {
return threadId;
}
public void setThreadId(int threadId) {
this.threadId = threadId;
}
public int getStartPos() {
return startPos;
}
public void setStartPos(int startPos) {
this.startPos = startPos;
}
public int getEndPos() {
return endPos;
}
public void setEndPos(int endPos) {
this.endPos = endPos;
}
public int getCompeleteSize() {
return compeleteSize;
}
public void setCompeleteSize(int compeleteSize) {
this.compeleteSize = compeleteSize;
}
public String toString() {
return "DownloadInfo [threadId=" + threadId + ", startPos=" + startPos
+ ", endPos=" + endPos + ", compeleteSize=" + compeleteSize
+ "]";
}
}
/*
5月9日
断点续传-音乐播放器
LoadInfo
*/
package com.example.downloaderstopsart;
public class LoadInfo {
public int fileSize;// 文件大小
private int complete;// 完成度
private String urlstring;// 下载器标识
public LoadInfo(int fileSize, int complete, String urlstring) {
this.fileSize = fileSize;
this.complete = complete;
this.urlstring = urlstring;
}
public LoadInfo() {
}
public int getFileSize() {
return fileSize;
}
public void setFileSize(int fileSize) {
this.fileSize = fileSize;
}
public int getComplete() {
return complete;
}
public void setComplete(int complete) {
this.complete = complete;
}
public String getUrlstring() {
return urlstring;
}
public void setUrlstring(String urlstring) {
this.urlstring = urlstring;
}
@Override
public String toString() {
return "LoadInfo [fileSize=" + fileSize + ", complete=" + complete
+ ", urlstring=" + urlstring + "]";
}
}
/*
5月11日
Android 视频播放器
进度条的界面
*/
<SeekBar
android:id="@+id/play_seek"
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_marginLeft="-20dp"
android:layout_marginRight="-20dp"
android:indeterminate="false"
android:max="100"
android:progress="20"
android:progressDrawable="@drawable/seekbar_style2"
android:thumb="@null" />
/*
5月12日
Android 视频播放器
进度条的背景
*/
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<solid android:color="#707070" />
<size android:height="5dp" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<solid android:color="#994310" />
<size android:height="5dp" />
</shape>
</clip>
</item>
</layer-list>
/*
5月13日
Android 视频播放器
播放与暂停
*/
private Handler UIHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == UPDATE_UI) {
// 获取视频当前播放时间
int currentPosition = videoView.getCurrentPosition();
// 获取视频播放总时间
int totalduration = videoView.getDuration();
// 格式化视频播放时间
updateTextViewWithTimeFormat(time_current_tv, currentPosition);
updateTextViewWithTimeFormat(time_total_tv, totalduration);
play_seek.setMax(totalduration);
play_seek.setProgress(currentPosition);
UIHandler.sendEmptyMessageDelayed(UPDATE_UI, 500);
}
}
};
/*
5月14日
Android 视频播放器
播放与暂停
*/
play_controller_img.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (videoView.isPlaying()) {
play_controller_img.setImageResource(R.drawable.play_btn_selector);
videoView.pause();
UIHandler.removeMessages(UPDATE_UI);
} else {
play_controller_img.setImageResource(R.drawable.pause_btn_selector);
videoView.start();
UIHandler.sendEmptyMessage(UPDATE_UI);
}
}
});
/*
5月14日
Android 视频播放器
视频进度条
*/
play_seek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
updateTextViewWithTimeFormat(time_current_tv, progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
UIHandler.removeMessages(UPDATE_UI);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int progress = seekBar.getProgress();
// 视频播放进度拖至滚动条位置
videoView.seekTo(progress);
UIHandler.sendEmptyMessage(UPDATE_UI);
}
});
/*
5月15日
Android 视频播放器
音量进度条
*/
// 获取音频服务
mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
/**
* 获取设备最大音量
*/
int streamMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
/**
* 获取当前设备音量
*/
int streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
volume_seek.setMax(streamMaxVolume);
volume_seek.setProgress(streamVolume);
/*
5月16日
Android 视频播放器
绑定进度条的拖动事件
*/
volume_seek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
/**
* 设置当前音量
*/
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
/*
5月17日
Android 视频播放器
转动屏幕的切换
*/
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
/**
* 屏幕为横屏
*/
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
setVideoViewScale(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
volume_img.setVisibility(View.VISIBLE);
volume_seek.setVisibility(View.VISIBLE);
isFullScreen = true;
}
/**
* 屏幕为竖屏
*/
else {
setVideoViewScale(ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtil.dip2px(this, 240));
volume_img.setVisibility(View.GONE);
volume_seek.setVisibility(View.GONE);
isFullScreen = false;
}
}
/*
5月18日
Android 视频播放器
设置屏幕亮度
*/
/**
* 设置屏幕亮度
*/
private void setBrightness(Activity activity, float percent) {
if (activity == null) {
return;
}
if (percent < 0.01f) {
percent = 0.01f;
} else if (percent > 1.0f) {
percent = 1.0f;
}
WindowManager.LayoutParams params = activity.getWindow().getAttributes();
params.screenBrightness = percent;
activity.getWindow().setAttributes(params);
}
/*
5月19日
Android 视频播放器
获得当前屏幕亮度
*/
/**
* 获得当前屏幕亮度
*
* @param activity
* @return
*/
private float getBrightnessPercent(Activity activity) {
WindowManager.LayoutParams params = activity.getWindow().getAttributes();
return params.screenBrightness;
}
private Runnable mSwitchTitleRunnable = new Runnable() {
@Override
public void run() {
gestureOperationHelper.SingleTap();
}
};
/*
5月20日
Android 视频播放器
获得当前屏幕亮度
*/
private void initSensor() {
//初始化重力感应器,func:重力感应屏幕切换
sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
//获得重力传感器
sensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
listener = new OrientationSensorListener(mHandler);
sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI);
sm2 = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor2 = sm2.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
listener2 = new OrientationSensorListener2();
sm2.registerListener(listener2, sensor2, SensorManager.SENSOR_DELAY_UI);
}
/*
5月21日
Android 视频播放器
全屏 或者 退出全屏 播放
*/
/**
* 全屏 或者 退出全屏 播放
*/
iv_full.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("HHHH", "切换横屏)))" + stretch_flag);
// stretch_flag = sp1.getBoolean("stretch_flag", true);
if (stretch_flag) {
//切换成横屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
stretch_flag = false;
} else {
//切换成竖屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
stretch_flag = true;
}
/*
5月21日
Android 视频播放器
播放器状态
*/
public void onClick(View v) {
switch (v.getId()) {
case R.id.imageView_main_play:
if (iv_suolue != null && iv_suolue.getVisibility() == View.VISIBLE) {
iv_suolue.setVisibility(View.GONE);
}
Log.i(TAG, "imageView_main_play::播放" + imageView_main_show.isSelected());
// if (mediaPlayer != null && imageView_main_show.isSelected()&& mediaPlayer.isPlaying()) {
//说明此时正在播放,播放按钮处于播放状态
try {
if (mediaPlayer != null && imageView_main_show.isSelected() && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
//此时控制条的播放组件应该是显示暂停状态
if (iv_play != null) {
iv_play.setSelected(false);
// iv_play.setImageResource(R.drawable.fvl_selector_play);
}
imageView_main_show.setSelected(false);
} else if (mediaPlayer != null && !imageView_main_show.isSelected()) {
imageView_main_show.setSelected(true);
mediaPlayer.start();
//此时控制条的播放组件应该是显示播放状态
if (iv_play != null) {
iv_play.setSelected(true);
}
imageView_main_show.setVisibility(View.GONE);
}
/*
5月22日
Android 视频播放器
视频大小
*/
public void handleMessage(Message msg) {
super.handleMessage(msg);
Activity activity = weakReference.get();
if (activity != null) {
switch (msg.what) {
case MEASURE_VIDEO_SIZE:
/**
* 测量的视频大小
*/
/**
* 设置播放大小,如果视频的大小>显示器 设置显示器 反之 视频,取小的设置比率
*/
videoWidth = mediaPlayer.getVideoWidth();
Log.i(TAG, "视频的宽度:" + videoWidth);
Log.i(TAG, "视频的宽度:::" + screenWidth);
videoHeight = mediaPlayer.getVideoHeight();
Log.i(TAG, "视频的高度:" + videoHeight);
Log.i(TAG, "视频的高度:::" + screenHeight);
// screenHeight = display.getHeight();
if (videoWidth > display.getWidth() || videoHeight > screenHeight) {
//视频的大小>显示器的大小
float heightRatio = (float) videoHeight / (float) screenHeight;//高度比率
float widthRatio = (float) videoWidth / (float) screenWidth;//宽度比率
if (heightRatio > widthRatio) {
videoHeight = (int) Math.ceil((float) videoHeight / heightRatio);
videoWidth = (int) Math.ceil((float) videoWidth / heightRatio);
} else {
videoHeight = (int) Math.ceil((float) videoHeight / widthRatio);
videoWidth = (int) Math.ceil((float) videoWidth / widthRatio);
}
}
/*
5月23日
Android 视频播放器
切换屏幕
*/
int orientation = msg.arg1;
if (orientation > 45 && orientation < 135) {
} else if (orientation > 135 && orientation < 225) {
} else if (orientation > 225 && orientation < 315) {
Log.i(TAG, "切换成横屏");
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
sennorFlag = false;
stretch_flag = false;
} else if ((orientation > 315 && orientation < 360) || (orientation > 0 && orientation < 45))
Log.i(TAG, "切换成竖屏");
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
sennorFlag = true;
stretch_flag = true;
}
break;
/*
5月24日
Android 视频播放器
当出现关于播放媒体的特定信息或者需要发出警告的时候,将调用onInfo
*/
public boolean onInfo(MediaPlayer mp, int what, int extra) {
Log.i(TAG, "onInfo:");
if (what == MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING) {
//当文件中的音频和视频数据不正确的交错的时候会触发
Log.i(TAG, "onInfo:MEDIA_INFO_BAD_INTERLEAVING:" + extra);
} else if (what == MediaPlayer.MEDIA_INFO_NOT_SEEKABLE) {
//当媒体不能正确的定位
Log.i(TAG, "onInfo:MEDIA_INFO_NOT_SEEKABLE:" + extra);
} else if (what == MediaPlayer.MEDIA_INFO_UNKNOWN) {
//媒体信息尚未指定或者未知
Log.i(TAG, "onInfo:MEDIA_INFO_UNKNOWN:" + extra);
} else if (what == MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING) {
//无法播放视频或者音频太复杂或者码率过高
Log.i(TAG, "onInfo:MEDIA_INFO_VIDEO_TRACK_LAGGING:" + extra);
} else if (what == MediaPlayer.MEDIA_INFO_METADATA_UPDATE) {
//当新的元数据可用时
Log.i(TAG, "onInfo:MEDIA_INFO_METADATA_UPDATE:" + extra);
}
return false;
}
@Override
public void onPrepared(MediaPlayer mp) {
try {
/*当不是全屏的时候才需要测量,才需要比较*/
if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
//因为配置文件中并未设置横竖屏
mHandler.sendEmptyMessageDelayed(MEASURE_VIDEO_SIZE, 1000);
} else if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
mHandler.sendEmptyMessageDelayed(MEASURE_VIDEO_SIZE, 1000);
}
//Log.i("屏幕方向:::", isLandScape + "");
/*
5月25日
Android 视频播放器
重力感应监听
*/
public class OrientationSensorListener implements SensorEventListener {
private static final int _DATA_X = 0;
private static final int _DATA_Y = 1;
private static final int _DATA_Z = 2;
public static final int ORIENTATION_UNKNOWN = -1;
private MyHandler myHandler;
private boolean isSupportGravity = false;
public OrientationSensorListener(MyHandler myHandler) {
this.myHandler = myHandler;
}
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub
}
public void onSensorChanged(SensorEvent event) {
/**
* 检测手机自动旋转屏幕的功能是否打开
*/
isSupportGravity = isscreenAutoRotate()
if (!isSupportGravity) {
return;
}
if (sennorFlag != stretch_flag) //只有两个不相同才开始监听行为
{
float[] values = event.values;
int orientation = ORIENTATION_UNKNOWN;
float X = -values[_DATA_X];
float Y = -values[_DATA_Y];
float Z = -values[_DATA_Z];
float magnitude = X * X + Y * Y;
// Don't trust the angle if the magnitude is small compared to the y value
if (magnitude * 4 >= Z * Z) {
//屏幕旋转时
float OneEightyOverPi = 57.29577957855f;
float angle = (float) Math.atan2(-Y, X) * OneEightyOverPi;
orientation = 90 - (int) Math.round(angle);
// normalize to 0 - 359 range
while (orientation >= 360) {
orientation -= 360;
}
while (orientation < 0) {
orientation += 360;
}
}
if (myHandler != null) {
myHandler.obtainMessage(10001, orientation, 0).sendToTarget();
}
}
}
}
/*
5月26日
Android 视频播放器
重力感应监听
*/
public class OrientationSensorListener2 implements SensorEventListener {
//初始化重力感应器的坐标轴
private static final int sensor_X = 0;
private static final int sensor_Y = 1;
private static final int sensor_Z = 2;
private static final int ORIENTATION_UNKNOW = -1;
private boolean isSupportGravity = false;
public OrientationSensorListener2() {
}
@Override
public void onSensorChanged(SensorEvent event) {
/**
* 检测手机自动旋转屏幕的功能是否打开
*/
isSupportGravity = isscreenAutoRotate();
if (!isSupportGravity) {
return;
}
float[] values = event.values;
int orientation = ORIENTATION_UNKNOW;
float X = -values[sensor_X];
float Y = -values[sensor_Y];
* 重力传感器监听手机的摆放状态的算法
*/
float magnitude = X * X + Y * Y;
// Don't trust the angle if the magnitude is small compared to the y value
if (magnitude * 4 >= Z * Z) {
//屏幕旋转时
float OneEightyOverPi = 57.29577957855f;
float angle = (float) Math.atan2(-Y, X) * OneEightyOverPi;
orientation = 90 - (int) Math.round(angle);
// normalize to 0 - 359 range
while (orientation >= 360) {
orientation -= 360;
}
while (orientation < 0) {
orientation += 360;
}
}
if (orientation > 225 && orientation < 315) { //横屏
sennorFlag = false;
} else if ((orientation > 315 && orientation < 360) || (orientation > 0 && orientation < 45)) { //竖屏
sennorFlag = true;
}
if (stretch_flag == sennorFlag) { //点击变成横屏 屏幕 也转横屏 激活
Log.i(TAG, "激活");
sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI);
}
}
@Override
/*
5月28日
Android 视频播放器
重力感应监听
*/
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.i("TTTTT", "onConfigurationChanged");
if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
//如果是横屏
Log.i("WWWWWW", "横屏");
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
surfaceView.setLayoutParams(params);
if (iv_suolue.getVisibility() == View.VISIBLE && !iv_play.isSelected() && !imageView_main_show.isSelected()) {
iv_suolue.setVisibility(View.GONE);
new GetVideoBitmapAsyncTask(iv_suolue, surfaceView).execute(filepath);
}
} else if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
mHandler.sendEmptyMessage(MEASURE_VIDEO_SIZE);
Log.i("*****", "竖屏");
} else if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
mHandler.sendEmptyMessage(MEASURE_VIDEO_SIZE);
Log.i("*****", "无屏");
}
}
/*
5月29日
Android 视频播放器
重力感应监听
*/
/**
* 检测手机自动旋转的是否打开
*
* @return
*/
private boolean isscreenAutoRotate() {
int gravity = 0;
try {
gravity = Settings.System.getInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
Log.i(TAG, "检测手机是否打开屏幕旋转出错");
}
return gravity == 1;
}
}
/*
5月30日
Android 视频播放器
MainActivity
*/
package com.example.videotest1;
import com.example.service.ServiceTest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
public static SurfaceView sv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sv = (SurfaceView) findViewById(R.id.surfaceView1);// 获得SurfaceView控件
}
/*
*点击那4个按钮后触发的事件
*/
public void click(View v) {
Intent intent = new Intent(MainActivity.this, ServiceTest.class);
int op = -1;// 定义一个中间变量
switch (v.getId()) {
case R.id.play:
op = 1;
Toast.makeText(MainActivity.this, "视频正在播放...", Toast.LENGTH_SHORT)
.show();
break;
case R.id.pause:
op = 2;
Toast.makeText(MainActivity.this, "视频暂停播放...", Toast.LENGTH_SHORT)
.show();
break;
case R.id.stop:
op = 3;
Toast.makeText(MainActivity.this, "视频停止播放...", Toast.LENGTH_SHORT)
.show();
break;
case R.id.finish:
if (intent != null) {
stopService(intent);
}
finish();
break;
default:
break;
}
Bundle bundle = new Bundle();// 声明一个Bundle对象并实例化
bundle.putInt("middle", op);// 把中间变量op放置到middle这个键
intent.putExtras(bundle);// 用intent把bundle放入进去
startService(intent);// 开始服务
}
/*
5月31日
Android 视频播放器
MainActivity
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
/*
6月1日
Android 视频播放器
ServiceTest
*/
package com.example.service;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.IBinder;
public class ServiceTest extends Service {
public static MediaPlayer player;// 声明MediaPlayer对象
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
// 创建服务
@Override
public void onCreate() {
// TODO Auto-generated method stub
if (player == null) {
try {
player = new MediaPlayer();//实例化MediaPlayer对象
player.setDataSource("/sdcard/wf2.mp4");// 设置要播放的视频
player.setLooping(false);// 设置视频不循环播放
super.onCreate();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// 开始服务
/*
6月2日
Android 视频播放器
ServiceTest
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Bundle bundle = intent.getExtras();// 获得从MainActivity传来的bundle对象
int op = bundle.getInt("middle");// 获得从MainActivity.java里传递过来的op
switch (op) {
case 1:// 当op为1,即点击了播放按钮
play();// 调用play()方法
break;
case 2:// 当op为2,即点击了暂停按钮
pause();// 调用pause()方法
break;
case 3:// 当op为3,即点击了停止按钮
stop();// 调用stop()方法
break;
default:
break;
}
return super.onStartCommand(intent, flags, startId);
}
// 播放视频play()方法
private void play() {
// TODO Auto-generated method stub
if (player != null && !player.isPlaying()) {
player.setDisplay(com.example.videotest1.MainActivity.sv
.getHolder());//把视频画面显示出来
try {
player.prepare();//预加载视频
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
player.start();// 开始播放音乐
}
}
/*
6月3日
Android 视频播放器
ServiceTest
*/
private void pause() {
// TODO Auto-generated method stub
if (player != null && player.isPlaying()) {
player.pause();// 暂停视频的播放
}
}
private void stop() {
// TODO Auto-generated method stub
if (player != null) {
player.seekTo(0);//如果点击播放按钮的话会从头播放
player.stop();// 停止音乐的播放
}
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
if (player != null) {
player.stop();//停止播放视频
player.release();// 释放资源
player = null;
}
super.onDestroy();
}
}
3月26日
Android异步消息机制
Handler的常规使用方式
*/
/**
* 测试Activity,主要用于测试异步消息(Handler)的使用方式
*/
public class MainActivity extends AppCompatActivity {
public static final String TAG = MainActivity.class.getSimpleName();
private TextView texttitle = null;
/**
* 在主线程中定义Handler,并实现对应的handleMessage方法
* 一般handler的使用方式都是在主线程中定义Handler,然后在子线程中调用mHandler.sendEmptyMessage();方法
*/
public static Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 101) {
Log.i(TAG, "接收到handler消息...");
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
texttitle = (TextView) findViewById(R.id.texttitle);
texttitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
// 在子线程中发送异步消息
mHandler.sendEmptyMessage(101);
}
}.start();
}
});
}
}
/*
3月27日
Android异步消息机制
在子线程中定义Handler
*/
/**
* 定义texttitle的点击事件处理
* 在初始化Handler对象之前需要调用Looper.prepare()方法
*/
texttitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
Looper.prepare();
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 101) {
Log.i(TAG, "在子线程中定义Handler,并接收到消息。。。");
}
}
};
}
}.start();
}
});
/*
3月28日
Android异步消息机制
App初始化的时候执行ActivityThread的main方法
*/
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
CloseGuard defaults to true and can be quite spammy. We
disable it here, but selectively enable it later (via
StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
AndroidKeyStoreProvider.install();
//Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
/*
3月29日
Android异步消息机制
Handler的标准写法
*/
Looper.prepare();
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 101) {
Log.i(TAG, "在子线程中定义Handler,并接收到消息。。。");
}
}
};
Looper.loop();
/*
3月30日
Android异步消息机制
查看Looper.prepare()方法
*/
sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
//Looper对象的构造方法,可以看到在其构造方法中初始化了一个MessageQueue对象
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
/*
3月31日
Android异步消息机制
查看Handler对象的构造方法
*/
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
//查看handler.sendMessage(msg)方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
/*
4月1日
Android异步消息机制
查看messagequeue对象的enqueueMessage方法
*/
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
/*
4月2日
Android异步消息机制
查看Looper.Loop()方法
*/
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
/Make sure the identity of this thread is that of the local process,
and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
Make sure that during the course of dispatching the
identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
/*
4月3日
Android异步消息机制
Looper.loop()方法里起了一个死循环,不断的判断MessageQueue中的消息是否为空,如果为空则直接return掉,然后执行queue.next()方法:
*/
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
/*
4月4日
Android异步消息机制
Looper.loop()方法里起了一个死循环,不断的判断MessageQueue中的消息是否为空,如果为空则直接return掉,然后执行queue.next()方法:
*/
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
/*
4月5日
Android异步消息机制
Looper.loop()方法里起了一个死循环,不断的判断MessageQueue中的消息是否为空,如果为空则直接return掉,然后执行queue.next()方法:
*/
Run the idle handlers.
We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
/*
4月6日
Android异步消息机制
查看Handler类的dispatchMessage方法
*/
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
/*
4月7日
Android异步消息机制
总结
*/
主线程中定义Handler,直接执行:
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
在子线程中定义Handler,则标准的写法为:
// 初始化该线程Looper,MessageQueue,执行且只能执行一次
Looper.prepare();
// 初始化Handler对象,内部关联Looper对象
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
// 启动消息队列出栈死循环
Looper.loop();
Handler的post方法:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
view的post方法:
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().post(action);
return true;
activity的runOnUiThread方法:
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
/*
4月10日
异步任务AsyncTask
AsyncTask的基本使用
*/
/**
* 自定义AsyncTask对象
*/
class MAsyncTask extends AsyncTask<Integer, Integer, Integer> {
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.i(TAG, "onPreExecute...(开始执行后台任务之前)");
}
@Override
protected void onPostExecute(Integer i) {
super.onPostExecute(i);
Log.i("TAG", "onPostExecute...(开始执行后台任务之后)");
}
@Override
protected Integer doInBackground(Integer... params) {
Log.i(TAG, "doInBackground...(开始执行后台任务)");
return 0;
}
}
/*
4月11日
异步任务AsyncTask
查看异步任务的构造方法
*/
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
/*
4月13日
异步任务AsyncTask
测试在子线程中通过MAsyncTask执行异步操作
*/
/**
* 测试代码,测试在子线程中通过MAsyncTask执行异步操作
*/
new Thread(new Runnable() {
@Override
public void run() {
Log.i("tag", Thread.currentThread().getId() + "");
new MAsyncTask().execute();
}
}).start();
Log.i("tag", "mainThread:" + Thread.currentThread().getId() + "");
/*
4月14日
异步任务AsyncTask
execute方法内部调用了executeOnExecutor方法
*/
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
/*
4月14日
异步任务AsyncTask
执行了execute方法之后,如果再次执行就会进入这里的if条件判断并抛出异常
*/
final MAsyncTask mAsyncTask = new MAsyncTask();
title.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/*MLog.e("you have clicked the title textview!!!");
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivityForResult(intent, 101);*/
new Thread(new Runnable() {
@Override
public void run() {
Log.i("tag", Thread.currentThread().getId() + "");
mAsyncTask
.execute();
}
}).start();
Log.i("tag", "mainThread:" + Thread.currentThread().getId() + "");
}
});
/*
4月15日
异步任务AsyncTask
查看SerialExecutor的具体实现
*/
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
/*
4月16日
异步任务AsyncTask
AsyncTask内部定义了一个Handler对象
*/
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
/*
4月17日
异步任务AsyncTask
异步任务完成的消息会调用finish方法
*/
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
/*
4月18日
HandlerThread
HandlerThread的基本用法
*/
/**
* 测试HandlerThread的基本使用
*/
HandlerThread mHandlerThread = new HandlerThread("myHandlerThreand");
mHandlerThread.start();
// 创建的Handler将会在mHandlerThread线程中执行
final Handler mHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
Log.i("tag", "接收到消息:" + msg.obj.toString());
}
};
title = (TextView) findViewById(R.id.title);
title.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message msg = new Message();
msg.obj = "11111";
mHandler.sendMessage(msg);
msg = new Message();
msg.obj = "2222";
mHandler.sendMessage(msg);
}
});
/*
4月19日
HandlerThread
Thread的run方法
*/
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/*
4月20日
IntentService
自身含有消息循环的Service
定义一个IntentService
*/
/**
* 自定义IntentService
*/
public class MIntentService extends IntentService{
public MIntentService() {
super("");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.i("tag", intent.getStringExtra("params") + " " + Thread.currentThread().getId());
}
}
/*
4月21日
IntentService
自身含有消息循环的Service
启动service
*/
/**
* 定义TextView点击事件,启动IntentService服务
*/
title.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MIntentService.class);
intent.putExtra("params", "ceshi");
startService(intent);
}
});
点击title组件的时候,service接收到了消息并打印出了传递过去的intent参数,同时显示onHandlerIntent方法执行的线程ID并非主线程
/*
4月22日
IntentService
自身含有消息循环的Service
service源码
*/
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(Intent intent);
}
/*
4月23日
IntentService
自身含有消息循环的Service
消息队列的处理逻辑
*/
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
/*
4月24日
SystemServer进程启动流程
SystemServer.run方法的实现
*/
private void run() {
...
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
Slog.w(TAG, "System clock is before 1970; setting to 1970.");
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}
...
if (!SystemProperties.get("persist.sys.language").isEmpty()) {
final String languageTag = Locale.getDefault().toLanguageTag();
SystemProperties.set("persist.sys.locale", languageTag);
SystemProperties.set("persist.sys.language", "");
SystemProperties.set("persist.sys.country", "");
SystemProperties.set("persist.sys.localevar", "");
}
// Here we go!
Slog.i(TAG, "Entered the Android system server!");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis())
...
SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
// Enable the sampling profiler.
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
mProfilerSnapshotTimer = new Timer();
mProfilerSnapshotTimer.schedule(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegration.writeSnapshot("system_server", null);
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}
/*
4月25日
SystemServer进程启动流程
SystemServer.run方法的实现
*/
VMRuntime.getRuntime().clearGrowthLimit();
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
// Some devices rely on runtime fingerprint generation, so make sure
// we've defined it before booting further.
Build.ensureFingerprintProperty();
// Within the system server, it is an error to access Environment paths without
// explicitly specifying a user.
Environment.setUserRequired(true);
// Ensure binder calls into the system always run at foreground priority.
BinderInternal.disableBackgroundScheduling(true);
// Prepare the main looper thread (this thread).
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
Looper.prepareMainLooper();
// Initialize native services.
System.loadLibrary("android_servers");
// Check whether we failed to shut down last time we tried.
// This call may not return.
performPendingShutdown();
// Initialize the system context.
createSystemContext();
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Start services.
try {
startBootstrapServices();
startCoreServices();
startOtherServices();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
}
// For debug builds, log event loop stalls to dropbox for analysis.
if (StrictMode.conditionallyEnableDebugLogging()) {
Slog.i(TAG, "Enabled StrictMode for system server main thread.");
}
// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
/*
4月26日
SystemServer进程启动流程
startBootstrapServices() 主要用于启动系统Boot级服务
startBootstrapServices方法
*/
private void startBootstrapServices() {
Installer installer = mSystemServiceManager.startService(Installer.class);
// Activity manager runs the show.
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
// Now that the power manager has been started, let the activity manager
// initialize power management features.
mActivityManagerService.initPowerManagement();
// Manages LEDs and display backlight so we need it to bring up the display.
mSystemServiceManager.startService(LightsService.class);
// Display manager is needed to provide display metrics before package manager
// starts up.
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
// We need the default display before we can initialize the package manager.
mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
// Only run "core" apps if we're encrypting the device.
String cryptState = SystemProperties.get("vold.decrypt");
if (ENCRYPTING_STATE.equals(cryptState)) {
Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
mOnlyCore = true;
} else if (ENCRYPTED_STATE.equals(cryptState)) {
Slog.w(TAG, "Device encrypted - only parsing core apps");
mOnlyCore = true;
}
/*
4月27日
SystemServer进程启动流程
startBootstrapServices() 主要用于启动系统Boot级服务
startBootstrapServices方法
*/
Slog.i(TAG, "Package Manager");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
Slog.i(TAG, "User Service");
ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());
// Initialize attribute cache used to cache resources from packages.
AttributeCache.init(mSystemContext);
// Set up the Application instance for the system process and get started.
mActivityManagerService.setSystemProcess();
// The sensor service needs access to package manager service, app ops
// service, and permissions service, therefore we start it after them.
startSensorService();
}
/*
4月28日
SystemServer进程启动流程
startCoreServices() 主要用于启动系统核心的服务
startService方法的具体实现
*/
public <T extends SystemService> T startService(Class<T> serviceClass) {
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);
// Create the service.
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service could not be instantiated", ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (NoSuchMethodException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service constructor threw an exception", ex);
}
// Register it.
mServices.add(service);
// Start it.
try {
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + name
+ ": onStart threw an exception", ex);
}
return service;
}
//通过反射器构造方法创建出服务类,然后添加到SystemServiceManager的服务列表数据中,最后调用了service.onStart()方法
/*
4月29日
SystemServer进程启动流程
Lifecycle类的定义
*/
public static final class Lifecycle extends SystemService {
private final ActivityManagerService mService;
public Lifecycle(Context context) {
super(context);
mService = new ActivityManagerService(context);
}
@Override
public void onStart() {
mService.start();
}
public ActivityManagerService getService() {
return mService;
}
}
/*
4月30日
SystemServer进程启动流程
ActivityManagerService的start方法的实现
*/
private void start() {
Process.removeAllProcessGroups();
mProcessCpuThread.start()
mBatteryStatsService.publish(mContext);
mAppOpsService.publish(mContext);
Slog.d("AppOps", "AppOpsService published");
LocalServices.addService(ActivityManagerInternal.class, new LocalService());
}
/*
5月1日
SystemServer进程启动流程
startCoreServices方法
*/
private void startCoreServices() {
// Tracks the battery level. Requires LightService.
mSystemServiceManager.startService(BatteryService.class);
// Tracks application usage stats.
mSystemServiceManager.startService(UsageStatsService.class);
mActivityManagerService.setUsageStatsManager(
LocalServices.getService(UsageStatsManagerInternal.class));
// Update after UsageStatsService is available, needed before performBootDexOpt.
mPackageManagerService.getUsageStatsIfNoPackageUsageInfo()
// Tracks whether the updatable WebView is in a ready state and watches for update installs.
mSystemServiceManager.startService(WebViewUpdateService.class);
}
/*
5月3日
断点续传-音乐播放器
主框架
*/
public class MainActivity extends ListActivity {
// 固定下载的资源路径,这里可以设置网络上的地址private static final String URL = "http://10.81.36.193:8080/";
// 固定存放下载的音乐的路径:SD卡目录下
private static final String SD_PATH = "/mnt/sdcard/";
// 存放各个下载器
private Map<String, Downloader> downloaders = new HashMap<String, Downloader>();
// 存放与下载器对应的进度条
private Map<String, ProgressBar> ProgressBars = new HashMap<String, ProgressBar>();
/**
* 利用消息处理机制适时更新进度条
*/
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 1) {
String url = (String) msg.obj;
int length = msg.arg1;
ProgressBar bar = ProgressBars.get(url);
if (bar != null) {
// 设置进度条按读取的length长度更新
bar.incrementProgressBy(length);
if (bar.getProgress() == bar.getMax()) {
Toast.makeText(MainActivity.this, "下载完成!", 0).show();
// 下载完成后清除进度条并将map中的数据清空
/*
5月4日
断点续传-音乐播放器
主框架
*/
LinearLayout layout = (LinearLayout) bar.getParent();
layout.removeView(bar);
ProgressBars.remove(url);
downloaders.get(url).delete(url);
downloaders.get(url).reset();
downloaders.remove(url);
}
}
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showListView();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());
}
/*
5月5日
断点续传-音乐播放器
主框架
*/
// 显示listView,这里可以随便添加音乐
private void showListView() {
List<Map<String, String>> data = new ArrayList<Map<String, String>>();
Map<String, String> map = new HashMap<String, String>();
map.put("name", "mm.mp3");
data.add(map);
map = new HashMap<String, String>();
map.put("name", "pp.mp3");
data.add(map);
map = new HashMap<String, String>();
map.put("name", "tt.mp3");
data.add(map);
map = new HashMap<String, String>();
map.put("name", "ou.mp3");
data.add(map);
SimpleAdapter adapter = new SimpleAdapter(this, data, R.layout.list_item, new String[] { "name" },
new int[] { R.id.tv_resouce_name });
setListAdapter(adapter);
}
/**
* 响应开始下载按钮的点击事件
*/
public void startDownload(View v) {
// 得到textView的内容
LinearLayout layout = (LinearLayout) v.getParent();
String musicName = ((TextView) layout.findViewById(R.id.tv_resouce_name)).getText().toString();
String urlstr = URL + musicName;
String localfile = SD_PATH + musicName;
/*
5月6日
断点续传-音乐播放器
主框架
*/
public void startDownload(View v) {
// 得到textView的内容
LinearLayout layout = (LinearLayout) v.getParent();
String musicName = ((TextView) layout.findViewById(R.id.tv_resouce_name)).getText().toString();
String urlstr = URL + musicName;
String localfile = SD_PATH + musicName;
//设置下载线程数为4,这里是我为了方便随便固定的
int threadcount = 4;
// 初始化一个downloader下载器
Downloader downloader = downloaders.get(urlstr);
if (downloader == null) {
downloader = new Downloader(urlstr, localfile, threadcount, this, mHandler);
downloaders.put(urlstr, downloader);
}
if (downloader.isdownloading())
return;
// 得到下载信息类的个数组成集合
LoadInfo loadInfo = downloader.getDownloaderInfors();
// 显示进度条
showProgress(loadInfo, urlstr, v);
// 调用方法开始下载
downloader.download();
}
/*
5月7日
断点续传-音乐播放器
主框架
*/
/**
* 显示进度条
*/
private void showProgress(LoadInfo loadInfo, String url, View v) {
ProgressBar bar = ProgressBars.get(url);
if (bar == null) {
bar = new ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal);
bar.setMax(loadInfo.getFileSize());
bar.setProgress(loadInfo.getComplete());
ProgressBars.put(url, bar);
LinearLayout.LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, 5);
((LinearLayout) ((LinearLayout) v.getParent()).getParent()).addView(bar, params);
}
}
/**
* 响应暂停下载按钮的点击事件
*/
public void pauseDownload(View v) {
LinearLayout layout = (LinearLayout) v.getParent();
String musicName = ((TextView) layout.findViewById(R.id.tv_resouce_name)).getText().toString();
String urlstr = URL + musicName;
downloaders.get(urlstr).pause();
}
}
/*
5月8日
断点续传-音乐播放器
DownloadInfo
*/
package com.example.downloaderstopsart;
public class DownloadInfo {
private int threadId;// 下载器id
private int startPos;// 开始点
private int endPos;// 结束点
private int compeleteSize;// 完成度
private String url;// 下载器网络标识
public DownloadInfo(int threadId, int startPos, int endPos,
int compeleteSize, String url) {
this.threadId = threadId;
this.startPos = startPos;
this.endPos = endPos;
this.compeleteSize = compeleteSize;
this.url = url;
}
public DownloadInfo() {
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getThreadId() {
return threadId;
}
public void setThreadId(int threadId) {
this.threadId = threadId;
}
public int getStartPos() {
return startPos;
}
public void setStartPos(int startPos) {
this.startPos = startPos;
}
public int getEndPos() {
return endPos;
}
public void setEndPos(int endPos) {
this.endPos = endPos;
}
public int getCompeleteSize() {
return compeleteSize;
}
public void setCompeleteSize(int compeleteSize) {
this.compeleteSize = compeleteSize;
}
public String toString() {
return "DownloadInfo [threadId=" + threadId + ", startPos=" + startPos
+ ", endPos=" + endPos + ", compeleteSize=" + compeleteSize
+ "]";
}
}
/*
5月9日
断点续传-音乐播放器
LoadInfo
*/
package com.example.downloaderstopsart;
public class LoadInfo {
public int fileSize;// 文件大小
private int complete;// 完成度
private String urlstring;// 下载器标识
public LoadInfo(int fileSize, int complete, String urlstring) {
this.fileSize = fileSize;
this.complete = complete;
this.urlstring = urlstring;
}
public LoadInfo() {
}
public int getFileSize() {
return fileSize;
}
public void setFileSize(int fileSize) {
this.fileSize = fileSize;
}
public int getComplete() {
return complete;
}
public void setComplete(int complete) {
this.complete = complete;
}
public String getUrlstring() {
return urlstring;
}
public void setUrlstring(String urlstring) {
this.urlstring = urlstring;
}
@Override
public String toString() {
return "LoadInfo [fileSize=" + fileSize + ", complete=" + complete
+ ", urlstring=" + urlstring + "]";
}
}
/*
5月11日
Android 视频播放器
进度条的界面
*/
<SeekBar
android:id="@+id/play_seek"
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_marginLeft="-20dp"
android:layout_marginRight="-20dp"
android:indeterminate="false"
android:max="100"
android:progress="20"
android:progressDrawable="@drawable/seekbar_style2"
android:thumb="@null" />
/*
5月12日
Android 视频播放器
进度条的背景
*/
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<solid android:color="#707070" />
<size android:height="5dp" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<solid android:color="#994310" />
<size android:height="5dp" />
</shape>
</clip>
</item>
</layer-list>
/*
5月13日
Android 视频播放器
播放与暂停
*/
private Handler UIHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == UPDATE_UI) {
// 获取视频当前播放时间
int currentPosition = videoView.getCurrentPosition();
// 获取视频播放总时间
int totalduration = videoView.getDuration();
// 格式化视频播放时间
updateTextViewWithTimeFormat(time_current_tv, currentPosition);
updateTextViewWithTimeFormat(time_total_tv, totalduration);
play_seek.setMax(totalduration);
play_seek.setProgress(currentPosition);
UIHandler.sendEmptyMessageDelayed(UPDATE_UI, 500);
}
}
};
/*
5月14日
Android 视频播放器
播放与暂停
*/
play_controller_img.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (videoView.isPlaying()) {
play_controller_img.setImageResource(R.drawable.play_btn_selector);
videoView.pause();
UIHandler.removeMessages(UPDATE_UI);
} else {
play_controller_img.setImageResource(R.drawable.pause_btn_selector);
videoView.start();
UIHandler.sendEmptyMessage(UPDATE_UI);
}
}
});
/*
5月14日
Android 视频播放器
视频进度条
*/
play_seek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
updateTextViewWithTimeFormat(time_current_tv, progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
UIHandler.removeMessages(UPDATE_UI);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int progress = seekBar.getProgress();
// 视频播放进度拖至滚动条位置
videoView.seekTo(progress);
UIHandler.sendEmptyMessage(UPDATE_UI);
}
});
/*
5月15日
Android 视频播放器
音量进度条
*/
// 获取音频服务
mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
/**
* 获取设备最大音量
*/
int streamMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
/**
* 获取当前设备音量
*/
int streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
volume_seek.setMax(streamMaxVolume);
volume_seek.setProgress(streamVolume);
/*
5月16日
Android 视频播放器
绑定进度条的拖动事件
*/
volume_seek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
/**
* 设置当前音量
*/
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
/*
5月17日
Android 视频播放器
转动屏幕的切换
*/
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
/**
* 屏幕为横屏
*/
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
setVideoViewScale(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
volume_img.setVisibility(View.VISIBLE);
volume_seek.setVisibility(View.VISIBLE);
isFullScreen = true;
}
/**
* 屏幕为竖屏
*/
else {
setVideoViewScale(ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtil.dip2px(this, 240));
volume_img.setVisibility(View.GONE);
volume_seek.setVisibility(View.GONE);
isFullScreen = false;
}
}
/*
5月18日
Android 视频播放器
设置屏幕亮度
*/
/**
* 设置屏幕亮度
*/
private void setBrightness(Activity activity, float percent) {
if (activity == null) {
return;
}
if (percent < 0.01f) {
percent = 0.01f;
} else if (percent > 1.0f) {
percent = 1.0f;
}
WindowManager.LayoutParams params = activity.getWindow().getAttributes();
params.screenBrightness = percent;
activity.getWindow().setAttributes(params);
}
/*
5月19日
Android 视频播放器
获得当前屏幕亮度
*/
/**
* 获得当前屏幕亮度
*
* @param activity
* @return
*/
private float getBrightnessPercent(Activity activity) {
WindowManager.LayoutParams params = activity.getWindow().getAttributes();
return params.screenBrightness;
}
private Runnable mSwitchTitleRunnable = new Runnable() {
@Override
public void run() {
gestureOperationHelper.SingleTap();
}
};
/*
5月20日
Android 视频播放器
获得当前屏幕亮度
*/
private void initSensor() {
//初始化重力感应器,func:重力感应屏幕切换
sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
//获得重力传感器
sensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
listener = new OrientationSensorListener(mHandler);
sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI);
sm2 = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor2 = sm2.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
listener2 = new OrientationSensorListener2();
sm2.registerListener(listener2, sensor2, SensorManager.SENSOR_DELAY_UI);
}
/*
5月21日
Android 视频播放器
全屏 或者 退出全屏 播放
*/
/**
* 全屏 或者 退出全屏 播放
*/
iv_full.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("HHHH", "切换横屏)))" + stretch_flag);
// stretch_flag = sp1.getBoolean("stretch_flag", true);
if (stretch_flag) {
//切换成横屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
stretch_flag = false;
} else {
//切换成竖屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
stretch_flag = true;
}
/*
5月21日
Android 视频播放器
播放器状态
*/
public void onClick(View v) {
switch (v.getId()) {
case R.id.imageView_main_play:
if (iv_suolue != null && iv_suolue.getVisibility() == View.VISIBLE) {
iv_suolue.setVisibility(View.GONE);
}
Log.i(TAG, "imageView_main_play::播放" + imageView_main_show.isSelected());
// if (mediaPlayer != null && imageView_main_show.isSelected()&& mediaPlayer.isPlaying()) {
//说明此时正在播放,播放按钮处于播放状态
try {
if (mediaPlayer != null && imageView_main_show.isSelected() && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
//此时控制条的播放组件应该是显示暂停状态
if (iv_play != null) {
iv_play.setSelected(false);
// iv_play.setImageResource(R.drawable.fvl_selector_play);
}
imageView_main_show.setSelected(false);
} else if (mediaPlayer != null && !imageView_main_show.isSelected()) {
imageView_main_show.setSelected(true);
mediaPlayer.start();
//此时控制条的播放组件应该是显示播放状态
if (iv_play != null) {
iv_play.setSelected(true);
}
imageView_main_show.setVisibility(View.GONE);
}
/*
5月22日
Android 视频播放器
视频大小
*/
public void handleMessage(Message msg) {
super.handleMessage(msg);
Activity activity = weakReference.get();
if (activity != null) {
switch (msg.what) {
case MEASURE_VIDEO_SIZE:
/**
* 测量的视频大小
*/
/**
* 设置播放大小,如果视频的大小>显示器 设置显示器 反之 视频,取小的设置比率
*/
videoWidth = mediaPlayer.getVideoWidth();
Log.i(TAG, "视频的宽度:" + videoWidth);
Log.i(TAG, "视频的宽度:::" + screenWidth);
videoHeight = mediaPlayer.getVideoHeight();
Log.i(TAG, "视频的高度:" + videoHeight);
Log.i(TAG, "视频的高度:::" + screenHeight);
// screenHeight = display.getHeight();
if (videoWidth > display.getWidth() || videoHeight > screenHeight) {
//视频的大小>显示器的大小
float heightRatio = (float) videoHeight / (float) screenHeight;//高度比率
float widthRatio = (float) videoWidth / (float) screenWidth;//宽度比率
if (heightRatio > widthRatio) {
videoHeight = (int) Math.ceil((float) videoHeight / heightRatio);
videoWidth = (int) Math.ceil((float) videoWidth / heightRatio);
} else {
videoHeight = (int) Math.ceil((float) videoHeight / widthRatio);
videoWidth = (int) Math.ceil((float) videoWidth / widthRatio);
}
}
/*
5月23日
Android 视频播放器
切换屏幕
*/
int orientation = msg.arg1;
if (orientation > 45 && orientation < 135) {
} else if (orientation > 135 && orientation < 225) {
} else if (orientation > 225 && orientation < 315) {
Log.i(TAG, "切换成横屏");
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
sennorFlag = false;
stretch_flag = false;
} else if ((orientation > 315 && orientation < 360) || (orientation > 0 && orientation < 45))
Log.i(TAG, "切换成竖屏");
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
sennorFlag = true;
stretch_flag = true;
}
break;
/*
5月24日
Android 视频播放器
当出现关于播放媒体的特定信息或者需要发出警告的时候,将调用onInfo
*/
public boolean onInfo(MediaPlayer mp, int what, int extra) {
Log.i(TAG, "onInfo:");
if (what == MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING) {
//当文件中的音频和视频数据不正确的交错的时候会触发
Log.i(TAG, "onInfo:MEDIA_INFO_BAD_INTERLEAVING:" + extra);
} else if (what == MediaPlayer.MEDIA_INFO_NOT_SEEKABLE) {
//当媒体不能正确的定位
Log.i(TAG, "onInfo:MEDIA_INFO_NOT_SEEKABLE:" + extra);
} else if (what == MediaPlayer.MEDIA_INFO_UNKNOWN) {
//媒体信息尚未指定或者未知
Log.i(TAG, "onInfo:MEDIA_INFO_UNKNOWN:" + extra);
} else if (what == MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING) {
//无法播放视频或者音频太复杂或者码率过高
Log.i(TAG, "onInfo:MEDIA_INFO_VIDEO_TRACK_LAGGING:" + extra);
} else if (what == MediaPlayer.MEDIA_INFO_METADATA_UPDATE) {
//当新的元数据可用时
Log.i(TAG, "onInfo:MEDIA_INFO_METADATA_UPDATE:" + extra);
}
return false;
}
@Override
public void onPrepared(MediaPlayer mp) {
try {
/*当不是全屏的时候才需要测量,才需要比较*/
if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
//因为配置文件中并未设置横竖屏
mHandler.sendEmptyMessageDelayed(MEASURE_VIDEO_SIZE, 1000);
} else if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
mHandler.sendEmptyMessageDelayed(MEASURE_VIDEO_SIZE, 1000);
} else
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
surfaceView.setLayoutParams(params);}
//Log.i("屏幕方向:::", isLandScape + "");
/*
5月25日
Android 视频播放器
重力感应监听
*/
public class OrientationSensorListener implements SensorEventListener {
private static final int _DATA_X = 0;
private static final int _DATA_Y = 1;
private static final int _DATA_Z = 2;
public static final int ORIENTATION_UNKNOWN = -1;
private MyHandler myHandler;
private boolean isSupportGravity = false;
public OrientationSensorListener(MyHandler myHandler) {
this.myHandler = myHandler;
}
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub
}
public void onSensorChanged(SensorEvent event) {
/**
* 检测手机自动旋转屏幕的功能是否打开
*/
isSupportGravity = isscreenAutoRotate()
if (!isSupportGravity) {
return;
}
if (sennorFlag != stretch_flag) //只有两个不相同才开始监听行为
{
float[] values = event.values;
int orientation = ORIENTATION_UNKNOWN;
float X = -values[_DATA_X];
float Y = -values[_DATA_Y];
float Z = -values[_DATA_Z];
float magnitude = X * X + Y * Y;
// Don't trust the angle if the magnitude is small compared to the y value
if (magnitude * 4 >= Z * Z) {
//屏幕旋转时
float OneEightyOverPi = 57.29577957855f;
float angle = (float) Math.atan2(-Y, X) * OneEightyOverPi;
orientation = 90 - (int) Math.round(angle);
// normalize to 0 - 359 range
while (orientation >= 360) {
orientation -= 360;
}
while (orientation < 0) {
orientation += 360;
}
}
if (myHandler != null) {
myHandler.obtainMessage(10001, orientation, 0).sendToTarget();
}
}
}
}
/*
5月26日
Android 视频播放器
重力感应监听
*/
public class OrientationSensorListener2 implements SensorEventListener {
//初始化重力感应器的坐标轴
private static final int sensor_X = 0;
private static final int sensor_Y = 1;
private static final int sensor_Z = 2;
private static final int ORIENTATION_UNKNOW = -1;
private boolean isSupportGravity = false;
public OrientationSensorListener2() {
}
@Override
public void onSensorChanged(SensorEvent event) {
/**
* 检测手机自动旋转屏幕的功能是否打开
*/
isSupportGravity = isscreenAutoRotate();
if (!isSupportGravity) {
return;
}
float[] values = event.values;
int orientation = ORIENTATION_UNKNOW;
float X = -values[sensor_X];
float Y = -values[sensor_Y];
float Z = -values[sensor_Z];
/*
5月27日
Android 视频播放器
重力感应监听
*/
* 重力传感器监听手机的摆放状态的算法
*/
float magnitude = X * X + Y * Y;
// Don't trust the angle if the magnitude is small compared to the y value
if (magnitude * 4 >= Z * Z) {
//屏幕旋转时
float OneEightyOverPi = 57.29577957855f;
float angle = (float) Math.atan2(-Y, X) * OneEightyOverPi;
orientation = 90 - (int) Math.round(angle);
// normalize to 0 - 359 range
while (orientation >= 360) {
orientation -= 360;
}
while (orientation < 0) {
orientation += 360;
}
}
if (orientation > 225 && orientation < 315) { //横屏
sennorFlag = false;
} else if ((orientation > 315 && orientation < 360) || (orientation > 0 && orientation < 45)) { //竖屏
sennorFlag = true;
}
if (stretch_flag == sennorFlag) { //点击变成横屏 屏幕 也转横屏 激活
Log.i(TAG, "激活");
sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI);
}
}
@Override
/*
5月28日
Android 视频播放器
重力感应监听
*/
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.i("TTTTT", "onConfigurationChanged");
if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
//如果是横屏
Log.i("WWWWWW", "横屏");
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
surfaceView.setLayoutParams(params);
if (iv_suolue.getVisibility() == View.VISIBLE && !iv_play.isSelected() && !imageView_main_show.isSelected()) {
iv_suolue.setVisibility(View.GONE);
new GetVideoBitmapAsyncTask(iv_suolue, surfaceView).execute(filepath);
}
} else if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
mHandler.sendEmptyMessage(MEASURE_VIDEO_SIZE);
Log.i("*****", "竖屏");
} else if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
mHandler.sendEmptyMessage(MEASURE_VIDEO_SIZE);
Log.i("*****", "无屏");
}
}
/*
5月29日
Android 视频播放器
重力感应监听
*/
/**
* 检测手机自动旋转的是否打开
*
* @return
*/
private boolean isscreenAutoRotate() {
int gravity = 0;
try {
gravity = Settings.System.getInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
Log.i(TAG, "检测手机是否打开屏幕旋转出错");
}
return gravity == 1;
}
}
/*
5月30日
Android 视频播放器
MainActivity
*/
package com.example.videotest1;
import com.example.service.ServiceTest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
public static SurfaceView sv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sv = (SurfaceView) findViewById(R.id.surfaceView1);// 获得SurfaceView控件
}
/*
*点击那4个按钮后触发的事件
*/
public void click(View v) {
Intent intent = new Intent(MainActivity.this, ServiceTest.class);
int op = -1;// 定义一个中间变量
switch (v.getId()) {
case R.id.play:
op = 1;
Toast.makeText(MainActivity.this, "视频正在播放...", Toast.LENGTH_SHORT)
.show();
break;
case R.id.pause:
op = 2;
Toast.makeText(MainActivity.this, "视频暂停播放...", Toast.LENGTH_SHORT)
.show();
break;
case R.id.stop:
op = 3;
Toast.makeText(MainActivity.this, "视频停止播放...", Toast.LENGTH_SHORT)
.show();
break;
case R.id.finish:
if (intent != null) {
stopService(intent);
}
finish();
break;
default:
break;
}
Bundle bundle = new Bundle();// 声明一个Bundle对象并实例化
bundle.putInt("middle", op);// 把中间变量op放置到middle这个键
intent.putExtras(bundle);// 用intent把bundle放入进去
startService(intent);// 开始服务
}
/*
5月31日
Android 视频播放器
MainActivity
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
/*
6月1日
Android 视频播放器
ServiceTest
*/
package com.example.service;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.IBinder;
public class ServiceTest extends Service {
public static MediaPlayer player;// 声明MediaPlayer对象
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
// 创建服务
@Override
public void onCreate() {
// TODO Auto-generated method stub
if (player == null) {
try {
player = new MediaPlayer();//实例化MediaPlayer对象
player.setDataSource("/sdcard/wf2.mp4");// 设置要播放的视频
player.setLooping(false);// 设置视频不循环播放
super.onCreate();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// 开始服务
/*
6月2日
Android 视频播放器
ServiceTest
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Bundle bundle = intent.getExtras();// 获得从MainActivity传来的bundle对象
int op = bundle.getInt("middle");// 获得从MainActivity.java里传递过来的op
switch (op) {
case 1:// 当op为1,即点击了播放按钮
play();// 调用play()方法
break;
case 2:// 当op为2,即点击了暂停按钮
pause();// 调用pause()方法
break;
case 3:// 当op为3,即点击了停止按钮
stop();// 调用stop()方法
break;
default:
break;
}
return super.onStartCommand(intent, flags, startId);
}
// 播放视频play()方法
private void play() {
// TODO Auto-generated method stub
if (player != null && !player.isPlaying()) {
player.setDisplay(com.example.videotest1.MainActivity.sv
.getHolder());//把视频画面显示出来
try {
player.prepare();//预加载视频
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
player.start();// 开始播放音乐
}
}
/*
6月3日
Android 视频播放器
ServiceTest
*/
private void pause() {
// TODO Auto-generated method stub
if (player != null && player.isPlaying()) {
player.pause();// 暂停视频的播放
}
}
private void stop() {
// TODO Auto-generated method stub
if (player != null) {
player.seekTo(0);//如果点击播放按钮的话会从头播放
player.stop();// 停止音乐的播放
}
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
if (player != null) {
player.stop();//停止播放视频
player.release();// 释放资源
player = null;
}
super.onDestroy();
}
}