我有Fragment
用于显示从我的网络服务器获取的大量异构内容。我正在使用AsyncTaskLoader
来获取数据,一旦我得到响应,我会执行一些逻辑来确定要显示的内容。当AsyncTaskLoader
正在运行时,我有AnimationDrawable
占用整个显示。加载完内容后,我在stop()
上致电AnimationDrawable
,将其设为View.GONE
,然后将主LinearLayout
(包含我的所有内容)设置为可见。
<?xml version="1.0" encoding="UTF-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/animation_layout"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_vertical"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="@+id/progressDialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:scaleType="center" />
</LinearLayout>
<LinearLayout
android:id="@+id/main_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:orientation="vertical" />
</LinearLayout>
</ScrollView>
这是我如何初始化加载器和动画,并显示我的内容。
@Override
public void onStart(){
super.onStart();
LoaderManager lm = getLoaderManager();
lm.initLoader(LOADER_PROFILE, getArguments(), this);
loadingAnimation.start();
animationLayout.setVisibility(LinearLayout.VISIBLE);
mainLayout.setVisibility(ViewGroup.GONE);
}
@Override
public void onLoadFinished(Loader<Response> responseLoader, Response response) {
LayoutInflater inflater = LayoutInflater.from(getActivity());
for (Module m : response.modules) {
switch (m.Type) {
case Type1:
mainLayout.addView(Type1Module.getView(inflater, m));
break;
case Type2:
mainLayout.addView(Type2Module.getView(inflater, m));
break;
case Type3:
mainLayout.addView(Type3Module.getView(inflater, m));
break;
case Type4:
mainLayout.addView(Type4Module.getView(inflater, m));
break;
case Type5:
mainLayout.addView(Type5Module.getView(inflater, m));
break;
}
loadingAnimation.stop();
animationLayout.setVisibility(LinearLayout.GONE);
mainLayout.setVisibility(ViewGroup.VISIBLE);
}
在每个模块的静态getView()
方法中,我要么根据数据夸大布局并分配不同的TextViews
和ImageViews
,要么创建几个自定义{之一的实例{1}}我已创建(饼图,图表等),需要一点点数学。在我的测试中,这需要半秒到1.5秒。
我看到的情况是,当我的View
开始时,一旦我开始创建视图并将其添加到onLoadFinished
,mainLayout
就会冻结它所在的任何帧。当我停止动画并切换布局时,它会一直冻结,直到我到达方法的末尾。
现在,我知道这种情况正在发生,因为我在UI线程上执行了所有逻辑,因此阻止了AnimationDrawable
。问题是,我正在做的大多数个人逻辑是决定视图参数(文本,颜色,字体,是否显示事物),这必须在UI线程上完成。我的问题是,有没有人遇到过在UI线程阻塞动画上做太多工作的同样问题,你想出一个解决方案吗?
注意:我最初使用自定义AnimationDrawable
将其实现为ListView
。我创建了一个TypeXModule对象的数组(都实现了BaseAdapter
),并根据需要在适配器中调用它们。内容将几乎瞬间加载(一次只有3或4个模块适合屏幕,只有3或4个模块调用它们getView()
)。但是,使用getView()
在滚动时会产生轻微卡顿的副作用,直到您无法将整个列表拖到顶部或底部。我决定尝试一个ListView
,因为1)所有视图都会立即被实例化,因此没有口吃,2)模块'ScrollView
都不同,我无法真正利用View
回收View
执行。
答案 0 :(得分:0)
final AnimationDrawable dr = new AnimationDrawable();
dr.setBounds(0, 0, 100 ,100);
Drawable frame;
Resources res = getResources();
frame = res.getDrawable(R.drawable.t6);
dr.addFrame(frame, 200);
frame = res.getDrawable(R.drawable.t7);
dr.addFrame(frame, 200);
frame = res.getDrawable(R.drawable.t8);
dr.addFrame(frame, 200);
frame = res.getDrawable(R.drawable.t9);
dr.addFrame(frame, 200);
frame = res.getDrawable(R.drawable.t10);
dr.addFrame(frame, 200);
final TextView tv = new TextView(this);
tv.setTextSize(72);
tv.setTextColor(0xffeeeeee);
tv.setGravity(Gravity.CENTER);
tv.setBackgroundDrawable(dr);
FrameLayout fl = new FrameLayout(this);
fl.addView(tv);
fl.setBackgroundColor(0xffaaaaaa);
setContentView(fl);
final int STEPS = 200;
final Handler h = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what % 50 == 0) {
Log.d(TAG, "handleMessage msg: " + msg);
}
tv.setText(Integer.toString(msg.what));
if (msg.arg1 == 0) {
take20msofCPU();
}
if (msg.what < STEPS) {
obtainMessage(msg.what + 1).sendToTarget();
}
}
};
OnClickListener l = new OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick ");
h.removeCallbacksAndMessages(null);
dr.stop();
dr.start();
int caseNumber = 2;
switch (caseNumber) {
case 0:
Log.d(TAG, "onClick simple loop: no no");
for (int i = 0; i < STEPS; i++) {
take20msofCPU();
}
break;
case 1:
Log.d(TAG, "onClick send all Messages at once: no no");
for (int i = 0; i < STEPS; i++) {
h.obtainMessage(STEPS+i).sendToTarget();
}
break;
case 2:
Log.d(TAG, "onClick simple loop in a separate Thread + Handler notification");
new Thread() {
public void run() {
for (int i = 0; i < STEPS; i++) {
take20msofCPU();
// we take 20 ms here so dont do that in the Handler
// alse msg.what is >= STEPS so it doesnt kick itself
h.obtainMessage(STEPS+i, 1, 0, null).sendToTarget();
}
};
}.start();
break;
default:
Log.d(TAG, "onClick send a Message one by one");
h.obtainMessage(0).sendToTarget();
break;
}
}
};
tv.setOnClickListener(l);
void take20msofCPU() {
// simulate hard task: you can do some looping that do something or just sleep
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
答案 1 :(得分:0)
由于我无法完全消除动画冻结,我最终走的路线略有不同。在我完成所有模块之后,不是停止动画并切换布局。 Views
,我停止动画并在加载第一个模块后切换布局,然后逐步加载每个后续模块。我使用了单独的HandlerThread
,因此我没有在主UI线程上触发所有模块。
private ArrayList<Modules> modules;
private HandlerThread mThread;
private ModuleThreadHandler mThreadHandler;
@Override
public void onStart(){
super.onStart();
LoaderManager lm = getLoaderManager();
lm.initLoader(LOADER_PROFILE, getArguments(), this);
loadingAnimation.start();
animationLayout.setVisibility(LinearLayout.VISIBLE);
mainLayout.setVisibility(ViewGroup.GONE);
}
@Override
public void onLoadFinished(Loader<Response> responseLoader, Response response) {
modules = response.modules;
mThread = new HandlerThread("mThread");
mThread.start();
Looper mThreadLooper = mThread.getLooper();
mThreadHandler = new ModuleThreadHandler(mThreadLooper);
mThreadHandler.obtainMessage(0).sendToTarget();
}
private class ModuleThreadHandler extends Handler {
public ModuleThreadHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
fragmentHandler.obtainMessage(msg.what + 1).sendToTarget();
}
}
private Handler fragmentHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what < modules.size()) {
Module m = modules.get(msg.what);
switch (m.Type) {
case Type1:
mainLayout.addView(Type1Module.getView(inflater, m));
break;
case Type2:
mainLayout.addView(Type2Module.getView(inflater, m));
break;
case Type3:
mainLayout.addView(Type3Module.getView(inflater, m));
break;
case Type4:
mainLayout.addView(Type4Module.getView(inflater, m));
break;
case Type5:
mainLayout.addView(Type5Module.getView(inflater, m));
break;
}
}
if (msg.what == 0) {
loadingAnimation.stop();
animationLayout.setVisibility(LinearLayout.GONE);
mainLayout.setVisibility(ViewGroup.VISIBLE);
}
if ((msg.what + 1) < modules.size()) {
pThreadHandler.obtainMessage(msg.what).sendToTarget();
} else {
pThread.quit();
}
}
};
这具有良好的(IMO)副作用,即#34; loading&#34;当模块连续快速加载时效果。我发现加载速度与使用ListView
一样快。这种方法的唯一缺点是,在加载模块时,滚动是不稳定的(因为在UI线程上正在进行工作)。但是,一旦加载了所有模块,滚动就非常顺利(这首先是主要目标)。