奇怪的操作,处理程序在应用程序完成后仍然调用
Strange operation, Handler still call after application finish
我创建了一个简单的应用程序,它从 Internet 加载类别列表,然后加载到 UI...在 onCreate 上,我创建了一个线程来从 Internet 获取信息,然后显示给 UI...我使用接口在 activity 与线程 class 之间进行通信。问题是当我按返回键完成应用程序时,我看到线程仍然 运行 并且它仍然触发界面...
我的activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("dj", "On Create!");
setContentView(R.layout.activity_main);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
//Load category list
DjModel.getInstance(this).doDownloadCategoryList();
//Show dialog loading
showLoadingDialog();
}
//The listener implement
@Override
public void onGetListCategoryDone(List<Category> list) {
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
mDrawerLayout);
//Dismiss dialog
closeLoadingDialog();
//Start service it wasn't
if(mDownloadIntent == null){
mDownloadIntent = new Intent(this, DjVipDownloadService.class);
bindService(mDownloadIntent, mDownloadServiceConnection, Context.BIND_AUTO_CREATE);
startService(mDownloadIntent);
}
}
我的 DjModel:
public class DjModel {
private static DjModel _model;
private final int MESSAGE_NOTIFY_GET_TRACKS_DONE = 1;
private final int MESSAGE_NOTIFY_GET_CATEGORY_DONE = 2;
public static DjModel getInstance(OnModelTaskDone callback){
if(_model == null){
_model = new DjModel(callback);
_model.mListTrack = new ArrayList<>();
}
if(callback != null){
_model.mOnModelTaskDone = callback;
}
return _model;
}
public void doDownloadCategoryList(){
Thread thread = new Thread(new GetCategoryTask());
thread.start();
}
private class GetCategoryTask implements Runnable{
@Override
public void run() {
List<Category> list = new ArrayList<Category>();
String json = Utils.getContentFromURL(Common.API_PLATFORM + Common.API_CATEGORY_LIST);
try {
JSONObject jsonObject = new JSONObject(json);
//Get result
int result = jsonObject.getInt("result");
if(result == 1){//Success
//Parse datas
JSONArray jsonArray = jsonObject.getJSONArray("data");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject data = jsonArray.getJSONObject(i);
//Pull the data
long id = data.getLong("id");
String name = data.getString("name");
//Create category
Category category = new Category();
category.setID(String.valueOf(id));
category.setName(name);
list.add(category);
}
}else{
}
} catch (JSONException e) {
e.printStackTrace();
}
//Set to global data
DjModel.getInstance(null).setListCategory(list);
mNotifyHandler.sendMessage(mNotifyHandler.obtainMessage(MESSAGE_NOTIFY_GET_CATEGORY_DONE));
}
}
private Handler mNotifyHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case MESSAGE_NOTIFY_GET_CATEGORY_DONE:
if(mOnModelTaskDone != null){
Log.e("dj","Fire event update category list");
mOnModelTaskDone.onGetListCategoryDone(DjModel.getInstance(null).getListCategory());
}
break;
}
}
};
}
一切正常运行 我第一次打开应用程序时一切正常。但是当我按下后退按钮时,我在 logcat:
上得到了这个
01-14 00:02:25.810 16917-16917/tn.han.app.djvip E/ActivityThread﹕ Activity tn.han.app.djvip.MainActivity has leaked ServiceConnection tn.han.app.djvip.MainActivity@2f0816c9 that was originally bound here
android.app.ServiceConnectionLeaked: Activity tn.han.app.djvip.MainActivity has leaked ServiceConnection tn.han.app.djvip.MainActivity@2f0816c9 that was originally bound here
at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:1072)
at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:966)
at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1768)
at android.app.ContextImpl.bindService(ContextImpl.java:1751)
at android.content.ContextWrapper.bindService(ContextWrapper.java:538)
at tn.han.app.djvip.MainActivity.onGetListCategoryDone(MainActivity.java:630)
at tn.han.app.djvip.model.DjModel.handleMessage(DjModel.java:336)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
(DjModel.java:336) 是:
mOnModelTaskDone.onGetListCategoryDone(DjModel.getInstance(null).getListCategory());
(MainActivity.java:630) 是:
bindService(mDownloadIntent, mDownloadServiceConnection, Context.BIND_AUTO_CREATE);
我不知道为什么即使我没有调用 doDownloadCategoryList() onGetListCategoryDone 仍然触发...
谢谢!
您遇到了几个问题。首先,线程不是生命周期感知的,所以当你的 activity 被关闭时,线程继续 运行。您必须停止它并取消您 activity 的 onPause
中的工作。其次,你正在启动一个 Service
,它给你一个 Binder
但是当你的 activity 被销毁时你没有调用 unbindService
,所以 logcat 显示消息关于泄露的连接。
澄清最后一点:logcat 将问题显示为 ServiceConnection
未解除绑定。这确实是这里问题的根源。 logcat 输出中的堆栈跟踪没有显示崩溃发生的位置,而是 进行 bindService()
调用的位置 以帮助您追踪当 Activity
为 paused/stopped/destroyed.
时,需要在 unbindService()
调用中提供确切的 ServiceConnection
对象
我创建了一个简单的应用程序,它从 Internet 加载类别列表,然后加载到 UI...在 onCreate 上,我创建了一个线程来从 Internet 获取信息,然后显示给 UI...我使用接口在 activity 与线程 class 之间进行通信。问题是当我按返回键完成应用程序时,我看到线程仍然 运行 并且它仍然触发界面...
我的activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("dj", "On Create!");
setContentView(R.layout.activity_main);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
//Load category list
DjModel.getInstance(this).doDownloadCategoryList();
//Show dialog loading
showLoadingDialog();
}
//The listener implement
@Override
public void onGetListCategoryDone(List<Category> list) {
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
mDrawerLayout);
//Dismiss dialog
closeLoadingDialog();
//Start service it wasn't
if(mDownloadIntent == null){
mDownloadIntent = new Intent(this, DjVipDownloadService.class);
bindService(mDownloadIntent, mDownloadServiceConnection, Context.BIND_AUTO_CREATE);
startService(mDownloadIntent);
}
}
我的 DjModel:
public class DjModel {
private static DjModel _model;
private final int MESSAGE_NOTIFY_GET_TRACKS_DONE = 1;
private final int MESSAGE_NOTIFY_GET_CATEGORY_DONE = 2;
public static DjModel getInstance(OnModelTaskDone callback){
if(_model == null){
_model = new DjModel(callback);
_model.mListTrack = new ArrayList<>();
}
if(callback != null){
_model.mOnModelTaskDone = callback;
}
return _model;
}
public void doDownloadCategoryList(){
Thread thread = new Thread(new GetCategoryTask());
thread.start();
}
private class GetCategoryTask implements Runnable{
@Override
public void run() {
List<Category> list = new ArrayList<Category>();
String json = Utils.getContentFromURL(Common.API_PLATFORM + Common.API_CATEGORY_LIST);
try {
JSONObject jsonObject = new JSONObject(json);
//Get result
int result = jsonObject.getInt("result");
if(result == 1){//Success
//Parse datas
JSONArray jsonArray = jsonObject.getJSONArray("data");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject data = jsonArray.getJSONObject(i);
//Pull the data
long id = data.getLong("id");
String name = data.getString("name");
//Create category
Category category = new Category();
category.setID(String.valueOf(id));
category.setName(name);
list.add(category);
}
}else{
}
} catch (JSONException e) {
e.printStackTrace();
}
//Set to global data
DjModel.getInstance(null).setListCategory(list);
mNotifyHandler.sendMessage(mNotifyHandler.obtainMessage(MESSAGE_NOTIFY_GET_CATEGORY_DONE));
}
}
private Handler mNotifyHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case MESSAGE_NOTIFY_GET_CATEGORY_DONE:
if(mOnModelTaskDone != null){
Log.e("dj","Fire event update category list");
mOnModelTaskDone.onGetListCategoryDone(DjModel.getInstance(null).getListCategory());
}
break;
}
}
};
}
一切正常运行 我第一次打开应用程序时一切正常。但是当我按下后退按钮时,我在 logcat:
上得到了这个01-14 00:02:25.810 16917-16917/tn.han.app.djvip E/ActivityThread﹕ Activity tn.han.app.djvip.MainActivity has leaked ServiceConnection tn.han.app.djvip.MainActivity@2f0816c9 that was originally bound here
android.app.ServiceConnectionLeaked: Activity tn.han.app.djvip.MainActivity has leaked ServiceConnection tn.han.app.djvip.MainActivity@2f0816c9 that was originally bound here
at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:1072)
at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:966)
at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1768)
at android.app.ContextImpl.bindService(ContextImpl.java:1751)
at android.content.ContextWrapper.bindService(ContextWrapper.java:538)
at tn.han.app.djvip.MainActivity.onGetListCategoryDone(MainActivity.java:630)
at tn.han.app.djvip.model.DjModel.handleMessage(DjModel.java:336)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
(DjModel.java:336) 是:
mOnModelTaskDone.onGetListCategoryDone(DjModel.getInstance(null).getListCategory());
(MainActivity.java:630) 是:
bindService(mDownloadIntent, mDownloadServiceConnection, Context.BIND_AUTO_CREATE);
我不知道为什么即使我没有调用 doDownloadCategoryList() onGetListCategoryDone 仍然触发...
谢谢!
您遇到了几个问题。首先,线程不是生命周期感知的,所以当你的 activity 被关闭时,线程继续 运行。您必须停止它并取消您 activity 的 onPause
中的工作。其次,你正在启动一个 Service
,它给你一个 Binder
但是当你的 activity 被销毁时你没有调用 unbindService
,所以 logcat 显示消息关于泄露的连接。
澄清最后一点:logcat 将问题显示为 ServiceConnection
未解除绑定。这确实是这里问题的根源。 logcat 输出中的堆栈跟踪没有显示崩溃发生的位置,而是 进行 bindService()
调用的位置 以帮助您追踪当 Activity
为 paused/stopped/destroyed.
unbindService()
调用中提供确切的 ServiceConnection
对象