java.lang.String android.content.Context.getString(int)' on a null object reference

博客提到content未实例化,可在Activity的onCreate方法中进行处理,涉及Android开发中Activity的使用及内容实例化操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

content没有实例化,在Activity的onCreate中搞一下即可:



``` FATAL EXCEPTION: main Process: com.oem.qisda, PID: 9507 java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.oem.qisda/com.oem.qisda.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3690) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3923) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2444) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:205) at android.os.Looper.loop(Looper.java:294) at android.app.ActivityThread.main(ActivityThread.java:8223) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:685) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:977) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference at android.content.ContextWrapper.getPackageName(ContextWrapper.java:177) at com.oem.qisda.MainActivity.<init>(MainActivity.java:57) at java.lang.Class.newInstance(Native Method) at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95) at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:44) at android.app.Instrumentation.newActivity(Instrumentation.java:1379) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3677) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3923)  at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)  at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)  at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2444)  at android.os.Handler.dispatchMessage(Handler.java:106)  at android.os.Looper.loopOnce(Looper.java:205)  at android.os.Looper.loop(Looper.java:294)  at android.app.ActivityThread.main(ActivityThread.java:8223)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:685)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:977)```解决?
03-14
android 15中报错:// CRASH: com.android.mms (pid 32001) // Short Msg: java.lang.NullPointerException // Long Msg: java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference // Build Label: SONIM/X53001/X530:15/X53.0-01-15.0-99.01.11/jenkins:userdebug/test-keys // Build Changelist: jenkins // Build Time: 1754634422000 // java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference // at com.android.mms.ui.AttachmentViewActivity.onDataLoadFinished(AttachmentViewActivity.java:281) // at com.android.mms.ui.BaseAttachmentViewActivity$GetDataAsyncTask.onPostExecute(BaseAttachmentViewActivity.java:222) // at com.android.mms.ui.BaseAttachmentViewActivity$GetDataAsyncTask.onPostExecute(BaseAttachmentViewActivity.java:190) // at android.os.AsyncTask.finish(AsyncTask.java:771) // at android.os.AsyncTask.-$$Nest$mfinish(Unknown Source:0) // at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788) // at android.os.Handler.dispatchMessage(Handler.java:107) // at android.os.Looper.loopOnce(Looper.java:232) // at android.os.Looper.loop(Looper.java:317) // at android.app.ActivityThread.main(ActivityThread.java:8794) // at java.lang.reflect.Method.invoke(Native Method) // at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580) // at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:892) ,具体代码如下:AttachmentViewActivity.java:/* * Sonim Technologies, Inc. CONFIDENTIAL * Copyright (c) 2017 All Rights Reserved. * * The source code contained or described herein and all documents * related to the source code ("Material") is property of Sonim * Technologies, Inc. and its affiliates, may be covered by U.S. * or Foreign Patents or patents in process, and is protected by trade * secret or copyright law. No part of the Material may be used, * copied, reproduced, modified, published, uploaded, posted, * transmitted, distributed, or disclosed in any way without * prior written permission by Sonim Technologies, Inc. * * Unless required by applicable law or agreed to in writing, * the Materials are provided "AS IS," and WITHOUT WARRANTIES * OR CONDITIONS OF ANY KIND, either express or implied. No license * under any patent, copyright, trade secret or other * intellectual property right is granted to or conferred upon you * by disclosure or delivery of the Material, either expressly, by * implication, inducement, estoppel or otherwise. Any license * under such intellectual property rights must be express and * approved by Sonim Technologies, Inc. in writing. * */ package com.android.mms.ui; import android.content.Context; import android.content.Intent; import android.os.Bundle; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import android.text.Html; import android.util.DisplayMetrics; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.Menu; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.android.mms.R; import com.android.mms.model.MediaModel; import com.android.mms.model.MediaWithTextModel; import com.android.mms.ui.multipleviews.BaseViewFragment; import com.android.mms.ui.multipleviews.VideoViewFragment; import com.google.android.mms.ContentType; import java.util.ArrayList; public class AttachmentViewActivity extends BaseAttachmentViewActivity { private static final String TAG = "AttachmentViewActivity"; static final int SAVE_SLIDER_ATTACHMENT_PERMISSION_REQUEST_CODE = 2017; private static final int DEFAULT_VISIBLE_LIST_COUNT = 3; private static final int DEFAULT_RECYCLER_VIEW_HEIGHT = 0; private static final int RECYCLER_VIEW_DEVICE_PORTION_ON_DEVICE_HEIGHT = 4; private static final boolean CONTAINER_FULLVIEW_MODE_VISIBLE = true; private static final boolean CONTAINER_FULLVIEW_MODE_INVISIBLE = false; private static final String VIEW_VCARD = "VIEW_VCARD_FROM_MMS"; private static final String KEY_PACKAGE_NAME = "calling_package_name"; private static final String PACKAGE_NAME = "com.android.mms"; private static final String EXTRA_SINGLE_ITEM = "SingleItemOnly"; private LinearLayout mDotsLayout; private TextView[] mDotsTextview; private SlidesAdapter mSlidesAdapter; private RecyclerView mSlidesRecyclerView; /** * Default recycler view height will be zero. Based on Device height it will be calculate the * recyclerview height dynamically. */ private int mRecyclerViewHeight = 0; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); if (MessageUtils.checkPermissionsIfNeeded(this)) { return; } setContentView(R.layout.attachment_view_activity); new GetDataAsyncTask(this).execute(); } private void initView() { mSelectedAttachmentContainer = (LinearLayout) findViewById(R.id.frameLayout_container); mDotsLayout = (LinearLayout) findViewById(R.id.dots_layout); mSlidesRecyclerView = (RecyclerView) findViewById(R.id.slides_recycler_view); calculateRecyclerViewHeight(); resetRecyclerViewHeight(mRecyclerViewHeight); RecyclerView.LayoutManager layoutManager = new LinearLayoutManagerWrapper(getApplicationContext(), LinearLayoutManager.HORIZONTAL, false); mSlidesRecyclerView.setLayoutManager(layoutManager); mSlidesRecyclerView.setItemAnimator(new DefaultItemAnimator()); mSlidesAdapter = new SlidesAdapter(mMediaWithTextModelList, this); mSlidesRecyclerView.setAdapter(mSlidesAdapter); // << [DNL-7826] 20210422 JunYiLin >> mSlidesAdapter.setOnDataSetChangedListener(mDataSetChangedListener); // << [DNL-7080] 20210330 JunYiLin << mSlidesRecyclerView.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) { updateNavBar(getResources().getStringArray(R.array.setNavBar_highlight_attachments_view_in_slideshow)); } } }); // [DNL-7080] >> } /** * prepare display dots layout */ private void displayDotsLayout() { if (mDotsTextview == null) { if (mMediaWithTextModelList.size() % DEFAULT_VISIBLE_LIST_COUNT == 0) { mDotsTextview = new TextView[mMediaWithTextModelList.size() / DEFAULT_VISIBLE_LIST_COUNT]; } else { mDotsTextview = new TextView[ (mMediaWithTextModelList.size() / DEFAULT_VISIBLE_LIST_COUNT) + 1]; } for (int i = 0; i < mDotsTextview.length; i++) { TextView dotTextView = new TextView(this); mDotsTextview[i] = dotTextView; mDotsTextview[i].setText(Html.fromHtml(getResources(). getString(R.string.dots_text_design))); mDotsTextview[i].setTextSize(getResources().getDimension(R.dimen.dot_text_design_size)); mDotsTextview[i].setTextColor(getResources().getColor(R.color.dot_inactive)); Log.v(TAG, "mDotsTextview text: "+mDotsTextview[i].getText()); mDotsLayout.addView(mDotsTextview[i]); } changeDotsColor(0); } Log.d(TAG,"fxj 147"); // Message UABT-1662 Haifei.Liao remove the dot layout BEGIN mDotsLayout.setVisibility(View.GONE); // Message UABT-1662 Haifei.Liao remove the dot layout END } @Override public void onRequestPermissionsResult(final int requestCode, final String permissions[], final int[] grantResults) { if (requestCode == SAVE_SLIDER_ATTACHMENT_PERMISSION_REQUEST_CODE) { if (MessageUtils.hasStoragePermission()) { //TODO: Check for permission enabled or not } else { Toast.makeText(this, R.string.no_permission_save_attachment_to_storage, Toast.LENGTH_SHORT).show(); } } } /** * change dots color whenever focus going to change left to right or right to left * @param currentPage */ private void changeDotsColor(int currentPage) { if (mDotsTextview == null) { return; } int focus = currentPage / DEFAULT_VISIBLE_LIST_COUNT; if (focus > 0) { mDotsTextview[focus - 1].setTextColor(getResources().getColor(R.color.dot_inactive)); } if (focus < mDotsTextview.length - 1) { mDotsTextview[focus + 1].setTextColor(getResources().getColor(R.color.dot_inactive)); } mDotsTextview[focus].setTextColor(getResources().getColor(R.color.dot_active)); } @Override public void onBackPressed() { /** * When click on back button check for is it in full view mode or not. If it is in full view mode * adjust to normal mode without close application. If it is in normal mode close this activity */ if (mSlidesRecyclerView.getLayoutParams() != null && mSlidesRecyclerView.getLayoutParams().height == DEFAULT_RECYCLER_VIEW_HEIGHT) { if (isSingleSlideMode()) { finish(); } else { resetRecyclerViewHeight(CONTAINER_FULLVIEW_MODE_INVISIBLE); } } else { super.onBackPressed(); } } @Override public void onItemClick(int position) { /** * If seleted mediaModel is Vcard or Vcal open there respective actions * else adjust current view as full view. */ MediaModel mediaModel = mMediaWithTextModelList.get(position).getMediaModel(); if (mediaModel != null) { if (mediaModel.isVcard()) { Intent intent = new Intent(Intent.ACTION_VIEW); // we need open the saved part. intent.setDataAndType(mediaModel.getUri(), ContentType.TEXT_VCARD.toLowerCase()); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // distinguish view vcard from mms or contacts. intent.putExtra(VIEW_VCARD, true); Intent openInChooser = Intent.createChooser(intent, getString(R.string.action_header)); startActivity(openInChooser); } else if (mediaModel.isVcal()) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.putExtra(EXTRA_SINGLE_ITEM, true); // So we don't see "surrounding" images in Gallery intent.putExtra(KEY_PACKAGE_NAME, PACKAGE_NAME); String contentType; contentType = mediaModel.getContentType(); intent.setDataAndType(mediaModel.getUri(), contentType); startActivity(intent); } else { resetRecyclerViewHeight(CONTAINER_FULLVIEW_MODE_VISIBLE); } } } @Override public void onLoadContainerView(int position) { super.onLoadContainerView(position); updateCurrentPosition(position); Log.v(TAG, "Attachment no fragment loaded till now onLoadContainerView"); changeDotsColor(position); } /** * Update mediaWithTextModel on mediaModel and text available * @param mediaModel * @param message */ @Override public void onDataUpdate(final MediaModel mediaModel, final String message) { runOnUiThread(new Runnable() { @Override public void run() { if(mActualNumberOfSlides == mNumberOfSlidesLoaded) { onDataInsert(mediaModel, message); } else { MediaWithTextModel mediaWithTextModel = mMediaWithTextModelList.get(mNumberOfSlidesLoaded); mediaWithTextModel.setMediaModel(mediaModel); mediaWithTextModel.setMessageText(message); mMediaWithTextModelList.set(mNumberOfSlidesLoaded, mediaWithTextModel); mSlidesAdapter.notifyItemChanged(mNumberOfSlidesLoaded); mNumberOfSlidesLoaded = mNumberOfSlidesLoaded + 1; } } }); } /** * Method for once data loads done this method will trigger. Handle on Main Thread */ @Override public void onDataLoadFinished() { Log.v(TAG, "Attachment onDataLoadFinished media list size is " + mMediaWithTextModelList.size()); removeEmptySlideObjects(); displayDotsLayout(); } @Override public void setInitialSlideSize(int size) { super.setInitialSlideSize(size); mMediaWithTextModelList = new ArrayList<MediaWithTextModel>(size); for(int i = 0; i < size; i ++) { mMediaWithTextModelList.add(new MediaWithTextModel(null,null)); } runOnUiThread(new Runnable() { @Override public void run() { initView(); } }); } @Override public void onDataInsert(final MediaModel mediaModel, final String message) { runOnUiThread(new Runnable() { @Override public void run() { Log.v(TAG, "Attachment onDataInsert"); MediaWithTextModel mediaWithTextModel = new MediaWithTextModel(message, mediaModel); mMediaWithTextModelList.add(mediaWithTextModel); mSlidesAdapter.notifyItemInserted(mMediaWithTextModelList.size() - 1); } }); } @Override public void onDataRemove(final int position) { mSlidesAdapter.notifyItemRemoved(position); } /** * sometimes slidemodel will return empty mediamodel list */ private void removeEmptySlideObjects() { //check for number of slides reached or not. If not reached then remove dummy viewholder from recyclerview runOnUiThread(new Runnable() { @Override public void run() { if(mActualNumberOfSlides > mNumberOfSlidesLoaded) { mMediaWithTextModelList.remove(mNumberOfSlidesLoaded); mNumberOfSlidesLoaded = mNumberOfSlidesLoaded + 1; onDataRemove(mMediaWithTextModelList.size()); removeEmptySlideObjects(); } } }); } public static class LinearLayoutManagerWrapper extends LinearLayoutManager { public LinearLayoutManagerWrapper(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } @Override public boolean supportsPredictiveItemAnimations() { return false; } } /** * Calculate recycler view height using the device height * eg: if device height is 400 then recycleViewHeight = 400/4 * (Here 4 is portion of value). finally recyclerViewHeight = 100 */ private void calculateRecyclerViewHeight() { DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); int height = displayMetrics.heightPixels; mRecyclerViewHeight = (int) (height / RECYCLER_VIEW_DEVICE_PORTION_ON_DEVICE_HEIGHT ); } public void resetRecyclerViewHeight(boolean isViewEntered) { Log.d(TAG, "base resetRecyclerViewHeight isEnter = " + isViewEntered); BaseViewFragment baseFragment = (BaseViewFragment) getFragmentManager() .findFragmentById(R.id.selected_attachment_container); if (isViewEntered) { resetRecyclerViewHeight(DEFAULT_RECYCLER_VIEW_HEIGHT); mDotsLayout.setVisibility(View.GONE); if (baseFragment != null) { baseFragment.onPlayMedia(); } } else { resetRecyclerViewHeight(mRecyclerViewHeight); mDotsLayout.setVisibility(View.VISIBLE); if (baseFragment != null) { baseFragment.onStopMedia(); } } mSlidesRecyclerView.requestLayout(); } private void resetRecyclerViewHeight(int height) { mSlidesRecyclerView.getLayoutParams().height = height; mSlidesRecyclerView.requestLayout(); } /** * When click play all menu item readjust view from full view to normal */ @Override public void onPlayAllMenuItemSelect() { if (mSlidesRecyclerView.getLayoutParams().height == DEFAULT_RECYCLER_VIEW_HEIGHT) { resetRecyclerViewHeight(CONTAINER_FULLVIEW_MODE_INVISIBLE); } } @Override public void playMediaInFullView() { resetRecyclerViewHeight(CONTAINER_FULLVIEW_MODE_VISIBLE); } @Override public boolean dispatchKeyEvent(KeyEvent event) { BaseViewFragment baseFragment = (BaseViewFragment) getFragmentManager() .findFragmentById(R.id.selected_attachment_container); if(baseFragment instanceof VideoViewFragment) { VideoViewFragment videoViewFragment = (VideoViewFragment) baseFragment; videoViewFragment.onKeyEvent(); } return super.dispatchKeyEvent(event); } @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); invalidateOptionsMenu(); return true; } // [DNL-7080] 20210330 JunYiLin << @Override public boolean onKeyUp(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_MENU: saveAllAttachment(); break; case KeyEvent.KEYCODE_MULTIFUNC_CENTER: playAllSlideShow(); break; case KeyEvent.KEYCODE_MULTIFUNC_RIGHT: saveAttachment(); break; } return super.onKeyUp(keyCode, event); } @Override protected void onResume() { super.onResume(); updateNavBar(this.getResources().getStringArray(R.array.setNavBar_highlight_attachments_view_in_slideshow)); } // [DNL-7080] >> },BaseAttachmentViewActivity.java:/* * Sonim Technologies, Inc. CONFIDENTIAL * Copyright (c) 2017 All Rights Reserved. * * The source code contained or described herein and all documents * related to the source code ("Material") is property of Sonim * Technologies, Inc. and its affiliates, may be covered by U.S. * or Foreign Patents or patents in process, and is protected by trade * secret or copyright law. No part of the Material may be used, * copied, reproduced, modified, published, uploaded, posted, * transmitted, distributed, or disclosed in any way without * prior written permission by Sonim Technologies, Inc. * * Unless required by applicable law or agreed to in writing, * the Materials are provided "AS IS," and WITHOUT WARRANTIES * OR CONDITIONS OF ANY KIND, either express or implied. No license * under any patent, copyright, trade secret or other * intellectual property right is granted to or conferred upon you * by disclosure or delivery of the Material, either expressly, by * implication, inducement, estoppel or otherwise. Any license * under such intellectual property rights must be express and * approved by Sonim Technologies, Inc. in writing. * */ package com.android.mms.ui; import android.app.Activity; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.ContentValues; import android.content.Intent; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.provider.Telephony; import android.util.Log; import android.os.Environment; import android.text.TextUtils; import android.view.Menu; import android.view.MenuItem; // << [DNL-795] 20210113 JunYiLin >> import android.view.KeyEvent; import android.webkit.MimeTypeMap; import android.widget.LinearLayout; import android.widget.Toast; import com.android.mms.MmsApp; import com.android.mms.R; import com.android.mms.drm.DrmUtils; import com.android.mms.model.MediaWithTextModel; import com.android.mms.model.MediaModel; import com.android.mms.model.SlideModel; import com.android.mms.model.SlideshowModel; import com.android.mms.model.SmilHelper; import com.android.mms.transaction.MessagingNotification; import com.android.mms.ui.multipleviews.AudioViewFragment; import com.android.mms.ui.multipleviews.BaseViewFragment; import com.android.mms.ui.multipleviews.IAttachmentSelection; import com.android.mms.ui.multipleviews.ImageViewFragment; import com.android.mms.ui.multipleviews.VcardVcalViewFragment; import com.android.mms.ui.multipleviews.VideoViewFragment; import com.android.mms.util.Utils; import com.google.android.mms.ContentType; import com.google.android.mms.MmsException; import com.google.android.mms.util.SqliteWrapper; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.util.List; public abstract class BaseAttachmentViewActivity extends Activity implements IAttachmentSelection { private static final String TAG = BaseAttachmentViewActivity.class.getSimpleName(); private static final int SINGLE_SLIDE_MODEL_SIZE = 1; private static final String NO_SPACE_ERROR = "ENOSPC"; private static boolean mNoSpace = false; public static final int MENU_PLAY = 1; public static final int MENU_PAUSE = 2; public static final int MENU_RESUME = 3; public static final int MENU_PLAY_ALL = 4; public static final int MENU_STOP = 5; public static final int MENU_SAVE_ATTACHMENT = 6; public static final int MENU_SAVE_ALL_ATTACHMENTS = 7; public LinearLayout mSelectedAttachmentContainer; public List<MediaWithTextModel> mMediaWithTextModelList; private boolean mSingleSlideMode = false; private boolean mPlayAllMode = false; private boolean mEditSlideShowMode = false; private int mCurrentMediaPosition = 0; public int mActualNumberOfSlides, mNumberOfSlidesLoaded; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } private void markAsReadIfNeed() { Intent intent = getIntent(); boolean unread = intent.getBooleanExtra("unread", false); Uri uri = intent.getData(); if (unread) { ContentValues values = new ContentValues(2); values.put(Telephony.Mms.SEEN, MessageUtils.MESSAGE_SEEN); values.put(Telephony.Mms.READ, MessageUtils.MESSAGE_READ); SqliteWrapper.update(this, getContentResolver(), uri, values, null, null); MessagingNotification.blockingUpdateNewMessageIndicator( this, MessagingNotification.THREAD_NONE, false); } } @Override public void onLoadContainerView(int position) { MediaWithTextModel mediaWithTextModel = mMediaWithTextModelList.get(position); overrideContainer(mediaWithTextModel); } @Override public void onLoadContainerView(MediaWithTextModel customMediaModel) { overrideContainer(customMediaModel); } // When switching between the fragments update mCurrentMediaPosition // with selected media position public void updateCurrentPosition(int currentMediaPosition) { mCurrentMediaPosition = currentMediaPosition; } private void overrideContainer(MediaWithTextModel mediaWithTextModel) { if (!isFinishing() && !isDestroyed()) { FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); MediaModel mediaModel = mediaWithTextModel.getMediaModel(); switch (mediaModel.getTag()) { case SmilHelper.ELEMENT_TAG_TEXT: fragmentTransaction.replace(R.id.selected_attachment_container, ImageViewFragment.newInstance(mediaWithTextModel), null); break; case SmilHelper.ELEMENT_TAG_IMAGE: fragmentTransaction.replace(R.id.selected_attachment_container, ImageViewFragment.newInstance(mediaWithTextModel), null); break; case SmilHelper.ELEMENT_TAG_AUDIO: fragmentTransaction.replace(R.id.selected_attachment_container, AudioViewFragment.newInstance(mediaWithTextModel), null); break; case SmilHelper.ELEMENT_TAG_VIDEO: fragmentTransaction.replace(R.id.selected_attachment_container, VideoViewFragment.newInstance(mediaWithTextModel), null); break; case SmilHelper.ELEMENT_TAG_REF: if (mediaModel.getContentType().toLowerCase().equals(ContentType.TEXT_VCARD. toLowerCase()) || mediaModel.getContentType().toLowerCase(). equals(ContentType.TEXT_VCALENDAR.toLowerCase())) { fragmentTransaction.replace(R.id.selected_attachment_container, VcardVcalViewFragment.newInstance(mediaWithTextModel), null); } break; default: Log.v(TAG,"default attachment type case"); } fragmentTransaction.commit(); } } public boolean isSingleSlideMode() { return mSingleSlideMode; } public void setSingleSlideMode(boolean mSingleSlideMode) { this.mSingleSlideMode = mSingleSlideMode; } static class GetDataAsyncTask extends AsyncTask<Void, Void, Void> { private WeakReference<BaseAttachmentViewActivity> attachmentViewActivityWeakReference; public GetDataAsyncTask(BaseAttachmentViewActivity baseAttachmentViewActivity) { attachmentViewActivityWeakReference = new WeakReference(baseAttachmentViewActivity); } @Override protected Void doInBackground(Void... voids) { Log.v(TAG, "GetDataAsyncTask doInBackground"); BaseAttachmentViewActivity activity = attachmentViewActivityWeakReference.get(); if (activity != null) { try { Intent intent = activity.getIntent(); Uri uri = intent.getData(); SlideshowModel.createFromMessageUri(activity, uri); } catch (MmsException e) { Log.e(TAG, "Cannot present the slide show.", e); } activity.markAsReadIfNeed(); } else { Log.v(TAG, "GetDataAsyncTask Activity is null "); } return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); BaseAttachmentViewActivity activity = attachmentViewActivityWeakReference.get(); if (activity != null) { activity.onDataLoadFinished(); } } } /** * Update mediaWithTextModelList on slideModel available * @param slideModel * @param currentSlide */ @Override public void onDataUpdate(SlideModel slideModel, int currentSlide) { String message = slideModel.getText() != null ? slideModel.getText().getText() : null; if (slideModel.size() == SINGLE_SLIDE_MODEL_SIZE && slideModel.get(0).isText()) { if (mActualNumberOfSlides > mNumberOfSlidesLoaded) { onDataUpdate(slideModel.get(0), message); } else { onDataInsert(slideModel.get(0), message); } } else { for (int j = 0; j < slideModel.size(); j++) { MediaModel mediaModel = slideModel.get(j); Log.d(TAG, "Attachment prepareSlideData MediaModel contentType = " + mediaModel.getContentType()); if (mediaModel != null && !mediaModel.isText()) { Log.d(TAG, "Attachment prepareSlideData adding MediaWithTextModel "); if (mActualNumberOfSlides > mNumberOfSlidesLoaded) { onDataUpdate(mediaModel, message); } else { onDataInsert(mediaModel, message); } } } } } @Override public void setInitialSlideSize(int size) { Log.v(TAG, "Attachment setSlideShowSize size " + size); mActualNumberOfSlides = size; } public IAttachmentSelection getIAttachmentSelection() { return this; } public boolean isPlayAllMode() { return mPlayAllMode; } public void setPlayAllMode(boolean mPlayAllMode) { this.mPlayAllMode = mPlayAllMode; } @Override public void onPlayNextSlide() { } //[DNL-795] 20210220 JunYiLin << /* mark original @Override public boolean onPrepareOptionsMenu(Menu menu) { menu.clear(); BaseViewFragment baseFragment = (BaseViewFragment) getFragmentManager(). findFragmentById(R.id.selected_attachment_container); if(baseFragment != null) { baseFragment.onMenuUpdate(menu); } if(mMediaWithTextModelList != null && mMediaWithTextModelList.size() > 1) { menu.add(0, MENU_PLAY_ALL, 0,R.string.play_all); } menu.add(0, MENU_SAVE_ATTACHMENT, 0,R.string.save_attachment); if(mMediaWithTextModelList != null && mMediaWithTextModelList.size() > 1) { menu.add(0, MENU_SAVE_ALL_ATTACHMENTS, 0, R.string.save_all_attachments); } return true; } */ // [DNL-795] >> @Override public boolean onOptionsItemSelected(MenuItem item) { BaseViewFragment baseFragment = null; switch (item.getItemId()) { case MENU_PLAY_ALL: onPlayAllMenuItemSelect(); Intent intent = new Intent(this, AttachmentPlayAllActivity.class); intent.setData(getIntent().getData()); startActivity(intent); break; case MENU_SAVE_ATTACHMENT: saveAttachment(); break; case MENU_SAVE_ALL_ATTACHMENTS: saveAllAttachment(); break; case MENU_PLAY: playMediaInFullView(); baseFragment = (BaseViewFragment) getFragmentManager() .findFragmentById(R.id.selected_attachment_container); baseFragment.onPlayMedia(); break; case MENU_PAUSE: baseFragment = (BaseViewFragment) getFragmentManager() .findFragmentById(R.id.selected_attachment_container); baseFragment.onPauseMedia(); break; case MENU_RESUME: baseFragment = (BaseViewFragment) getFragmentManager() .findFragmentById(R.id.selected_attachment_container); baseFragment.onResumeMedia(); break; default: return super.onOptionsItemSelected(item); } return true; } // [DNL-7080] 20210330 JunYiLin << public void saveAllAttachment() { /* mark original private void saveAllAttachment(){ */ // [DNL-7080] int resId; boolean isCopied = copyMedia(); if(isCopied){ resId = R.string.save_all_attachment_success; }else{ resId = mNoSpace ? R.string.space_low_message : R.string.save_attachment_fail; } Toast.makeText(BaseAttachmentViewActivity.this, resId, Toast.LENGTH_SHORT).show(); } // [DNL-795] 20210113 JunYiLin << public void saveAttachment() { /* mark original private void saveAttachment(){ */ // [DNL-795] >> int resId; boolean isCopied = copyPart(mMediaWithTextModelList.get(mCurrentMediaPosition)); if(isCopied){ resId = R.string.save_attachment_success; }else{ resId = mNoSpace ? R.string.space_low_message : R.string.save_attachment_fail; } Toast.makeText(BaseAttachmentViewActivity.this, resId, Toast.LENGTH_SHORT).show(); } /** * Copies media from an Mms to the "download" directory on the SD card. If any of the parts * are audio types, drm'd or not, they're copied to the "Ringtones" directory. */ private boolean copyMedia() { boolean result = true; if (mMediaWithTextModelList == null) { return false; } for(int i = 0; i < mMediaWithTextModelList.size(); i++) { // all parts have to be successful for a valid result. result &= copyPart(mMediaWithTextModelList.get(i)); } return result; } private boolean copyPart(MediaWithTextModel customMediaModel) { // [DNL-8241] 20210423 JunYiLin << if (MessageUtils.checkIsPhoneMemoryFull(BaseAttachmentViewActivity.this)) { mNoSpace = true; return false; } // [DNL-8241] >> mNoSpace = false; MediaModel mediaModel = customMediaModel.getMediaModel(); Uri uri = mediaModel.getUri(); String type = new String(mediaModel.getContentType()); boolean isDrm = DrmUtils.isDrmType(type); if (isDrm) { type = MmsApp.getApplication().getDrmManagerClient() .getOriginalMimeType(uri); } if (!ContentType.isImageType(type) && !ContentType.isVideoType(type) && !ContentType.isAudioType(type) && !(ContentType.TEXT_VCARD.toLowerCase().equals(type.toLowerCase())) && !(ContentType.TEXT_VCALENDAR.toLowerCase().equals(type.toLowerCase())) && !(ContentType.AUDIO_OGG.toLowerCase().equals(type.toLowerCase()))) { return true; // we only save pictures, videos, and sounds. Skip the text parts, // the app (smil) parts, and other type that we can't handle. // Return true to pretend that we successfully saved the part so // the whole save process will be counted a success. } InputStream input = null; FileOutputStream fout = null; try { input = getContentResolver().openInputStream(uri); if (input instanceof FileInputStream) { FileInputStream fin = (FileInputStream) input; String fileName = mediaModel.getSrc(); File originalFile = new File(fileName); fileName = originalFile.getName(); // Strip the full path of where the "part" is // stored down to just the leaf filename. // For every media the default saving directory should be 'Download'. String dir = Utils.getStoragePath(this) + "/" + Environment.DIRECTORY_DOWNLOADS + "/"; String extension; int index; if ((index = fileName.lastIndexOf('.')) == -1) { extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(type); } else { extension = fileName.substring(index + 1, fileName.length()); fileName = fileName.substring(0, index); } if (isDrm) { extension += DrmUtils.getConvertExtension(type); } // Remove leading periods. The gallery ignores files starting with a period. if (!TextUtils.isEmpty(fileName)) { fileName = fileName.trim(); fileName = fileName.replaceAll("^\\.", ""); } File file = getUniqueDestination(dir + fileName, extension); // make sure the path is valid and directories created for this file. File parentFile = file.getParentFile(); if (!parentFile.exists() && !parentFile.mkdirs()) { Log.e(TAG, "[MMS] copyPart: mkdirs for " + parentFile.getPath() + " failed!"); return false; } fout = new FileOutputStream(file); byte[] buffer = new byte[8000]; int size = 0; while ((size=fin.read(buffer)) != -1) { fout.write(buffer, 0, size); } // Notify other applications listening to scanner events // that a media file has been added to the sd card sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file))); } } catch (IOException e) { // Ignore Log.e(TAG, "IOException caught while opening or reading stream", e); if(e.getMessage().contains(NO_SPACE_ERROR)){ mNoSpace = true; } return false; } finally { if (null != input) { try { input.close(); } catch (IOException e) { // Ignore Log.e(TAG, "IOException caught while closing stream", e); return false; } } if (null != fout) { try { fout.close(); } catch (IOException e) { // Ignore Log.e(TAG, "IOException caught while closing stream", e); return false; } } } return true; } private File getUniqueDestination(String base, String extension) { File file = new File(base + "." + extension); for (int i = 2; file.exists(); i++) { file = new File(base + "_" + i + "." + extension); } return file; } @Override public void onPlayAllMenuItemSelect() { } @Override public void playMediaInFullView() {} public boolean isEditSlideShowMode() { return mEditSlideShowMode; } public void setEditSlideShowMode(boolean editSlideShowMode) { this.mEditSlideShowMode = editSlideShowMode; } // << [DNL-7080] 20210330 JunYiLin << public void updateNavBar(String[] str) { if (str.length > 0) { MessageUtils.setNavigationBarName(this, str); } } public void playAllSlideShow() { Intent intent = new Intent(this, AttachmentPlayAllActivity.class); intent.setData(getIntent().getData()); startActivity(intent); } // [DNL-7080] >> // [DNL-7826] 20210422 JunYiLin << public final SlidesAdapter.OnDataSetChangedListener mDataSetChangedListener = new SlidesAdapter.OnDataSetChangedListener() { @Override public void onHighLightItem(int position) { playAudioMedia(position); } }; public void playAudioMedia(int position) { MediaModel mediaModel = mMediaWithTextModelList.get(position).getMediaModel(); if (mediaModel != null && mediaModel.isAudio()) { BaseViewFragment baseFragment = (BaseViewFragment) getFragmentManager().findFragmentById(R.id.selected_attachment_container); if (baseFragment != null) { baseFragment.onPlayMedia(); } } } // [DNL-7826] >> }以上报错,怎么在上述代码上具体修改
最新发布
08-12
package com.example.kucun2.entity.data; import android.content.Context; import android.util.Log; import com.example.kucun2.entity.*; import com.example.kucun2.function.MyAppFnction; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.*; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class Data { // 数据集合声明(保持原有属性名不变) public static SynchronizedList<Bancai> bancais = new SynchronizedList<>(Bancai.class); public static SynchronizedList<Caizhi> caizhis = new SynchronizedList<>(Caizhi.class); public static SynchronizedList<Mupi> mupis = new SynchronizedList<>(Mupi.class); public static SynchronizedList<Chanpin> chanpins = new SynchronizedList<>(Chanpin.class); public static SynchronizedList<Chanpin_Zujian> chanpinZujians = new SynchronizedList<>(Chanpin_Zujian.class); public static SynchronizedList<Dingdan> dingdans = new SynchronizedList<>(Dingdan.class); public static SynchronizedList<Dingdan_Chanpin> dingdanChanpins = new SynchronizedList<>(Dingdan_Chanpin.class); public static SynchronizedList<Dingdan_Bancai> dingdanBancais = new SynchronizedList<>(Dingdan_Bancai.class); public static SynchronizedList<Kucun> kucuns = new SynchronizedList<>(Kucun.class); public static SynchronizedList<Zujian> zujians = new SynchronizedList<>(Zujian.class); public static SynchronizedList<User> users = new SynchronizedList<>(User.class); public static SynchronizedList<Jinhuo> jinhuoList = new SynchronizedList<>(Jinhuo.class); private static final Gson gson = new Gson(); private static final OkHttpClient client = new OkHttpClient(); private static final String TAG = "DataLoader"; // 加载所有数据的方法 public static void loadAllData(Context context, LoadDataCallback callback) { // 开始批量模式 for (SynchronizedList<?> list : getAllSyncLists()) { list.beginBatch(); } String url = MyAppFnction.getStringResource("String", "url") + MyAppFnction.getStringResource("String", "url_all"); Request request = new Request.Builder() .url(url) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG, "Failed to load data", e); if (callback != null) callback.onFailure(); } @Override public void onResponse(Call call, Response response) throws IOException { parseAndAssignData(response.body().string(), context,callback); // 结束批量模式(会触发一次全量同步) for (SynchronizedList<?> list : getAllSyncLists()) { list.endBatch(); } if (callback != null) callback.onSuccess(); } }); } // 获取所有同步列表的方法 private static List<SynchronizedList<?>> getAllSyncLists() { return Arrays.asList(bancais, caizhis, mupis, chanpins, chanpinZujians, dingdans, dingdanChanpins, dingdanBancais, kucuns, zujians, users, jinhuoList); } // 解析并赋值数据 private static void parseAndAssignData(String jsonData, Context context, LoadDataCallback callback) { // 创建包含所有数据类型的TypeToken Type informationType = new TypeToken<Information<AllDataResponse>>(){}.getType(); Information<AllDataResponse> information = gson.fromJson(jsonData, informationType); if (information == null || information.getData() == null || information.getStatus() != 200) { Log.e(TAG, "Invalid response data"); if (callback != null) callback.onFailure(); return; } AllDataResponse allData = information.getData(); // 赋值到对应的列表(使用安全方法保持已有引用) updateList(bancais, allData.bancais); updateList(caizhis, allData.caizhis); updateList(mupis, allData.mupis); updateList(chanpins, allData.chanpins); updateList(chanpinZujians, allData.chanpin_zujians); updateList(dingdans, allData.dingdans); updateList(dingdanChanpins, allData.dingdan_chanpins); updateList(dingdanBancais, allData.dingdan_bancais); updateList(kucuns, allData.kucuns); updateList(zujians, allData.zujians); updateList(users, allData.users); updateList(jinhuoList, allData.jinhuos); resolveReferences(); if (callback != null) callback.onSuccess(); } // 更新列表内容但保持对象引用不变 private static <T> void updateList(List<T> existingList, List<T> newList) { if (newList == null) return; existingList.clear(); for (T item : newList) { existingList.add(item); // 会被包装成代理对象 } } // 解析对象间的引用关系(使用ID关联) // 改进的引用解析方法 private static void resolveReferences() { // 创建全局对象映射 Map<Integer, EntityClassGrassrootsid> globalMap = new HashMap<>(); // 填充全局映射表 addToGlobalMap(globalMap, bancais); addToGlobalMap(globalMap, caizhis); addToGlobalMap(globalMap, mupis); addToGlobalMap(globalMap, chanpins); addToGlobalMap(globalMap, zujians); addToGlobalMap(globalMap, dingdans); addToGlobalMap(globalMap, kucuns); addToGlobalMap(globalMap, users); // 解析所有实体的引用 resolveListReferences(bancais, globalMap); resolveListReferences(kucuns, globalMap); resolveListReferences(dingdanChanpins, globalMap); resolveListReferences(chanpinZujians, globalMap); resolveListReferences(dingdanBancais, globalMap); resolveListReferences(jinhuoList, globalMap); } // 添加对象到全局映射表 private static void addToGlobalMap(Map<Integer, EntityClassGrassrootsid> map, SynchronizedList<?> list) { for (Object item : list) { Object original = getOriginalFromList(list, item); if (original instanceof EntityClassGrassrootsid) { EntityClassGrassrootsid entity = (EntityClassGrassrootsid) original; map.put(entity.getId(), entity); } } } // 解析列表中所有实体的引用 private static void resolveListReferences(SynchronizedList<?> list, Map<Integer, EntityClassGrassrootsid> globalMap) { for (Object item : list) { Object original = getOriginalFromList(list, item); resolveEntityReferences(original, globalMap); } } // 安全获取原始对象(无需类型转换) @SuppressWarnings("unchecked") private static <T> T getOriginalFromList(SynchronizedList<?> list, Object item) { try { // 使用反射调用getOriginal方法 Method getOriginal = list.getClass().getMethod("getOriginal", Object.class); return (T) getOriginal.invoke(list, item); } catch (Exception e) { Log.e("Data", "Failed to get original object", e); return (T) item; } } //解析集合中的引用 private static void resolveCollectionReferences(Collection<?> collection, Map<Integer, EntityClassGrassrootsid> globalMap) { for (Object item : collection) { if (item instanceof EntityClassGrassrootsid) { EntityClassGrassrootsid ref = (EntityClassGrassrootsid) item; EntityClassGrassrootsid resolved = globalMap.get(ref.getId()); if (resolved != null && ref.getClass().isInstance(resolved)) { // 注意:直接替换集合元素需要特殊处理 // 实际项目应考虑使用CopyOnWrite集合或创建新集合 if (collection instanceof List) { int index = ((List<?>) collection).indexOf(ref); if (index != -1) { try { ((List<Object>) collection).set(index, resolved); } catch (Exception e) { Log.e("Data", "Failed to update collection", e); } } } } } } } // 解析单个实体的引用 private static void resolveEntityReferences(Object entity, Map<Integer, EntityClassGrassrootsid> globalMap) { if (entity == null) return; Class<?> clazz = entity.getClass(); for (Field field : clazz.getDeclaredFields()) { try { field.setAccessible(true); // 处理基本类型字段 if (EntityClassGrassrootsid.class.isAssignableFrom(field.getType())) { EntityClassGrassrootsid ref = (EntityClassGrassrootsid) field.get(entity); if (ref != null && ref.getId() != null) { EntityClassGrassrootsid resolved = globalMap.get(ref.getId()); if (resolved != null && field.getType().isInstance(resolved)) { field.set(entity, resolved); } } } // 处理集合类型字段 else if (Collection.class.isAssignableFrom(field.getType())) { Collection<?> collection = (Collection<?>) field.get(entity); if (collection != null) { resolveCollectionReferences(collection, globalMap); } } } catch (Exception e) { Log.e("Data", "Error resolving field: " + field.getName(), e); } } } // 创建ID到对象的映射 private static <T extends EntityClassGrassrootsid> Map<Integer, T> createIdMap(List<T> list) { Map<Integer, T> map = new HashMap<>(); for (T item : list) { map.put(item.getId(), item); } return map; } // 回调接口 public interface LoadDataCallback { void onSuccess(); void onFailure(); } private static void resolveFields(Object entity, Map<Integer, EntityClassGrassrootsid> globalMap) { for (Field field : entity.getClass().getDeclaredFields()) { if (EntityClassGrassrootsid.class.isAssignableFrom(field.getType())) { try { field.setAccessible(true); EntityClassGrassrootsid ref = (EntityClassGrassrootsid) field.get(entity); if (ref != null) { EntityClassGrassrootsid resolved = globalMap.get(ref.getId()); if (resolved != null && field.getType().isAssignableFrom(resolved.getClass())) { field.set(entity, resolved); } } } catch (Exception e) { Log.e("Data", "Error resolving reference", e); } } } } // 内部类用于解析JSON响应 public static class AllDataResponse { public List<Bancai> bancais; public List<Caizhi> caizhis; public List<Mupi> mupis; public List<Chanpin> chanpins; public List<Chanpin_Zujian> chanpin_zujians; public List<Dingdan> dingdans; public List<Dingdan_Chanpin> dingdan_chanpins; public List<Dingdan_Bancai> dingdan_bancais; public List<Kucun> kucuns; public List<Zujian> zujians; public List<User> users; public List<Jinhuo> jinhuos; } }package com.example.kucun2.entity.data; import android.util.Log; import androidx.annotation.NonNull; import com.google.gson.Gson; import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; import okhttp3.Call; import okhttp3.Callback; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; /** * 支持数据变更自动同步的泛型集合类 * @param <T> 继承自 SynchronizableEntity 的实体类型 */ public class SynchronizedList<T extends SynchronizableEntity> implements List<T> { private final List<T> list = new ArrayList<>(); private final OkHttpClient client = new OkHttpClient(); private static final Gson gson = new Gson(); private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); private final Class<T> entityClass; // 类型标记 // 添加批量操作模式标志 private boolean batchMode = false; // 属性变更监听器 private final List<PropertyChangeListener<T>> listeners = new ArrayList<>(); public SynchronizedList(Class<T> entityClass) { Type superClass = getClass().getGenericSuperclass(); ParameterizedType type = (ParameterizedType) superClass; Type[] typeArgs = type.getActualTypeArguments(); this.entityClass = (Class<T>) typeArgs[0]; } // 安全的类型转换方法 private T safeCast(Object o) { if (o != null && entityClass.isInstance(o)) { return entityClass.cast(o); } return null; } public interface PropertyChangeListener<T> { void onPropertyChange(T entity, String propertyName, Object oldValue, Object newValue); } public void addPropertyChangeListener(PropertyChangeListener<T> listener) { listeners.add(listener); } public void removePropertyChangeListener(PropertyChangeListener<T> listener) { listeners.remove(listener); } // 添加方法来获取原始对象 @SuppressWarnings("unchecked") public T getOriginal(T proxy) { if (proxy == null) return null; // 检查是否为代理对象 if (java.lang.reflect.Proxy.isProxyClass(proxy.getClass())) { try { java.lang.reflect.InvocationHandler handler = java.lang.reflect.Proxy.getInvocationHandler(proxy); if (handler instanceof IProxyHandler) { Object original = ((IProxyHandler) handler).getOriginal(); // 安全类型检查 if (entityClass.isInstance(original)) { return (T) original; } } } catch (Exception e) { Log.e("SynchronizedList", "Failed to get proxy handler", e); } } return proxy; } /** * 同步实体到后端 * * @param entity 要同步的实体 */ private void syncEntity(T entity) { if (batchMode) return; String operation = "add"; T originalEntity = getOriginal(entity); String endpoint = originalEntity.getEndpoint(operation); String json = gson.toJson(originalEntity); RequestBody body = RequestBody.create(json, JSON); Request request = new Request.Builder() .url(endpoint) .method(getHttpMethod(operation), body) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { Log.e("SynchronizedList", "同步失败: " + entity.getClass().getSimpleName(), e); } @Override public void onResponse(@NonNull Call call, @NonNull Response response) { if (!response.isSuccessful()) { Log.e("SynchronizedList", "同步失败: " + response.code() + " - " + response.message()); } response.close(); } }); } // 添加用于批量操作的方法 public void beginBatch() { this.batchMode = true; } public void endBatch() { this.batchMode = false; // 批量结束后触发一次全量同步 syncAllEntities(); } private void syncAllEntities() { for (T entity : list) { syncEntity(entity); } } private String getHttpMethod(String operation) { switch (operation) { case "add": return "POST"; case "update": return "PUT"; case "delete": return "DELETE"; default: return "POST"; } } // 获取类实现的所有接口(包括父类接口) private Class<?>[] getInterfaces(Class<?> clazz) { Set<Class<?>> interfaces = new HashSet<>(); while (clazz != null) { interfaces.addAll(Arrays.asList(clazz.getInterfaces())); clazz = clazz.getSuperclass(); } return interfaces.toArray(new Class<?>[0]); } /** * 创建代理对象,用于监听属性变更 */ // 优化 createProxy 方法 private T createProxy(T original) { if (original == null) return null; if (!entityClass.isInstance(original)) { throw new IllegalArgumentException("Invalid entity type"); } // 为原始对象创建代理 return (T) java.lang.reflect.Proxy.newProxyInstance( original.getClass().getClassLoader(), getInterfaces(original.getClass()), new EntityProxyHandler(original) ); // if (!entityClass.isInstance(original)) { // throw new IllegalArgumentException("Invalid entity type"); // } // // 这里使用动态代理模式监听setter方法调用 // return (T) java.lang.reflect.Proxy.newProxyInstance( // original.getClass().getClassLoader(), // original.getClass().getInterfaces(), // (proxy, method, args) -> { // // 只拦截setter方法 // if (method.getName().startsWith("set") && args.length == 1) { // String propertyName = method.getName().substring(3); // propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1); // // // 获取旧值 // Object oldValue = original.getClass() // .getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1)) // .invoke(original); // // // 调用原始方法 // Object result = method.invoke(original, args); // // // 触发监听器 // for (PropertyChangeListener<T> listener : listeners) { // listener.onPropertyChange(original, propertyName, oldValue, args[0]); // } // // // 自动同步到后端 // syncEntity(original); // return result; // } // return method.invoke(original, args); // } // ); } // 以下是List接口的实现 @Override public int size() { return list.size(); } @Override public boolean isEmpty() { return list.isEmpty(); } @Override public boolean contains(Object o) { return list.contains(o); } @NonNull @Override public Iterator<T> iterator() { return list.iterator(); } @NonNull @Override public Object[] toArray() { return list.toArray(); } @NonNull @Override public <T1> T1[] toArray(@NonNull T1[] a) { return list.toArray(a); } @Override public boolean add(T t) { T proxy = createProxy(t); boolean result = list.add(proxy); if (!batchMode) { syncEntity(proxy); } return result; // 添加时创建代理 } @Override public boolean remove(Object o) { T entity = safeCast(o); if (entity != null) { syncEntity((T) entity); // 删除前同步 } return list.remove(o); } @Override public boolean containsAll(@NonNull Collection<?> c) { return list.containsAll(c); } @Override public boolean addAll(@NonNull Collection<? extends T> c) { boolean modified = false; for (T t : c) { modified |= add(t); } return modified; } @Override public boolean addAll(int index, @NonNull Collection<? extends T> c) { for (T t : c) { add(index++, t); } return true; } @Override public boolean removeAll(@NonNull Collection<?> c) { for (Object o : c) { T entity = safeCast(o); if (entity != null) { syncEntity(entity); } } return list.removeAll(c); } @Override public boolean retainAll(@NonNull Collection<?> c) { List<T> toRemove = new ArrayList<>(); for (T t : list) { if (!c.contains(t)) { toRemove.add(t); } } // 使用安全转换 for (T entity : toRemove) { syncEntity(entity); } return list.retainAll(c); } @Override public void clear() { for (T t : list) { syncEntity(t); // 清空前同步 } list.clear(); } @Override public T get(int index) { return list.get(index); } @Override public T set(int index, T element) { T old = list.set(index, createProxy(element)); if (old != null) { syncEntity(old); // 替换旧元素前同步 } return old; } @Override public void add(int index, T element) { list.add(index, createProxy(element)); } @Override public T remove(int index) { T removed = list.remove(index); if (removed != null) { syncEntity(removed); // 删除前同步 } return removed; } @Override public int indexOf(Object o) { return list.indexOf(o); } @Override public int lastIndexOf(Object o) { return list.lastIndexOf(o); } @NonNull @Override public ListIterator<T> listIterator() { return list.listIterator(); } @NonNull @Override public ListIterator<T> listIterator(int index) { return list.listIterator(index); } @NonNull @Override public List<T> subList(int fromIndex, int toIndex) { return list.subList(fromIndex, toIndex); } // 触发属性变更通知 // 添加类型安全的属性监听 private void firePropertyChange(T entity, String propertyName, Object oldValue, Object newValue) { if (oldValue != null && newValue != null && oldValue.equals(newValue)) { return; // 值未变化时不触发监听 } for (PropertyChangeListener<T> listener : listeners) { try { listener.onPropertyChange(entity, propertyName, oldValue, newValue); } catch (Exception e) { Log.e("SynchronizedList", "Listener error", e); } } } // 修改代理处理器以支持获取原始对象 /* 完整的 EntityProxyHandler 实现 */ private class EntityProxyHandler implements IProxyHandler, java.lang.reflect.InvocationHandler { private final T original; private final Map<String, Object> propertyValues = new HashMap<>(); public EntityProxyHandler(T original) { this.original = original; // 初始化属性缓存 for (Method method : original.getClass().getMethods()) { if (method.getName().startsWith("get") && method.getParameterCount() == 0) { try { String propName = method.getName().substring(3); propName = Character.toLowerCase(propName.charAt(0)) + propName.substring(1); propertyValues.put(propName, method.invoke(original)); } catch (Exception e) { Log.e("ProxyHandler", "Failed to cache property", e); } } } } @Override public T getOriginal() { return original; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); // 处理 setter 方法 if (methodName.startsWith("set") && args != null && args.length == 1) { String propertyName = methodName.substring(3); propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1); Object oldValue = propertyValues.get(propertyName); Object newValue = args[0]; // 调用原始方法 Object result = method.invoke(original, args); propertyValues.put(propertyName, newValue); // 触发监听 firePropertyChange(original, propertyName, oldValue, newValue); // 非批量模式下自动同步 if (!batchMode) { syncEntity(original); } return result; } // 特殊处理 getOriginal 方法 if ("getOriginal".equals(methodName)) { return original; } // 处理 getter 方法(使用缓存) if (methodName.startsWith("get") && method.getParameterCount() == 0) { String propertyName = methodName.substring(3); propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1); return propertyValues.getOrDefault(propertyName, method.invoke(original)); } return method.invoke(original, args); } private Object getPropertyValue(String propertyName) { String getterName = "get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); try { Method getter = original.getClass().getMethod(getterName); return getter.invoke(original); } catch (Exception e) { Log.e("ProxyHandler", "Failed to get property value: " + propertyName, e); return null; } } } // 在 SynchronizedList 类中添加 private interface IProxyHandler { Object getOriginal(); } }app/all返回json数据:{ “status”: “200”, “text”: “success”, “data”: { “bancais”: [ { “houdu”: 15, “mupi1”: { “id”: 1 }, “mupi2”: { “id”: 1 }, “caizhi”: { “id”: 1 }, “kucun”: { “id”: 1 }, “id”: 1 }, { “houdu”: 15, “mupi1”: { “id”: 2 }, “mupi2”: { “id”: 2 }, “caizhi”: { “id”: 1 }, “kucun”: { “id”: 2 }, “id”: 2 } ], “dingdans”: [ { “dingdanChanpinZujian”: [ ], "number": "直接入库", "id": 1, "dingdanChanpin": [ {"id":1} ] } ], "mupis": [ { "name": "千和板", "id": 1, "you": null }, { "name": "桃花芯", "id": 2, "you": null }, { "name": "杉木", "id": 3, "you": null } ], "chanpins": [ { "chanpinZujian": [ { "id": 1 } ], "bianhao": "直接入库", "id": 1, "dingdanChanpin": [ {"id":1} ] } ], "kucuns": [ { "bancai": { "Id": 1 }, "shuliang": 12, "id": 1 }, { "bancai": { "Id": 2 }, "shuliang": 32, "id": 2 } ], "chanpin_zujians": [ { "chanpin": { "Id": 1 }, "bancai": { "id": 1 }, "id": 1, "zujian": { "Id": 1 }, "one_howmany": 15 } ], "zujians": [ { "chanpinZujian": [ { "id": 1 } ], "name": "前板", "id": 1 } ], "caizhis": [ { "name": "千和板", "bancai": [ { "id": 1 }, { "id": 2 } ], "id": 1 }, { "name": "杉木", "bancai": [ ], "id": 3 }, { "name": "桃花芯", "bancai": [ ], "id": 2 } ], "users": [ { "role": 0, "name": "超管", "id": 1, "andy": "123456" } ] } } <string name=“url”>https://tian.sef/Kucun2</string> <string name=“url_all”>/app/all</string> <string name=“url_bancis”>/app/bancai/all</string> <string name=“url_caizhis”>/app/caizhi/all</string> <string name=“url_mupis”>/app/mupi/all</string> <string name=“url_dingdans”>/app/dingdan/all</string> <string name=“url_chanpins”>/app/chanpin/all</string> <string name=“url_zujians”>/app/zujian/all</string> <string name="url_chanpin_zujians">/app/chanpin_zujian/all</string> <string name="url_dingdan_zujians">/app/dingdan_zujian/all</string> <string name="url_dingdan_chanpins">/app/dingdan_chanpin/all</string> <string name="url_jinhuos">/app/jinhuo/all</string> <string name="url_add_bancai">/app/bancai/add</string> <string name="url_add_dingdan">/app/dingdan/add</string> <string name="url_add_chanpin">/app/chanpin/add</string> <string name="url_add_zujian">/app/zujian/add</string> <string name="url_add_caizhi">/app/caizhi/add</string> <string name="url_add_mupi">/app/mupi/add</string> <string name="url_add_dingdan_chanpin">/app/dingdan_chanpi/add</string> <string name="url_add_dingdan_zujian">/app/dingdan_zujian/add</string> <string name="url_add_chanpin_zujian">/app/chanpin_zujian/add</string> <string name="url_add_jinhuo">/app/jinhuo/add</string> <string name="url_login">/user/login</string> 开始是填充数据
06-10
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值