Android-skin-support
Android-skin-support copied to clipboard
通过AsyncLayoutInflater inflate的View有什么办法换肤?
trafficstars
你好,请问你是怎么解决的,修改布局文件吗?有没有更好的方法
基于系统AsyncLayoutInflater实现SkinAsyncLayoutInflater,传入一个支持换肤的LayoutInflater即可。
示例:
LayoutInflater layoutInflater = LayoutInflater.from(this);
ViewGroup rootView = (ViewGroup) layoutInflater.inflate(R.layout.layout_placeholder, null);
setContentView(rootView);
new SkinAsyncLayoutInflater(layoutInflater, this).inflate(getLayoutId(), null, (view, resid, parent) -> {
rootView.addView(view);
//todo 初始化数据
});
SkinAsyncLayoutInflater.java
import android.content.Context;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.core.util.Pools;
import java.util.concurrent.ArrayBlockingQueue;
/**
* SkinAsyncLayoutInflater 使用外部LayoutInflater
* @see androidx.asynclayoutinflater.view.AsyncLayoutInflater
*/
public final class SkinAsyncLayoutInflater {
private static final String TAG = SkinAsyncLayoutInflater.class.getSimpleName();
LayoutInflater mInflater;
Handler mHandler;
InflateThread mInflateThread;
public SkinAsyncLayoutInflater(LayoutInflater layoutInflater, Context context) {
mInflater = layoutInflater;
mHandler = new Handler(mHandlerCallback);
mInflateThread = InflateThread.getInstance();
}
@UiThread
public void inflate(@LayoutRes int resid, @Nullable ViewGroup parent,
@NonNull OnInflateFinishedListener callback) {
if (callback == null) {
throw new NullPointerException("callback argument may not be null!");
}
InflateRequest request = mInflateThread.obtainRequest();
request.inflater = this;
request.resid = resid;
request.parent = parent;
request.callback = callback;
mInflateThread.enqueue(request);
}
private Callback mHandlerCallback = new Callback() {
@Override
public boolean handleMessage(Message msg) {
InflateRequest request = (InflateRequest) msg.obj;
if (request.view == null) {
request.view = mInflater.inflate(request.resid, request.parent, false);
}
request.callback.onInflateFinished(request.view, request.resid, request.parent);
mInflateThread.releaseRequest(request);
return true;
}
};
public interface OnInflateFinishedListener {
void onInflateFinished(@NonNull View view, @LayoutRes int resid, @Nullable ViewGroup parent);
}
private static class InflateRequest {
SkinAsyncLayoutInflater inflater;
ViewGroup parent;
int resid;
View view;
OnInflateFinishedListener callback;
InflateRequest() {
}
}
private static class InflateThread extends Thread {
private static final InflateThread sInstance;
static {
sInstance = new InflateThread();
sInstance.start();
}
public static InflateThread getInstance() {
return sInstance;
}
private ArrayBlockingQueue<InflateRequest> mQueue = new ArrayBlockingQueue<>(10);
private Pools.SynchronizedPool<InflateRequest> mRequestPool = new Pools.SynchronizedPool<>(10);
// Extracted to its own method to ensure locals have a constrained liveness
// scope by the GC. This is needed to avoid keeping previous request references
// alive for an indeterminate amount of time, see b/33158143 for details
public void runInner() {
InflateRequest request;
try {
request = mQueue.take();
} catch (InterruptedException ex) {
// Odd, just continue
Log.w(TAG, ex);
return;
}
try {
request.view = request.inflater.mInflater.inflate(request.resid, request.parent, false);
} catch (RuntimeException ex) {
// Probably a Looper failure, retry on the UI thread
Log.w(TAG, "Failed to inflate resource in the background! Retrying on the UI thread", ex);
}
Message.obtain(request.inflater.mHandler, 0, request).sendToTarget();
}
@Override
public void run() {
while (true) {
runInner();
}
}
public InflateRequest obtainRequest() {
InflateRequest obj = mRequestPool.acquire();
if (obj == null) {
obj = new InflateRequest();
}
return obj;
}
public void releaseRequest(InflateRequest obj) {
obj.callback = null;
obj.inflater = null;
obj.parent = null;
obj.resid = 0;
obj.view = null;
mRequestPool.release(obj);
}
public void enqueue(InflateRequest request) {
try {
mQueue.put(request);
} catch (InterruptedException e) {
throw new RuntimeException("Failed to enqueue async inflate request", e);
}
}
}
}
你好,请问你是怎么解决的,修改布局文件吗?有没有更好的方法